kftpgrabber-0.8.99~svn1214766/0000755000175000017500000000000011276037142015403 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/COPYING.DOC0000644000175000017500000004766311276037142017062 0ustar michaelmichael GNU Free Documentation License Version 1.2, November 2002 Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. 51 Franklin St, 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. 0. PREAMBLE The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference. 1. APPLICABILITY AND DEFINITIONS This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them. The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text. A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License. 2. VERBATIM COPYING You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3. You may also lend copies, under the same conditions stated above, and you may publicly display copies. 3. COPYING IN QUANTITY If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects. If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages. If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public. It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document. 4. MODIFICATIONS You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version: A. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission. B. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement. C. State on the Title page the name of the publisher of the Modified Version, as the publisher. D. Preserve all the copyright notices of the Document. E. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices. F. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below. G. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence. J. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. L. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties--for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one. The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version. 5. COMBINING DOCUMENTS You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers. The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work. In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements". 6. COLLECTIONS OF DOCUMENTS You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects. You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document. 7. AGGREGATION WITH INDEPENDENT WORKS A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate. 8. TRANSLATION Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail. If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. 9. TERMINATION You may not copy, modify, sublicense, or distribute the Document except as expressly provided for under this License. Any other attempt to copy, modify, sublicense or distribute the Document 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. 10. FUTURE REVISIONS OF THIS LICENSE The Free Software Foundation may publish new, revised versions of the GNU Free Documentation 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. See http://www.gnu.org/copyleft/. Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. ADDENDUM: How to use this License for your documents To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page: Copyright (c) YEAR YOUR NAME. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation. If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software. kftpgrabber-0.8.99~svn1214766/src/0000755000175000017500000000000011276037142016172 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/kftpgrabber-bi-wizard.png0000644000175000017500000016457011276037142023074 0ustar michaelmichaelPNG  IHDR w pHYs  tIME,'nRtEXtComment̖IDATx} ytOϹVB $yB%n';$>;1@|aǿ!_l1$!!Nc@B t]9g}_U}3'wWsŷ#9淂H12*"tr*D T1m/>f`cs)Hnn T ?_j\%փRagg陕/V d&MnKIAJ&fz-+yx:tr]382DB Nx$B9 <-Rz!GI6Nut-!KILNmyn"^K3" inb127$\ ):- (7Վ@pw\>b YD,#ț']{Kѿ\ ^Y DiV?uJHdkDD>IS9~dXm2:&qG)zy**Ma@w"p{ RMˆri΍]~;Ԣ*)%Z7p<u^Qz@ݢ)e P"{5V`ZCTS" rOdk}JG@ajLT:4#QEW8d CAL lR>;Z/Tz;ʩ)qlYhmi,y?OL?XӚEcm_k~m;[lL!uq aJ2"#O? Zʘ7AXv/@zTkgKM ԹV,ZcDGH I0N`ITT4%0W 0M,q|t85]TFwud( y /0 E*:Pui8M\'7Wxvz{FJl:3Zޱ{&qj9jR7Q_DXӞ-S(Eλ/jd規-숦]T2y[ˇ}¦2Y&PEEf*WIKqnu{`\Cʂ=OHEx4BAEY3C3X>1sW}uphWqЧ$]ynʌH(]E2޵1 DtxXG1FXb.ʲ*w4z#SMmJ\P'Qnx{xak1YN{]K&TyI^ XI3{7VJV }Lr䖝R0 ]A9tZ]a\WPh1aQBuH)>iL9ZېԀ!/{ZJwrIXs0Ay 1[o׉ a},hafjkT^ϨGJCT߯" v;r 73 ]YKJQiD#njĖ _@bk+-$2<Ut (bt.’z%iEёאmmo>^㈙F@܋ <U8l˰Yˮ&se@( POˑ!wGwhE+E,0V;!.Ed8$B&o''߫uC-ƪ.aF%r@s+H>˱[hgWPC: ⤜r24b/sh4}*P@bhJcG OLkk,U9H?RE敘>&uСki1&i8M\WOmӚ ^9 HGLvϓv_/4䣰_cfteuAŧ܋u\"?4`,0E"sH>%H~!SR{'w<wh G6(jbO1+\Dб"XQ'zA "v\?xVtlރfN$T0&w&T ʲ`'î0 8{Ԓ9[h#bO=N*GWQnzPDOJSwɺ>ꑐK,^F&-[:gBrpBꍲeQ籐3 {HnR zBr9$a =&#ߏo^(4W}x]Jd,[0__!n2 Bzz e?E 1EIP,՗}QB%|R$4-EvWBZ.bf+Z=t =Z[ebSe*&it`=Ds?æXSϾ5 wXEԑub7 98`C[ѣH"cL78l9WAJ,''T"`Vp/Wug):E'ؙRYD:a0ӝJ8H. bZk S^3t5z( pFC5 YXPtSdسg ]\gRwI&!cqe.4[=Jym:2h9p-N!'x)3FF#MbGCQ *3%Ys 7 23 aT [zRZt2VyH4w c&T.2JXnHT/_J+8M2Eb/?0i&ȦhQb40jDq d '{;8P <k uGЎ1aV0k<b9L6tBgn:^  Ny(kACc ݇V9Y7oQt`c"Ȕ'ˎ Wn]tX`+^Je4ARЋp8M+*&g J^/5~u8O ! Dc~恡 x>ݎQ-25wpul`odDxQ G3iNLLMdT,UC͊DvJ1 ۧt@t/DHQlnLxQ"Ё+L )~5{Ά=#v]h$Iy \@/F.hChVX'\HaQw{lI1eni(2o@HQͅ*ՑvHl$+5l-֬7H,; dBe.wzC#D*YfHW- Ŷ>*ix@Z c>l[ {l1 m0fM9|G~8Yx8tWPP4QM_M Em!:F?tsH._T=FuQ`@t*qԐ b$k(Hr,z,4.CGzJu yu\P*JMc&q| QxOoz)Hh7 JK'Z>$ MEPr2pDZ" 4/_(ec>7 kN1jHh0$fzBN<2%jCbHx<EBYqR,wm\X|fl*` Qb(񸋌C$Z `qH 6}e}J7W90p,nt&Y~_>m^wrG:@RGAe^kX͗z \̢Bc0 YZz#әQϒV}?dOجe j)^v b GTfǒt1j$RI=_޿wd1T^ .u5e3}c2^\Jŵ^[ &'s\TB^\Y6IXя5ZqRQ3QjZ}ORjH){].AFc<1b)B-v1-l_ ݊0K<`9,`u'4A &zs&ݒM7eTe'Cg:\ k&pDPVw,=_`HXȧ鳦HLgϞ=ƍB8HKU$gox7.˒:#I LiJ Ǣ[ET*/]yU,#ibWU!s/_זP8YD} /!*@:%\Nv(t-0Ń0֓`>~m"5P(ӳLf r`Bןo1D4cƌ|>z Og]L`B AMjL= AͿ^rs& u'Ƽ<¸d^7HKbn_R7WsE#] 99ҨZ4l[yԛk;SW P<ԗ ܁T>LNRA ^}g~5c~*CNS0!(B ޾ܨl>#<䢋.g L&=1;{leodRYMW選ލR7]L"Y25 fO{$4"Cn"t{ֱ: fQ1>χ 6Xx2-ALU/&Θ)Y7 EUhJ&m2-8Zwa° qc#9`Hs)^+k$WBI&+V"$6v.,cCu <---BtYfuww1l<K^1hӖ=] '~hE͸PO-;^[>&K\ ͚6i1-辫oӶ]ot1s lPs߲W~gΙ9(w<zs})dbe\7ԣ?u֘aZxuO|c>s?q.K^Z@/2sA 8mqϬX *}dƾPSsNh~ ;q#T;I>&%}lRwy^v}ӱGp"4'OG iهgPnj/^i)]p(Ϝ9e{nǎ~{?\  !bP% K=]<~+onڱD79qO &6Ϭxk=}ug>}jLᗧǎ` zs? `G3k/v o?~}2B 7Ӈzx[/:KN G6QGO3ߺspWɖ?qRg)8@ SF¡~t )PYPJݳ@U/*#/+ml~$YB ޵ίn exP 2d%Ҏ f_FN/7ݽdg-;s6>:l{Oe{4B&=Atb};!ͻ>$P: /ږo NrS+RY>j(~YDf}"EXV G/|=OQ*?,㡾]}<@ggWCC?*iN!-[WZͦP)P e`灎] kSyb냇Pw/n9EkzH(}?ǎiJg}jnɌ)>C"J߷G__bn2U%NHC6̶;WjP಺CG~y_ (C_q-/_NH4gy&drW{<j ~]r)3N6qݻnӶW]xM;|ԙΜ:Ah[_|c-$?ۀ=أǏN%.:kY"ć.OC¿~'`,ﯲ)䞼Cj8>g.Xfի-dsfPʃ1t/}ؚ p)G \ 64̜o/)g0\_9%vؓA-s"hۀ,FNn9e.@C#({FhtgGMBN_Utb#* x7 pxk׾Rogϻn1)_@# Ӓ$QSsN[QG EC4o_–gNn?=)znj &6 O>o} n]k`Com,L d`ch G5qW+Tq6"Mkڎ&XTLcd0f[oO>^0ѯ]?LZ~3]w?jl5q{|;81k6؛6m5[5e Nz&LXm=x=uK~@!*G78IhHٗ頞XY_L<#; /Vr7eG оMlYb x3ձvϺMbdcs+~SeXe==>ܚ'vbrpDCK$NRǗ$RQ.R#I;M3/@ItI^ t5%<<:9!^ ` 1㼑DɈj]7k yEv( J:!A@1 މ?QM|+/$[̆r z߻J M!hHg(gԦC?;K=幦Z,-)( aNB$_uwQԣpJ~`ٶ1m9Q5un[2)/7fS1bC>|aVz"u k)$QCboDI2WG&MqZgS<=sCqË :y(W`^]]Ӝd&fk(@U?RN_~~6O@Һ̄of0-zsBaދPn(A&B\n~O5旸xr2Qf<^d0-[@5,/Z'Q3%`S"㬙bZ,\GMj%fY+6j75"}Y)6+|I*aX˱?Z=a4 +LNEϬY}Yz|eʋ_Cl>_6ʳ+xsTķ-S6žŕ2W3/S(N%7ҡP)˚5v\힨`ެJU[4_]vz3觵ioY"}Rukj9х)}:\b:o^eN>2{t=gh/]V5vOmpPsߌɾZmq 3'w ]^p-<m4o{^@u*{MZ<ko;=,ʺ#xX(ECn 5Q?]SlFnU݅>}_tW9~Jٳ؜/~uf'Fۖ 9*.jݤnh浰 X &!,|`R {K ]yɌ7Ubja9*^xEFv+LU4D򥊃k\UY/5-:qxaCL"~ͭhH4E:X ZBڏvQ[? 6Qoy/'& /Nh-Y8'cC:#ʭq=3;UoX"*` /K_evoߝCÞ#~]T02P!x߾qHޛpwv3s'oN6Vy2 X1<y4=yLô ԟaO@9<a\誫h*5g`CEU*VѠA ]$ve~h*òi>Gp1e0llm6-f޲wjLA׃ܬz0ʏ^{ЖjTXdB ײ,̕(]q+]A59rf a0^K?ihvi=ų;XL~2D$%_2Q`9^J(|{o-)LY[(Q9kb5믾LL276^ohv|0GPD=LTm.Yr+URf, {Z} m%Nb4KdozW ;?#&IkcP8(ꥷWAZc߱=|LK81iپ1koQ4RT'9s|S@Q`g*kN|l =NWL2&r3Lz'x9%,1;vQt.F#㕛m.@g&n*D V,EOOG6t,{JDh- je i<|1赝*"U5psT)GbygTya >Goe e?cf>_lcX` {޷ػ[):`t-8A4$粌 Dќޏ-nyE*-˛A,о5oU#,fk10.zX7'+~F- P~{JN _㔢`&VjՎ(蝚mf,^Q)Q+PCM9ϔXt[-9=HX- {)b\y\t.;,{MKG͓b%(rPLe8uiM.yR51)}ޑ>j!2ۑeXUb7ez$,mYx^,_u[׌{MEx鿃{y͘%?qC)% CaboRޚrR!X0ԃ~~p]& a.K 7O{(\~zr.Ȉ;h Kג?!g_B瀯9-x1'wJ痮%XvCU,"6wOd1nwlU"~گy>SΘV=)<6 <[̄|)BrCԛ]ڑ7%XtGcaO" xۛl7l~z]86hl= NOs"p;HJT=.2fagԃ$X{0,ӭfiK6TϖY}@h%N;qG?fO*}Lt, mZUs}%%)K[ڶJ\k\leO0-y^2؈qn' !܊pUZ_c:2 aLFR3SVE}FR8`#kOEQn̰d^PַpP $z_yT߿πϖ|DP!哪KL8S-ֵʺK? t;VۂC֤WhSl$l͇>c& Z"'פ!֋yQsIMtoOhNgqI":Ѳ!˷(;$AVA>CCeJ,=}o+4yW/k2jLT525,1&ȡ/,3%}oz[h-[G C-z&8c : g0JG%ZYVF]^<#*/RGh>ȵ_}k,Π2&_|"'hn#8Dstl(eD1o]4 h?#i/ /K (D F,{3dXƏ5=jՒβ0ڢ51L1; [Sh^҆Ol^R]l\aCgOT:؅:qɠZtq & 8>$7RtnUHOFз'Җ* :oCWN$mD-%:Fn GIZG0 qJhȁx^!+KZ+>"קCkK2=:5kcJQݗga;տ2c;!wܟ[5E[>?+jFw[/&wBRcpnQ~}`P"j.u?-ͶzϹ|K=VVCS@A7 D"3a-l[[-,f67:$6d CyM[ n ~uT1"xD +}~IRLx^NAtF]LݜjJ3NnoFfy1Dp)O0Fb?n» C/:vL-٭ѩӀxc%K^voz8~ ~b%OceU{RH@{ړdzTcop]葄/Z2I:XyJN 3^Pq#/'"]&)zj@bD`]wRYǪĦ;ۼnjxO d!U[K<o{ߴ"T^*dhZK$w+sJ%k$eؗ [5 L`Lj1V/r̕rAL+Z,v'o5ԥ1Puh59WZ ԡQx9=gyF;S؉rq3Åg.Q5B//tȁۡz?{9O apyhx|ܡ޸ VLo>!/ K[[UXfqP= bVly%@=B160,"wMlN0XQ-8F\j3R4ns%t;{sk[p[5E{bVʗR﹐VL;WCK 炟p7ˈת*?mO@[UoB !FE 򏒩Hg+"RNT$=6g~1Q*, h;|nRܣِΘ^L\ҋB M]Tqwv; GIz͏)U+J*Qqu}lw.3тw r{:ki LCȋ$aQ$ 6s1, beǘ&M5jیcB7y89X3=O6?쒜~06 ~Kq.eQmHvoxHPUk! ^7LAd[^Ğh_ ن rˈ Ԙ*؂}ՙmWzWy}tVPĆt1݁Uti,.'``W0-俹ǪE-W2,v= {&PWHqx{_;-0(8v>F0ąJ8 v H|S X`E$ K.]Fu\pYhV+{.n cAQ^$n7~Aǀ=(SV[n\T|_ŧS?5ߵ=.c-gqD{ pE;[DNt'T^nM{%`?ŢyOΞ\pԪrg՞9PHyVbaXV؇ ,xo?Fjww<ZMr,AZLq@0nwus&!#S@J/9Fhʚy cUGIE|]i C}vÏ︁45pF|WVdW?8S:޿kG>Ozqbo*B82Ya~LxI łﶓ*-Jõڊ4Cy.ҀBQt!9X3EKjSlq?.λ ={}Y9Y~OWz7Nl6$:N_G mw )b ?{& v1 gTHm R yDOP.CqSi`BB*^2Cmkڰg2Y{n]ΧN#gC]h-{1kgZ?(A`[N\ȧn|iO (:`Nݿ1.pG+̫Ȭw׼%>Y+ cR`Wo\K=ӽd֑tT6-F@^ӡSxa%:s=N2CJNNp~jm!໚o4Ā9 ;Kl YòfĬ%eH< q_Z艳FnIԝnJYfH 7څ%=d8rh{L^:Q/jqon^#^['K5^)={aXIQW̔B≞5zno\W}Ud*){_:YH]5Wשio~4v(\n+\Ɠֻ@RƧ /9姰U}w)m-Hۦ+8S}siF jgvUdj:]ttm %=N?id`1 uƯop\NP޷uYMdOAιu719#!~+*C˧ϟD.>*ĖXU撍Ύ22&_>&C5Cu?hT N[_җ#y率{nyN_hW\X~ & }$ߵSj:~VX'*)1\.a3k♺t˯|޳HwjOC@>[0š˹oU Vqq#,z>tOJvh zus*>B ˳_,92^Cp1^x%lƈyX_tScjOyx ~.Mh `4? |} ro8l<9)R#_l:kpȑrt|'>Pb C!il[d`٘+8Ý}E\?lm,!G4l1[-'秠NЬnnN?fiBG=m^׭'w!`:vY_' KYJ$- =% ndmoYY¿D.=jx _ǸEA//~G iWYQ?+TtAl?*^ >$l10"Q@o#+LW@/VDrë3绎5ڬaRafF~`b^Ao O˧]0o}]{iK" HP-Bf m׻۵bSK}̰(z-mA U9QڒHxiZ3,-A'g6v S*EAZ4zL}@Nw;2Ćkf` oq^1>V^ #nuyP'j_ #yх<Q+(+vLUi(UR^Q>g@|x^8 !@%7}|6،0-ʼn\8 ha4{?ϚN RBlV6F]pү`SL>p=DV bW}~};\2gx\ʈzsOj !k}v9(t<kP81__j"*0} Yi Mlۦ:w"Cv\]`ߠikIPt8:/dԅ5OK|f🾾7Q"š$=Ha k~~勧 jF[Ȃ7UӳllZ6IS {]`֣&VhfTgV^+E_Tί2\h=vohIې^! |n&ܐ5ʨch>{^ׁߞ5 ΕbuũwsqE4u $Lbr. >RJf@ 3ybP'jϨD>o琜\!4\Sckv5;=wВ` ~l:ŇMAA ow;NxZfB#jG5[w;C{H톳*=ԈOχ؏tܷ K r YFaܣk ?WQLU 減%|Itz(dC @@5BM$dwʩ8nO’F!a[R%-Z BGr}gZM"h4?P%9ߵxiR&YgM{/` L~02 kXftkb[Mi.![j**q+cK.ݟU^ a9q*"D0qh1|^: &Q'"KMw3閃QqI&Y-Վ[@~Mv1[I-XG[fok\7onZޭmS.4Y+24)C=! G!w;HFgV%X%MLó/524(T56&r(ZC5(DKc2-=1}2$[U q1o0܋ '43=" 4h~s2ߗENH A@`oxu ceZ]q.CsR9;՞w-g􍱳zǕUUD/X7JR?WڄF"=L>2;Zƥn%!12eD0_N콾%Lcr3 ai%D!b0q67䰄|3v,r-0 qA,ƞ[ ).\JTEZ}Z "<͝wrK4ܷT}NkJ:j>ÿ,QcK zz |V@q#vΗr䀯[!"52\vF qR¦a ݟ3S.@)a[W"\ƳDa˝6gY3ۅxs}7\Ũo=')`P,d~+= b?}N +0@! ~'~JB-fQg_ej0Z땉i;@NU#2HW re8'Ua؋+~f}>1ĵ[Т)"[Eu&+BCHT@b_@LէPIn@+x8VV˻^f^T_`b=C9I߈ދ/}zv3g AS]˧JZ|W5T $3rJQ%7w ,Wg]o}kKɨb<1V͘x\0MIWt Z;+F3֪l'00!̈}6]m"Y߽#VG-3sfFOYq9j2R2 {F r1 9ȥbʛ ]ܾo+>|Ǿ_+Q++XUi>fg_0nTCU S I>~{:7ԋ=| l?/'FON0_KJ 'u)0HxzmruBz~^ #ۺ 6MЬ.7 0%RVh\$N`rp>)_}ӧs[\nʌH7s_+>V' ndswi%'kb`ScIƃժ- 8@RJ!` ^-YU-D yE굹Al|p TUؖ$ÅCgHpZCYsx?./oKBI!3&M2ie!GP'!<.ŏBU~<ghЧUE3cs_Yi-dkOh,!nю&q^%/Fhe2h=)$ }Ih7·pR7E9S8@W~7 .X{3\TmF95BGr}83:Ϻ "0;S ,q|Ҹci`|DBt4/Vb}t5@?>M޳)eEA@F`4 41׷IplXÒ0 &ajuUk'H|)b "_~m/.(e$, FS.*¯\֤賈@ڡi[.2ϭ֋B0NgS `}Џ,?xW°j qyj"G0|~Ӆ ǖ3SN+v6;FƦqG;65mO"c~pʤy-<*r8+4MLsHsX6nRD1X+{[.&&B=~m3!}hK u}lˑc:PK@r)Oq*+ CfwA_>A4WqH_+.n(F;~e/+k,:lK!WɡCjG}Ix+!{ veP`}Gs (m.5GOqt&iL+P[<2m}?d1hj>x{ki9G9l$k5}?b|3=AC&ah %>^; {%5~-ߵI'u9%W$HSVԃ+#y?\mK) ̸h]36%q9Vv]>\@ rԦ!`MGK}Qi>A(~-&þoC yw4 "^]] N 8|@cjdRqxt@7>RFXXR̍}vQbEULW៊`\49!_a;2Yr|+{Q֫gOv|U )ǒ_p@uc,̒rxz$`mf_;LLÌaPǀr 7 ؿq/=4#SXͮ,$wdv`Jxx{xxnN8LqpLB_2kUO2FRm[?*[jm6my@Pt.y5b;\ * f/Y gmh=OXh31"B <@X>_πAo]ѭqeՉ{G&꒮A37i&rl Sސ}A5T  }ETpK!vjH$ؓs<#74(!4y\/oˇ?iߢeYH(Qaوvm"E*9p; ( }߼]a/~7 ieǮ_p(R&61>T馞گ~E}a}KzOA@9aPH[\^="Ɔ$[M$<}K: z6篅4W/_naZjQ^%$hؽ#Xa=X##T/ };!00XV(gOzԀ8Ʀt~%SyWr8w#~tJ1HSjeW98n~t͐H&uj{o)U>/|5i|DR!("Gե[.Ul9Hy[ܡ] L>EaU? 1 _eHIw ׵ha\eJ3=V l˳D؎k9 ;ޅ /eEhXLJP-Ƀ`.NC>/7.`Xe(1?F׷u56KX^}žt{`)Cps47ɬ$R:-\NzgW(f<%kJǨMU#k,dyϯJEF~KVly *zʥiQZƉyr{<г"YFO{-]Aɏ_Y|<>LtCpq7@WtCt=} Y`\_k}߿;?dIBsuiO@꓾Z Tkа>(#U)],&pbJE "sT mB:WY78*J8W]@]>OoħY0fD8aV_ `˩'wh l_SlC@0g{ 4iٲ7Cl=;V3{cZSx\vSrQ3㊚ȓe7-jݨB$)2A;K#ӷˢ↯{2;A6w"ɰ"&,(Ȇ/׃LEo*7^%?˲ h!Y4+ߜͫ!~黷?~^%7w^2+NT^h0 J$%k8.O~Yc*X1ZUg?@00jՙHb-AEկ\(1`~Ͽ|x9@"@[U͜ hLoe 7ۥae8(XD9pkKW][JWZ⭊QP7 iC^Wcr>0;ñNU8ȳ<7Xf[7؊k W +cVhS\f7_!_/߽6XiXpǷ/~㯛닺MVr0w|V;{g32LJͯRöxtfHv[A$ۧYc(H&gXcqtYpbX]86ؾK Ș}߿?2y{~0]̯%Ӎ Z.wokkH`V귭;`4ϭ7̖ CJ/LDYbDD)j o !4kHix,1Rأ@IL^O6D[`?ͮzI_G:'dX2kOx}}//`FLQbAZτP^HӁ ϗ1_ƀul-Og980"l's؟_^C !^fhڦWh5#O]1JZ1_8cI9(r(/ɷ!ޡ]C2},V|@l94A_P۳7uI`Gi7o^m߿󫋫eǏl;,߂}Ii}= rj!rfM2X(܎=fhP0=v KC {y(G^ SrI`C 4)qlwŌc#r:g&@%.Ĉw5 D&rקϱ<O^^ݺ|K݆\ڵi1yfϸCCL.E_$=)#.zgODk *gh/$O MXDYvෝ;kL!PjWS7i=Ăwzp*^D2$u}I¼eVp)qԂ\AG'b|?ژCx8f !CYKLLXúV :'k܌n!$eʪ/X]/ik_oIAUӝ͗D~_;h'._ fբ/@Y*P*9` xRxT"gPjgnQ@ԛ?1;U:d5V=@tԫ~O|,r pY2\^:wCJ(GدMc~`7B0I.ñ@UD<o''[k6RzrH[K^^͏+`At.`ʅ/yXW\B1#=~]Ƹ( .}Ӥo{㤻 m'::n*viHg6QvD[i[͛h^,n`8瘥P?== #P-7F6"rvxq>0t=}o}P*d9L! {%>Ёka W=T^6خw)i&mIӡ5JE)x,@H> 9T`a9װCȻo խX~̳mɎA-ng@ yR޿y0zzR+] inA6f@>GZRM$Q#ᐉ#,~]'anx]ˏT?=E­±k(>ʲ692daFb?{2ۙd̋ף~w5KpY $WVrs't+81Ԩ4}5xq}V*Hk|c7Vm nc~')Mt,^vY]Ce)<xFfi7arCSϢ;@tOJH~Edw7}2/&WqQ!$bQ5h 3ޕϠ7jt=Ncil7=7!p9*%j,tjCJWЊ`eE‹I_s8eAWVDIa*[k " jԢԪݸ/ 7]e%oNH509[bu!YD,*t*׭y{4FV׊l fkk JW aa#^|Rea} LGtWt#k5xӨP$Xi$K#a{D]jITbu3XɅPo / cq3z^1tvJ Yl%,S"]m'_wb>h yŵEU S-Z^//?};Lђ+fK+wdm}32*Ҝ:k8#z[:K}DuiTBqyT!U"7R({&I" G5:n$ hf&HZf'LCYNa]YZPwޒ*,s`&荙R" s,[mul)(j;,v< I}1m1A/Ts͑h6~lJ?Ma芎))ʶ/Xpz̟l,^E5DUK-_"vOFfo74iēE;㻉Q3kc wRs9H^lP!o7a&n<iEYE($mnWPWiv˫/gx=BNp:dl}/ g+[ mvo"h1_@M%!̙CaoRG>e#G#ɤ޾x*/L}Bt%71OED̅ݒyZ $=Rޮoj2E}P@~H/7ҭU%g Xbȶ89sY啣˄ wī&{!r xyᨴ£اTŰ&>LP/wMc}$U+&% C!YU4x648n, X`dz:!ZbJ:;-Q0ZLkFm:v0QX55~ _["0* Dvϒր5MGK [T{9J5+"ޙZd@Yʼnx*;u9zk1* [4}A}O"5YGx0{&uPrlQw5U+wѳJ-(tGcϡO3bٺPcw7ů:V-kq3HtBƝL| ;z|z0}lAe2&=B\/# h̠ {uE+0{y=XNa/r wIuJ&V*CiMzS̅IIk{r|*ߩ!oCV˙/qRK^bbTbM<=N9Si#D+h(XH{V*7A5Nrc%S#/i2dyxB; }lȂa_8~qP?BRlԪeYЏ$D>]ȭd׹9"F݊(5X(kY!_؅kdoEDl-㒛( n,.^!U/./>տ<wV/Ow';|9}p0q}C-@CKKdg M%IH+[o4*&#e4D%; k3}.C,tbGi$ؙ{~DyH4Oiɠb[, jER.R.\ ^)m!Z|}|~%Jġ Bw3GC/9Y&}uNKo ޔ91so~:]_ac^ĺk')z?%0[K`HTAV:pkTɢ@28b8ЉՍ uЌ]y{*oQ/"*qL`;LG{u3/sD[=|>jy: ;l0@lY -'Y l ĈHɦGg^HZJK_pYID\2֨fqTX"acͼvRB ۰?]tǽ eF)!Bb(ȣgW?5H)ox<}؍POOɜ^R }#+E GOΓE:*wz6QӈSL-o0,MoionқЭ4g ?gFFis- D姅S{dg0YzjyW8opXdHCQ1mc 0@ԃ<nD 2{N0̍ \(Sꐤ (^Ё5.02 I [!#B lxF5:0 MExe[U10O X+T)LbvRZK1_M6Ի XQwmv%nN 1)www>]" <{-Jma3 7 ڲL>>C괾5Te<A{d3q"B$laf9#߫xdRhA^+QC##./3LTgչcyQ?֫兂F V@)~uw_Un8bB%zF''ȥ- ǫ~vJ_d*4DEĩT/C9ι_q#PZN\i.<}{ ̈́}05 nn…GiK@͇ЬW&rگϑy 3&xSJg 1qr4i/pP#;vgW89nI3oEqUyH 'ȳQvDJ,X خ/]x BũjZtdl1c%Q*檭dXi<_ 3g̶2㢈 bY! H'x[!a 1M\PE a(0b`.9E j\7]FVu疘(Ǥ" ~̵ :0ιr+uVMR%Ů1'<_^Lއ>6/vV.1}gKI@ •τ0$B50uGBI9RZʼ^|-0?c". Z 7MYG@NoE]2{g$r.Kjd]: ͳ-Cla>?\ގP}Q Ūd 1ZEJMF3o3yBG2i:eH/Bq@Рϟ@7*܎ 5OhJQ~h эEq}MϞ?1J㹹㩚#3_!k"RfbP9b` Ks{RHqEXa/%u=@14 **\NTernGLj;nв٥O/U?M)}a,c 9HGZKu~akEjT 8æ|-%b^¨o/j.vf,ɐ 9^\\]\\pqk{:+" yj}Y6T+j,R1)^2?BUC-tQeaةR: IG>`6G!DH{.>Cơ̞U/S-3;GuTn<<5{PBi ;_^~3tx@W"ܜ@SAV198W9? aHu E&0{tTD)"G$>L`d,`8i83n9L)-Jh P3 XǠnI|¯ij }N6eUFpU@4<5*5R[4TW(Ĥ {/$ <>]\t/Z7fz9@89a,H![:ꦲ%&sRe`A<1}"1Cۆe(B+mwA<Ԫŷ2U-܁O 3 RwS.1 ҭ71VC[4Xe]نxZ Jԅ.4۱KrꑼcL7ZJ`K/`KZ%GD4P=@Un2r$Cqзtg 3Y"0JŇN%+!22`$Z]Z3US[31GJ/@`qŚ8|?j ٿ #d qQ)kױO}9h<N9!kVa=|v KA%ܜd ggx:[)*8U۬6q_by6}L.H!!UDٚT4F螛-˭t $>JfeYT xEX&+ hF+b&~{ [M/ _? ZZkV=Ip[,-y27Ocxh3+_:ZEg߁kM1*pmo~ev޲G։v& 1$zed1 ݎ d5Op3pIrIY@qaHt׵سwC.8EGu_M)ߓ9O^ [׏j 0ph/iAlC%3Fcϛ8-|ŅQj4k0M:fGs⦇ŞcS c}Q eV?M꛳pW>f'W|'"fcz, 鞁tR "XRVPWz"޲oY\pq&cX|X@ N׍]u]5;mtd=:XhiP9җi XP#.'ҁԂOhh)s؈!+q PQ~z>vۻXe=XܕAh=~|-MN#" ׮SU7ܑc nGI?Nh]"~a<{KE 0KC!ڥ̤7Q)Ռ;>0<'C㕨nG)":<{ɪ,{H3,&\9w~q9~ќ4t.Fo'~Z].JLZsgpv0Np̊Q&zCJef8K3 Ӭmz>I/7XH|5=1}BKg h:Z\{_X%reqš{:)A}`We B >x2[IaWxX0[xXl kUx+yI/ SiWXMY3wv5uqQ-sXsM`bwx*~w00%X; (FCv|9)0$ЗQ Sa) <2SaҘj.QÈ&B"}F;ia )?<b \_QƝ/ JXٻgkee"4; D6uh8񼙤^ v3#1j?BNHD.Y:A({%A:B?>kXH;Th`khg@bE˕bRy3qʸΌ\2)YV9T_nTgЁЮ_GTĂgJԋ9ͤQj%uO.pRQ{-AȈoq[J _3 H xFs*V͉؊9ϗ)R)D\3(HQcJ,Fዡia%:V>yк6B6%EO)d,Evg-c J ](2rM\jSWRv>] !>}bBB  K"f`ajog DTj}uo\҅k`W^N9Z ^?n&H`14̟E]1NKc)ˤ/=?1 @vXq˺JxoëSZt12s7}Xs?~ Lŝ*Yޚ'loUTNaaA0#>p\)YSQ/aB 'x/oDR.qg.3 V/}e=tPmAҌ k oav @B (q8Ʋ%ǃDG"4UMAJQrX&zm7o2CkM}?O痂 E\6F1 M04a46Zctתφ{IV/s CWG#@e%ȹg )4ulV3SPuTW w7\BK־i[}]5g`n)_|s gNЀ=l\B5Ơ=&kF;lhN?2E}jW2y#({\kuqKlpǦlG5vÀ gʅv{U ~:1wLŕmc3JLk0cy(=mRg7KNKi HJ :+n@# - `MaNGl^;܏1"&Z=@@Va Q{%շ3d7$h((EBէs{C *uP10 v=qBgO  ƃ*lsh A.!D5W<'6FH;ef/7`C0UeP!]b*PEhս&mEH9H 5*M9\$#}/j+,a14<%siװˑQN?Wz*<N9ȣNf}6C @^< ],CGȪ.V;+ ӤJ{UkgY9ᆁ n̓\#Rjd"h+F#f{}2+KOm+k (Жvy;~ld4DW1n RΫz'"g&_GӪ-P"~QszZ4|#q;='U}2 얺b|xO* naښ dA=;)G!ai QwJ+,WZ K@RZrVݯQ_cF(vQL,W=B cՎ!}t/KdOb\aiKs] Gşm6)VȎ\QI4DXpL`5v4Ofr n=LW5EOx:P!NqysRŒ %ddCIJɐXj] P-s b0Zϣ2LxH;K+F'`RfOpSP M5?`^61 ^_V-nVBn Y5dY*7C4*3WO$YB*X/ (x E]`gD"TJyU 4cUϕݓ,U2skg]וa:IhQ y:@j+~:`9Ο P6[E:"A@R$T+!4pkWi\\Ňy `XZ ,O\0/ eYzN^xn9YϜB&b:F4wkǙ9)ke ƒ|hC^xz ޮ:MG{.!»\8I~1-hōoڼ]A 5cMewAy^4hm%.тU&CQ@:L3_"-ލKԡ}T gDWԶN TؖU,rIw{}=KBS!"F٠GJև{`UgRDZ(g7><G {{Q~Ʌ$d&z'. n "DΡ;\t]Y{ Wf*Lenjw,7j&1eDfx^crM\Lo采מ$h#ЊR>'Ŷ0QtŒi'#X5T}i4ޥװg)WV{rLQ Dɺkض;mcR`b445&&EXjzL @$\>*1YYTzτZt.=Yu㧵zËȒyF4<% ,+C1&oeFlF\iԈLK2&B?$6T+ɐ@K GQ3q{aSW9`s ÷O(ņwَ *f/&cʧ::]JV2֑ҁy9gA]c"[F+7ZL$z#on6„RRJo~_TʶȨ;kR"6LW}-D fKmO&UKҷw#78}gywgk̏^ˡ&hsyԢ?E~_굄ߗn` ͒Z 4ghUoy(A2Uӊ-'E4+%{!4%YjV h`/.mFIb3i4<ʾ{eyPRK-99oG7ۂSiUÙnc`cmFLHWsV*kUAES1jPS a_\_NƮ8_5EC &m#7g2aRY"~Uyk5x34̔՝Ț륳Yr5ݶy>ȆS}|}kUWޓCLL$rBrkw PM ҮHLS_39,Ar ]U.'ڲ}Pd.O2Ki+Yy7{v35c+f$$Ӳ,k#t guLL.a KjuٰL-eqSW` 'Qiv6cSAfy 0qf[Y!Jy.eo3RdAb%:7ZvZV& :;LI"lk's'P_ֹ |}k]THfI˗0? ~e'y`a-)<4JxsnpeK@> è5p>1wN ෠ryĦ*X+;L{6Qe}¿[fY}d$ j Kx&>'m.o/?^kf%TIX*icص~0vQ>.g$՛틣LՁw p'SțV֩T V A&8[7u":F4y9q#]h=<08 `FJ,t%jnrtKYDP <:$"ߌӄʭqv9-ecc1UB"zv: O}|8뇨?#hQ⢇H ~e :(lP71-wc:4n]_lz|ef?ǹG4}J sTqI?km4]{F [~- 6? 2g緜(#0L58#Mt_Pi*j=iAΚ%}T ~M>V܆HB8~r& ,HBP XƤ{Ҫ4vo^"fd9y *`_]؁S KurWoύ K[4w78"5ziHI†|<Յ *#Ej͔@HR&]-ӠZO½sss]qBT/9n-r u!Q_$˒7\=Yh6nM̦f t=(p!/a" !qWYdn #H`"i{||\pg+,9ăa֤EWD~-$fzb }OTn.2NbCĥa I*n"5fogBnk2EHdb7NE< P1q{c6p>G@c'[,հ X)/ФO5["+ruL! `QR@s0Hy T] `ʽČǠA|uv"IfRmkѻV qF+ 5bJ>@A&ZxTԒ: `>Cm)F-Ԛi }snۊ-O{}zU1lܸÜIj*+PU%B2}\ vGHRۯDp5.?^}Gb:@ajɣSUhDiﱱ#1p\#+:?I]I#O_#2WEwj16C=)RQцAD 6KI7t3]&ô/FsIr}he'qsQe-wg*l՚%X)WvaRM\%6# G!S3< 8 Pn n1kJX.W̒j8o.*'Հp[3VKXj1-5)g =}̤:UZ:J gաI\ï(Me0u3qd h[.w&H"J~/`xy)_6;sȀ5C5J)`GFKZ<+]+%TRW L; dIZ=֣$z\_s|%ދ%4Re82*F3_` P[&ᆍ՞!%|aIq#JàQ{-(.[Z4nOa7/+㊥`KNQK':d́]gےzkb=@xSַE6HM~묷^D` <(ánR%Ťoޥ\юUCȡp79*?\ oZܑ)IBKdk*; }oTh.fE*Ԥ-f._>@{{pe.+ UxE-k dmH250ȸH:Z-} FGƿ6}P8JmzВRi().=mG U ZtYn"`3v oVBL ߐx]uJ/I:@{Jg>> mN|%OLߠ|e\Q>wO¨eKhdQ #l)e^O&tIYQFa_&Plyn 57v/+ rꆙ Ё>WY?I3\xjDUrFgX-^PEvP- P\'wrP(@YJVϗmJӔ!Xy2#rOraCo a5L,< P^bZ 8|(81II7)UѦ* ]HBu$@WWJ8hWǠ{-Jg\9P Z gLlPުhĴ>6ff:R\sHd\{ .v'rc^v~k?9seS(;jv.FYFۇRVmDFWJc Mh G\3Rv<:|n7ʴKH56c@2sI'BuȫJGFN<Ơ/zL*qƎ}#ve}s)&kJ.śs[fh>GK[O%2`)k.TJ@u]Gs6|˜ӊaRV>7FšMc+BtFpE-Dv<\ea؎p56IӞ{[2L{5~֤Xpp5,j|mR {Ew- V!mgxŪZcKV+'+mT)6!=``oZv҇{qg&o 6vT#V3,U/*=- g 6zIf`t%IIԀQF*˥&gwjtvl©IzXd/\]shc ( ; s^狃dk<$?`o=%`j-#̜@󄪿Ёe$\˵v@*]^~-҃iZhry==䡺~9Q8#Oγƃ,Ey>5γ؊Y؈.JE~nhEh@]p{~{CA1`ݭĀGM-j!O `&J喪 k;2u7=h ⶉO҇\c-&Ny]7p 6}~ys<@x\B#K R3&F.cmZ椵UxeI {sPo([ٷa岶ś,񤭿3ӯ`XGE/ (6YLCM;m EmGI{! wCf yڼ@$+$_/քyn<O|j\NCad B?>=>~7od3FviC>"dK^M,2H^xE 2̚\*RXSp*׊HpݢgTT\.: ~DNg1kY;!0s u`hb̒MfxEmy8|ŧz-R#Ϯ?Ň-F#G0G|!+w3=k8LONeKWh2Sb$]X:¹\:xyAgP__SX3y#>,3VGm7kr;a+o6&_:VB,i/'(k?rtoZGOz\W?oo1`!ܼ׿'<?eFikz#5B[b$e/SHkX?gQJ:!.uUff=/?Ա X kN!ƞx|?0'ãrߏ_n1/>|{HL`NီL&ݱ0t QV/qX(:˩,QVpѐLhs̈́+^Z8mD)De=MKJћM`X#>(І31ۧO/GT6j sH)@>kƐno$wF%&5a:^#@ eR} U UTHBB, Aks~i_O*!EհfoFn3p?}ǟ_] l>>;H"n! 7!c7=l)%sU/k,R"6Y_s#v}l̇f l?Ti@F0OǷ7{˴}2@T_..L4%lixj~xu<~Q RN/]_k{qׇq4_Yd"=ZbVB#bY1YfQ526{s  />U |_i(!P:Ejc:uξ);uؕ\ E,oPaf||cNHn#?od?.)]^_l E% IFCJQa$O ~maB@q\\ͼȓ9r͕ V~ɼ{N|^u4g~5n"tTM rK^" BV^r )މT\v3q?/ Ee =>P`,J'B[ߺ=dJOF9wn p|/{=*A8Ŏ%ʅ>YSŸ9^feЍaF+hp%Q=*; ! sm^tm];PG]nt7gc8fLnT넚,ջ/u {2[Ʉ¯[<.'{ B6Uw 2WY `_=CRW U+,x0 9YAz">uQ$1N'.|FAzL\@R3ezT nH@/ }>1|m~ގ͖EC0 no'p v=t>Ip?и}[XR4 T@^\ _P p X|Zp(.g|E>,ݚVU?m~w_!5q{lYSӑA&U{6ĄG(&~]7v%f;:wb~BcزWM$^L@JJY#r{;gk&-!dw <4Ϯ!0׮4' F-sf |[/$Sam%bU88Ek9J t am~~ԬZIn̰!0=/ Z,ZMWCиwԭa1 r P.`PSω^)',darRc`0 F}e5wkr9~VOC$芍Q1:.}(}YkU5a`[?EY8mpQ;-ˬʧvgs- G? 1:H3.yiBM@ZHM7/6 D5w Pf~Wسx%EЅiW%]=-N&,Ǧ.*Ϳ DJiw^Я/DW[,Ev`]R8R^P3& TNPG"|N/?KLF9q pKx_bw6Q8xk(RfZ=YU0J,1+|Ƹqj7.4. rV'ƤUL5-"v“:\YVҔX)-k7QP+UfUVz[`\ygGqS׼tT 2ף1P|l>n1V\&",iph>8Qr jn$3ݫ+!Z (Oh}t;7]Up*&rZP=ۊA?W *z-Mx$}KŸL+dR)!C}7\'[_0ēo"xM>N &Y, ɧ^_ʩL UCJ>8KvSW U( |$mz!ɭ%2(?T&¹o %GDn} U-8O~I?qeR^d]H 2{ZHI3ٍ}'n{Wg#jQ/x15lc5 #4DX%$07^Z)Mʼr2./>lH(Ȩ)mWog"RئfՒuW{B׀تMO"^$яv@v5'9tgpڗg^V}cWz;t`IЕHJvnOA^0U,e -p~auA_3]~Yr^g"]Qgo)G|p0^\h>L8{\^l;Ul$G >~? w_9$Fr;轑nFf|0/xB"0ދ`rhI |#ev R;Fb;z?SuOA|8/0"eZLJ]f0+~u=)ᚗaRzlX-& c@A7ͭZjI~Jg6VoEco)"f<ʳwá e.Z/617uhIn } Tz9Zb³/k*!$*txw D?MZkn.X؅ YarFP~=7_X׵g\\U@/{]wi6̞pDL|JZ 9=03>*oYuu ڶP_ӻN8W袜zVQJϏHЋ?h=^5'{}Ϙ6}W;j>{_q D~kؾ^[+Wo`!PS?UN0N2Az qpd),yw2 -Bmw{xqwxGs_ov4;խojYo 7n+tI*5@}YM'~>ʝ@:mړҍ%&`J8L6{(xsy3 clj&}MG:.d$KN\Z~ΤS黳F Σְ__5}}DjMSʷ!ůuk&t7NF,؀L>EUkV 1zߨ<hX6u0fPb37dk~=Ѳ'mg6nR_Rv*"Mscp4aZ(E~HlbOr.?m9&4UL¥96_AoeT}UHэ_Yq-j5k(?odbI0?  <=r/l,N( 3DSDN )Rr1@`oR,c V_3AӽhWq,VxP $MQZC#:|hpVײofsO`EGl5 \ ?ܽi BK5|Y)&=?*ӝ6XU*ƾ%wHprzos%H0սơ:'Tٶl|ٸVcNj=oױ| sEѲ?xVj}O)RxƤpk{$cGVFXEH_Dd hd(A).;*bkY( ]{;\m{Jj99R WE c.<.,I<_BK J6՞hVƶu4ŐNִ3J߫/ϛ+_[S!~򽅇kG.xT-RO"H始 C vCWl/AL *@ê WQMUk/v M7 D;fc 7 80EeW>kmٽTKhV5ro2*s1m;k< * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCORE_CHECKSUMVERIFIER_H #define KFTPCORE_CHECKSUMVERIFIER_H #include #include #include #include #include //Added by qt3to4: #include namespace KFTPCore { class ChecksumVerifierThread; /** * @author Jernej Kos */ class ChecksumVerifier : public QObject { friend class ChecksumVerifierThread; Q_OBJECT public: enum Type { CheckMd5, CheckSfv }; enum Result { Ok, NotFound, Error }; ChecksumVerifier(const QString &filename, Type type = CheckSfv); ~ChecksumVerifier(); void verify(); protected slots: void customEvent(QEvent *e); private: QString m_filename; Type m_type; ChecksumVerifierThread *m_thread; signals: void progress(int percent); void fileDone(const QString &filename, KFTPCore::ChecksumVerifier::Result result); void fileList(QList > list); void error(); }; #define CV_THR_EVENT_ID 65300 class ChecksumVerifierThreadEvent : public QEvent { friend class ChecksumVerifier; public: ChecksumVerifierThreadEvent(const QString &filename, ChecksumVerifier::Result result) : QEvent((QEvent::Type) CV_THR_EVENT_ID), m_type(0), m_filename(filename), m_result(result) {} ChecksumVerifierThreadEvent(Q3ValueList > list) : QEvent((QEvent::Type) CV_THR_EVENT_ID), m_type(1), m_list(list) {} ChecksumVerifierThreadEvent(int type, int progress = 0) : QEvent((QEvent::Type) CV_THR_EVENT_ID), m_type(type), m_progress(progress) {} private: int m_type; int m_progress; QString m_filename; ChecksumVerifier::Result m_result; QList > m_list; }; class ChecksumVerifierThread : public QThread { public: ChecksumVerifierThread(ChecksumVerifier *verifier); protected: void run(); private: ChecksumVerifier *m_verifier; void checkSFV(const QString &sfvfile, const QString &fileToCheck = QString::null); static inline long UpdateCRC(register unsigned long CRC, register char *buffer, register long count); static long getFileCRC(const char *filename); }; } #endif kftpgrabber-0.8.99~svn1214766/src/kftpbookmarks.h0000644000175000017500000002154511276037142021227 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPBOOKMARKS_H #define KFTPBOOKMARKS_H #include #include #include #include #include #include #include #include namespace KFTPEngine { class Thread; } namespace KFTPSession { class Session; } namespace KFTPWidgets { namespace Bookmarks { class ListView; class ListViewItem; } } #define KFTP_BOOKMARKS_VERSION 3 namespace KFTPBookmarks { class Manager; class ManagerPrivate; enum SiteType { ST_SITE, ST_CATEGORY, ST_ROOT }; class BookmarkActionData { public: QString siteId; KFTPSession::Session *session; }; class Site { friend class Manager; public: /** * Currently valid remote protocols. */ enum Protocol { ProtoFtp = 0, ProtoSftp }; /** * Currently valid SSL negotiation modes. */ enum SslNegotiationMode { SslNone = 0, SslAuthTLS, SslImplicit }; Site(Manager *manager, QDomNode node); ~Site(); /** * Refreshes this site by using the new node as the site * element. * * @param manager A valid Manager instance * @param node A valid site node */ void refresh(Manager *manager, QDomNode node); void reparentSite(Site *site); Site *addSite(const QString &name); void addCategory(const QString &name); KUrl getUrl(); Site *getParentSite(); /** * Returns the child site identified by index. Note that NULL will * be returned if this is not a category! * * @param index Sequential child index * @return A valid Site instance or NULL if index is invalid */ Site *child(int index); /** * Returns this node's relative index to the parent node. */ int index() const; /** * Returns the number of child sites if this is a category node. * Otherwise this returns 0. */ uint childCount() const; /** * Returns true if this Site instance represents the root node. */ bool isRoot() const { return m_type == ST_ROOT; } /** * Returns true if this Site instance represents a category. */ bool isCategory() const { return m_type == ST_CATEGORY; } /** * Returns true if this Site instance represents a site. */ bool isSite() const { return m_type == ST_SITE; } /** * Returns this site's protocol. */ int protocol() const { return getIntProperty("protocol"); } /** * Returns the bookmark manager associated with this site. */ Manager *manager() const { return m_manager; } Site *duplicate(); QString getProperty(const QString &name) const; int getIntProperty(const QString &name) const; void setProperty(const QString &name, const QString &value); void setProperty(const QString &name, int value); void setAttribute(const QString &name, const QString &value, bool notify = true); QString getAttribute(const QString &name) const; SiteType type() const { return m_type; } QString id() const { return m_id; } private: Manager *m_manager; SiteType m_type; QString m_id; QDomElement m_element; }; class Manager : public QObject { friend class Site; friend class ManagerPrivate; Q_OBJECT public: /** * Returns the global Manager instance. */ static Manager *self(); /** * Class constructor. */ Manager(); /** * Class constructor. * * @param manager A manager whose contents to copy */ Manager(const Manager *manager); /** * Class destructor. */ ~Manager(); void setBookmarks(KFTPBookmarks::Manager *bookmarks); void importSites(QDomNode node); void load(const QString &filename); void save(); /** * Returns a (possibly cached) Site instance for a given node. * * @param node A valid QDomNode instance * @return A valid Site instance for the given node */ Site *siteForNode(QDomNode node); /** * Adds the given site to the site cache. * * @param site The site to insert */ void cacheSite(Site *site); /** * Returns the root site. */ Site *rootSite(); Site *findSite(const QString &id); Site *findSite(const KUrl &url) KDE_DEPRECATED; Site *findCategory(const QString &id); /** * Removes the specified site. * * @param site The site instance to remove */ void removeSite(Site *site); /** * Configures the specified client with site parameters. * * @param site Site instance to get the parameters from * @param client Client thread to configure * @param primary Optional primary client thread for secondary connections */ void setupClient(Site *site, KFTPEngine::Thread *client, KFTPEngine::Thread *primary = 0); /** * Populates the given KActionMenu with bookmark actions. * * @param parentMenu Optional menu to use as root * @param session Optional session pointer * @return If no parentMenu was specified a list of actions is returned */ QList populateBookmarksMenu(KActionMenu *parentMenu = 0, KFTPSession::Session *session = 0); /** * Populates the given KActionMenu with published Zeroconf services. * * @param parentMenu Menu to use as root */ void populateZeroconfMenu(KActionMenu *parentMenu); /** * Populates the given KActionMenu with sites from KWallet. * * @param parentMenu Menu to use as root */ void populateWalletMenu(KActionMenu *parentMenu); /** * Establishes a connection with the given site. * * @param site A valid Site instance * @param session Optional session instance */ void connectWithSite(Site *site, KFTPSession::Session *session = 0); void emitUpdate() { emit update(); } protected: static Manager *m_self; private: QHash m_siteCache; QDomDocument m_document; Site *m_rootSite; QString m_decryptKey; QString m_filename; QDomNode findSiteElementByUrl(const KUrl &url, QDomNode parent = QDomNode()); QDomNode findSiteElementById(const QString &id, QDomNode parent = QDomNode()); QDomNode findCategoryElementById(const QString &id, QDomNode parent = QDomNode()); // Validation void validate(QDomNode node = QDomNode()); // XML conversion methods void versionUpdate(); void versionFrom1Update(QDomNode parent = QDomNode()); void versionFrom2Update(QDomNode parent = QDomNode()); private slots: void slotBookmarkExecuted(); void slotZeroconfExecuted(); void slotWalletExecuted(); signals: /** * Emitted when bookmarks get updated. */ void update(); /** * Emitted when a site gets added. */ void siteAdded(KFTPBookmarks::Site *site); /** * Emitted after a site has been removed. */ void siteRemoved(KFTPBookmarks::Site *site); /** * Emitted when site's properties change. */ void siteChanged(KFTPBookmarks::Site *site); }; } Q_DECLARE_METATYPE(KFTPBookmarks::Site*) Q_DECLARE_METATYPE(KFTPBookmarks::BookmarkActionData) #endif kftpgrabber-0.8.99~svn1214766/src/kftpqueueconverter.h0000644000175000017500000000542611276037142022313 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUECONVERTER_H #define KFTPQUEUECONVERTER_H #include #include namespace KFTPQueue { class Transfer; } /** This class provides queue export/import to XML files. @author Jernej Kos */ class KFTPQueueConverter : public QObject { Q_OBJECT public: KFTPQueueConverter(QObject *parent = 0); /** * Import queue from XML file. When called, this function will create * new KFTPQueueTransfers. * * @param filename XML file that contains the queue */ void importQueue(const QString &filename); /** * Export queue to XML file. It will take all current KFTPQueueTransfers * and convert their properties to XML format. * * @param filename File where queue will be exported */ void exportQueue(const QString &filename); private: QDomDocument m_xml; void generateXML(KFTPQueue::Transfer *transfer, QDomNode parent); void createTextNode(const QString &name, const QString &value, QDomNode parent); void importNode(QDomNode node, QObject *parent = 0); QString getTextNode(const QString &name, QDomNode parent); }; #endif kftpgrabber-0.8.99~svn1214766/src/directoryscanner.cpp0000644000175000017500000001421411276037142022256 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "directoryscanner.h" #include "kftpqueue.h" #include "misc/config.h" #include "misc/filter.h" #include using namespace KFTPQueue; using namespace KFTPCore::Filter; using namespace KFTPEngine; DirectoryScanner::DirectoryScanner(Transfer *transfer) : m_transfer(transfer), m_abort(false) { // Lock the transfer transfer->lock(); // Construct a new thread and run it m_thread = new ScannerThread(this, transfer); connect(m_thread, SIGNAL(finished()), this, SLOT(threadFinished())); m_thread->start(); } void DirectoryScanner::abort() { m_abort = true; if (m_thread->isRunning()) m_thread->abort(); } void DirectoryScanner::addScannedDirectory(KFTPEngine::DirectoryTree *tree, KFTPQueue::Transfer *parent) { if (m_abort) return; // Directories DirectoryTree::DirIterator dirEnd = tree->directories()->constEnd(); for (DirectoryTree::DirIterator i = tree->directories()->constBegin(); i != dirEnd; i++) { if (m_abort) return; KUrl sourceUrlBase = parent->getSourceUrl(); KUrl destUrlBase = parent->getDestUrl(); sourceUrlBase.addPath((*i)->info().filename()); destUrlBase.addPath((*i)->info().filename()); if (KFTPCore::Config::skipEmptyDirs() && !(*i)->directories()->count()) continue; // Add directory transfer KFTPQueue::TransferDir *transfer = new KFTPQueue::TransferDir(parent); transfer->setSourceUrl(sourceUrlBase); transfer->setDestUrl(destUrlBase); transfer->setTransferType(parent->getTransferType()); transfer->setId(KFTPQueue::Manager::self()->nextTransferId()); emit KFTPQueue::Manager::self()->objectAdded(transfer); transfer->readyObject(); QCoreApplication::processEvents(QEventLoop::AllEvents, 100); addScannedDirectory(*i, transfer); } // Files DirectoryTree::FileIterator fileEnd = tree->files()->constEnd(); for (DirectoryTree::FileIterator i = tree->files()->constBegin(); i != fileEnd; i++) { if (m_abort) return; KUrl sourceUrlBase = parent->getSourceUrl(); KUrl destUrlBase = parent->getDestUrl(); sourceUrlBase.addPath((*i).filename()); destUrlBase.addPath((*i).filename()); // Add file transfer KFTPQueue::TransferFile *transfer = new KFTPQueue::TransferFile(parent); transfer->addSize((*i).size()); transfer->setSourceUrl(sourceUrlBase); transfer->setDestUrl(destUrlBase); transfer->setTransferType(parent->getTransferType()); transfer->setId(KFTPQueue::Manager::self()->nextTransferId()); emit KFTPQueue::Manager::self()->objectAdded(transfer); transfer->readyObject(); QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } } void DirectoryScanner::threadFinished() { // Create required transfers DirectoryTree *tree = m_thread->tree(); addScannedDirectory(tree, m_transfer); delete tree; m_transfer->unlock(); emit completed(); // Destroy thiy object deleteLater(); } DirectoryScanner::ScannerThread::ScannerThread(QObject *parent, Transfer *item) : QThread(), m_parent(parent), m_item(item), m_abort(false) { } void DirectoryScanner::ScannerThread::run() { m_tree = new DirectoryTree(); scanFolder(m_item->getSourceUrl().path(), m_tree); } void DirectoryScanner::ScannerThread::abort() { m_abort = true; } void DirectoryScanner::ScannerThread::scanFolder(const QString &path, DirectoryTree *tree) { if (m_abort) return; QList list; QDir fs(path); fs.setFilter(QDir::Readable | QDir::Hidden | QDir::TypeMask); foreach (QFileInfo file, fs.entryInfoList()) { if (m_abort) return; if (file.fileName() == "." || file.fileName() == "..") continue; KUrl sourceUrl; sourceUrl.setPath(file.absoluteFilePath()); // Check if we should skip this entry const ActionChain *actionChain = Filters::self()->process(sourceUrl, file.size(), file.isDir()); if (actionChain && actionChain->getAction(Action::Skip)) continue; DirectoryEntry entry; entry.setFilename(file.fileName()); entry.setType(file.isDir() ? 'd' : 'f'); entry.setSize(file.size()); list.append(entry); } // Sort by priority qSort(list); foreach (DirectoryEntry entry, list) { if (m_abort) return; if (entry.isDirectory()) { DirectoryTree *child = tree->addDirectory(entry); scanFolder(path + "/" + entry.filename(), child); } else { tree->addFile(entry); } } } #include "directoryscanner.moc" kftpgrabber-0.8.99~svn1214766/src/queueobject.h0000644000175000017500000002666411276037142020674 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUEQUEUEOBJECT_H #define KFTPQUEUEQUEUEOBJECT_H #include #include #include #include "engine/directorylisting.h" namespace KFTPQueue { class QueueGroup; /** * This class represents a basic object that can be queued. * * @author Jernej Kos */ class QueueObject : public QObject { friend class QueueGroup; Q_OBJECT public: enum Type { File, Directory, Site, Toplevel }; enum Status { Unknown, Running, Stopped, Connecting, Locked, Failed, Waiting }; /** * Class constructor. * * @param parent Parent object * @param type Object type */ QueueObject(QObject *parent, Type type); /** * Class destructor. */ ~QueueObject(); /** * Returns true if this object has a parent object. * * @return True if this object has a parent object */ bool hasParentObject() const { return parent() ? parent()->inherits("KFTPQueue::QueueObject") : false; } /** * Returns the parent QueueObject. * * @return The parent QueueObject */ QueueObject *parentObject() const { return static_cast(parent()); } /** * Do we have any children ? * * @return True if we have some kids */ bool hasChildren() const { return m_children.count() > 0; } /** * Get object status. * * @return Status of this object */ Status getStatus() const { return m_status; } /** * This method has to be called after the object has been added into * the queue in a proper location. Otherwise the state of this object * is undefined. */ void readyObject(); /** * Is this object currently running ? * * @return true if this object's status is set to Running or Connecting */ bool isRunning() const { return m_status == Running || m_status == Connecting || m_status == Waiting; } /** * Is this object currently connecting ? * * @return True if this object's status is set to Connecting */ bool isConnecting() const { return m_status == Connecting; } /** * Is this object currently waiting for a connection to become available * in one of the sessions ? * * @return True if this object's status is set to Waiting */ bool isWaiting() const { return m_status == Waiting; } /** * Is the object currently locked ? * * @return true if this object's status is set to Locked */ bool isLocked() const { return m_status == Locked; } /** * Is this object currently aborting ? * * @return true if this object is currently aborting */ bool isAborting() const { return m_aborting; } /** * Returns the size of this queue object. * * @return Size */ filesize_t getSize() const { return m_size; } /** * Returns the actual size - that is usefull only if this is a directory since * it returns the current size of all its items (if some items were removed * from its first scan getSize() will return the initial size and getActualSize() * will return current size of all items). If this is not a directory, this * will return the same value as getSize(); * * @return Actual directory size */ filesize_t getActualSize() const { return m_actualSize; } /** * Returns the already transfered file/dir size. * * @return Transfered file/dir size */ filesize_t getCompleted() const { return m_completed; } /** * Returns the number of bytes that have been resumed (using REST). * * @return Resume offset */ filesize_t getResumed() const { return m_resumed; } /** * Get current transfer speed or 0 if the transfer is stalled. * * @return Transfer speed */ filesize_t getSpeed() const { return m_speed; } /** * Returns this transfer's current progress. * * @return A pair of two values - progress and percent resumed */ QPair getProgress() const; /** * Adds size bytes to the current transfer size. This will also update all * parent transfers (if any). * * @param size Size to add */ void addSize(filesize_t size); /** * Adds completed bytes to the current completed size. This will also update all * parent transfers (if any). * * @param completed Size to add */ void addCompleted(filesize_t completed); /** * Set the current transfer speed. This will also update all parent transfers. * * @param speed Speed to set */ void setSpeed(filesize_t speed = 0); /** * Returns the KFTPQueue::Transfer::Type of this transfer. This can either be * File or Directory. * * @return Transfer type */ Type getType() const { return m_type; } /** * Is this object a directory ? * * @return true if this object's type is set to Directory */ bool isDir() const { return m_type == Directory; } /** * Is this object a transfer ? * * @return true if this object's type is File or Directory */ bool isTransfer() const { return m_type == File || m_type == Directory; } /** * Is this object a site ? * * @return True if this object's type is Site */ bool isSite() const { return m_type == Site; } /** * Is this object the toplevel object ? * * @return True if this object's type is Toplevel */ bool isToplevel() const { return m_type == Toplevel; } /** * Delays transfer execution for msec miliseconds. If this number is greater than * 1000, it will be set to 1000. * * @param msec Number of miliseconds to delay execution */ void delayedExecute(int msec = 100); /** * Set transfer's ID. * * @param id Transfer identifier (must be unique) */ void setId(long id) { m_id = id; } /** * Get transfer's ID. * * @return Transfer's unique ID number */ long getId() const { return m_id; } /** * Abort current transfer. */ virtual void abort(); /** * Add a child queue object to this object. The object is NOT reparented! * * @param object The child queue object */ void addChildObject(QueueObject *object); /** * Delete a child queue object from this object. The object is NOT reparented! * * @param object The child queue object */ void delChildObject(QueueObject *object); /** * Find a QueueObject that is child of the current object by its id. This * method goes trough all the objects under this one. * * @param id Object's id * @return A valid QueueObject or NULL if no such object can be found */ QueueObject *findChildObject(long id); /** * Removes all transfers that have been marked for deletion. */ void removeMarkedTransfers(); /** * Move a child object up in the queue. * * @param child The object to move */ void moveChildUp(QueueObject *child); /** * Move a child object down in the queue. * * @param child The object to move */ void moveChildDown(QueueObject *child); /** * Move a child object to the top. * * @param child The object to move */ void moveChildTop(QueueObject *child); /** * Move a child object to the bottom. * * @param child The object to move */ void moveChildBottom(QueueObject *child); /** * Can a child be moved up ? * * @param child The child to be moved * @return True if the child can be moved up */ bool canMoveChildUp(QueueObject *child); /** * Can a child be moved down ? * * @param child The child to be moved * @return True if the child can be moved down */ bool canMoveChildDown(QueueObject *child); /** * Returns the list of this object's child QueueObjects. * * @return A QueueObject list */ QList getChildrenList() const { return m_children; } /** * Returns the child at index position i in the list. * * @param i Child index * @return A valid QueueObject instance */ QueueObject *getChildAt(int i) const { return m_children.at(i); } /** * Returns this object's relative index to the parent object. */ int index() const; /** * Returns the number of child objects. */ int childCount() const { return m_children.size(); } public slots: /** * Execute this queue object. */ virtual void execute(); protected: bool m_aborting; Status m_status; long m_id; Type m_type; QList m_children; QTimer m_delayedExecuteTimer; /* Statistical information */ filesize_t m_size; filesize_t m_actualSize; filesize_t m_completed; filesize_t m_resumed; filesize_t m_speed; void addActualSize(filesize_t size); /** * This method is called every time the object's statistics must be * updated. * * @warning This is the ONLY place where the Manager's objectChanged * signal may be invoked from! */ virtual void statisticsUpdated(); /** * This method should return true if the object can be moved. */ virtual bool canMove(); private slots: void slotChildDestroyed(QObject *child); signals: /** * This signal gets emitted when the object's state has changed in * some way. */ void objectUpdated(); }; } Q_DECLARE_METATYPE(KFTPQueue::QueueObject*) #endif kftpgrabber-0.8.99~svn1214766/src/mainwindow.cpp0000644000175000017500000004246711276037142021067 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * Copyright (C) 2004 Markus Brueffer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #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 #include // Widgets #include "widgets/configdialog.h" #include "widgets/systemtray.h" //#include "bookmarks/sidebar.h" #include "bookmarks/editor.h" //#include "bookmarks/listview.h" #include "widgets/logview.h" #include "widgets/queueview/queueview.h" #include "widgets/queueview/threadview.h" //#include "widgets/quickconnect.h" //#include "kftpserverlineedit.h" //#include "browser/view.h" //#include "kftpzeroconflistview.h" #include "widgets/trafficgraph.h" #include "widgets/failedtransfers/view.h" #include "misc/config.h" #include "misc/filter.h" #include "misc/customcommands/manager.h" #include "mainwindow.h" #include "kftpbookmarks.h" #include "kftpqueue.h" #include "kftpsession.h" #include "kftpqueueconverter.h" #include "misc/pluginmanager.h" #include "engine/thread.h" MainWindow::MainWindow() : KXmlGuiWindow(), m_trafficGraph(0), m_configDialog(0) { connect(KApplication::kApplication(), SIGNAL(aboutToQuit()), this, SLOT(appShutdown())); // Restore size and position resize(KFTPCore::Config::size()); move(KFTPCore::Config::position()); //setCaption("KFTPGrabber"); KFTPCore::Config::self()->postInit(); // Load plugins KFTPCore::PluginManager::self()->loadPlugins(); // Load custom commands KFTPCore::CustomCommands::Manager::self()->load(); connect(KFTPQueue::Manager::self(), SIGNAL(queueUpdate()), this, SLOT(slotUpdateStatusBar())); connect(KFTPBookmarks::Manager::self(), SIGNAL(update()), this, SLOT(initBookmarkMenu())); connect(KFTPCore::Config::self(), SIGNAL(configChanged()), this, SLOT(slotConfigChanged())); // Init the gui system initTrafficGraph(); initMainView(); initStatusBar(); initBookmarkMenu(); setupActions(); // Create the systray icon new KFTPWidgets::SystemTray(this); // Create base two sessions KFTPSession::Manager::self()->spawnLocalSession(KFTPSession::LeftSide); KFTPSession::Manager::self()->spawnLocalSession(KFTPSession::RightSide); // Load bookmarks QTimer::singleShot(0, this, SLOT(slotLoader())); // Check for the uirc file if (KGlobal::dirs()->findResource("appdata", "kftpgrabberui.rc") == QString::null) { KMessageBox::error(0, i18n("Unable to find %1 XML GUI descriptor file. Please check that you have installed the application correctly. If you have any questions please ask on %2.

Warning: Current GUI will be incomplete.
", xmlFile(), "irc.freenode.net/#kftpgrabber")); } createGUI("kftpgrabberui.rc"); // Auto-save toolbar/menubar/statusbar settings setAutoSaveSettings(QString::fromLatin1("MainWindow"), false); } void MainWindow::setupActions() { // Setup file menu QAction *quickConnect = actionCollection()->addAction("quick_connect"); quickConnect->setText(i18n("&Connect...")); quickConnect->setIcon(KIcon("network-connect")); connect(quickConnect, SIGNAL(triggered()), this, SLOT(slotQuickConnect())); KActionMenu *newSession = new KActionMenu(KIcon("document-new"), i18n("&New Session"), this); actionCollection()->addAction("new_session", newSession); QAction *sessionLeft = new QAction(this); sessionLeft->setText(i18n("&Left Side")); connect(sessionLeft, SIGNAL(triggered()), this, SLOT(slotNewSessionLeft())); QAction *sessionRight = new QAction(this); sessionRight->setText(i18n("&Right Side")); connect(sessionRight, SIGNAL(triggered()), this, SLOT(slotNewSessionRight())); newSession->addAction(sessionLeft); newSession->addAction(sessionRight); newSession->setStickyMenu(true); newSession->setDelayed(false); KActionMenu *transferMode = new KActionMenu(KIcon("application-octet-stream"), i18n("&Mode (Auto)"), this); actionCollection()->addAction("transfer_mode", transferMode); QAction *asciiMode = new QAction(this); asciiMode->setText(i18n("&ASCII")); asciiMode->setIcon(KIcon("text-x-generic")); connect(asciiMode, SIGNAL(triggered()), this, SLOT(slotModeAscii())); QAction *binaryMode = new QAction(this); binaryMode->setText(i18n("&Binary")); binaryMode->setIcon(KIcon("application-octet-stream")); connect(binaryMode, SIGNAL(triggered()), this, SLOT(slotModeBinary())); QAction *autoMode = new QAction(this); autoMode->setText(i18n("A&uto")); connect(autoMode, SIGNAL(triggered()), this, SLOT(slotModeAuto())); // Set grouping so only one action can be selected QActionGroup *modeGroup = new QActionGroup(this); modeGroup->setExclusive(true); modeGroup->addAction(asciiMode); modeGroup->addAction(binaryMode); modeGroup->addAction(autoMode); // Insert the actions into the menu transferMode->addAction(asciiMode); transferMode->addAction(binaryMode); transferMode->addSeparator(); transferMode->addAction(autoMode); transferMode->setStickyMenu(true); transferMode->setDelayed(false); KStandardAction::preferences(this, SLOT(slotSettingsConfig()), actionCollection()); KStandardAction::saveOptions(this, SLOT(slotSettingsSave()), actionCollection()); KStandardAction::quit(this, SLOT(slotFileQuit()), actionCollection()); } void MainWindow::slotLoader() { // Load bookmarks and custom site commands KFTPBookmarks::Manager::self()->load(KStandardDirs::locateLocal("appdata", "bookmarks.xml")); // Load the saved queue KFTPQueue::Manager::self()->getConverter()->importQueue(KStandardDirs::locateLocal("appdata", "queue")); // Update the bookmark menu initBookmarkMenu(); } void MainWindow::appShutdown() { KFTPQueue::Manager::self()->stopAllTransfers(); KFTPSession::Manager::self()->disconnectAllSessions(); // Save the queueview layout m_queueView->saveLayout(); // Save the config data on shutdown KFTPCore::Config::setSize(size()); KFTPCore::Config::setPosition(pos()); KFTPCore::Config::self()->saveConfig(); KFTPCore::Filter::Filters::self()->close(); // Save current queue KFTPQueue::Manager::self()->getConverter()->exportQueue(KStandardDirs::locateLocal("appdata", "queue")); } bool MainWindow::queryClose() { #if 0 if(KApplication::kApplication()->sessionSaving()) { m_actions->m_closeApp = true; } if (!KFTPCore::Config::exitOnClose() && KFTPCore::Config::showSystrayIcon() && !m_actions->m_closeApp) { /* * This code was adopted from the Konversation project * copyright: (C) 2003 by Dario Abatianni, Peter Simonsson * email: eisfuchs@tigress.com, psn@linux.se */ // Compute size and position of the pixmap to be grabbed: QPoint g = KFTPWidgets::SystemTray::self()->mapToGlobal(KFTPWidgets::SystemTray::self()->pos()); int desktopWidth = kapp->desktop()->width(); int desktopHeight = kapp->desktop()->height(); int tw = KFTPWidgets::SystemTray::self()->width(); int th = KFTPWidgets::SystemTray::self()->height(); int w = desktopWidth / 4; int h = desktopHeight / 9; int x = g.x() + tw/2 - w/2; // Center the rectange in the systray icon int y = g.y() + th/2 - h/2; if ( x < 0 ) x = 0; // Move the rectangle to stay in the desktop limits if ( y < 0 ) y = 0; if ( x + w > desktopWidth ) x = desktopWidth - w; if ( y + h > desktopHeight ) y = desktopHeight - h; // Grab the desktop and draw a circle arround the icon: QPixmap shot = QPixmap::grabWindow( qt_xrootwin(), x, y, w, h ); QPainter painter( &shot ); const int MARGINS = 6; const int WIDTH = 3; int ax = g.x() - x - MARGINS -1; int ay = g.y() - y - MARGINS -1; painter.setPen( QPen( Qt::red, WIDTH ) ); painter.drawArc( ax, ay, tw + 2*MARGINS, th + 2*MARGINS, 0, 16*360 ); painter.end(); // Associate source to image and show the dialog: Q3MimeSourceFactory::defaultFactory()->setPixmap( "systray_shot", shot ); KMessageBox::information( this, i18n( "

Closing the main window will keep KFTPGrabber running in the system tray. " "Use Quit from the KFTPGrabber menu to quit the application.

" "

" ), i18n( "Docking in System Tray" ), "HideMenuBarWarning" ); hide(); return false; } if (KFTPCore::Config::confirmExit() && KFTPQueue::Manager::self()->getNumRunning() > 0) { if (KMessageBox::questionYesNo(0, i18n("There is currently a transfer running.", "There are currently %1 transfers running.", KFTPQueue::Manager::self()->getNumRunning()) + i18n("\nAre you sure you want to quit?"), i18n("Quit")) == KMessageBox::No) { return false; } } #endif // Save XML bookmarks here, because the user may be prompted for an encryption password KFTPBookmarks::Manager::self()->save(); return true; } MainWindow::~MainWindow() { } void MainWindow::initTrafficGraph() { // Setup traffic graph m_graphTimer = new QTimer(this); connect(m_graphTimer, SIGNAL(timeout()), this, SLOT(slotUpdateTrafficGraph())); m_graphTimer->start(1000); // Create and configure the traffic graph m_trafficGraph = new KFTPWidgets::TrafficGraph(0); m_trafficGraph->setObjectName("trafficgraph"); m_trafficGraph->setShowLabels(true); m_trafficGraph->addBeam(QColor(255, 0, 0)); m_trafficGraph->addBeam(QColor(0, 0, 255)); m_trafficGraph->repaint(); } void MainWindow::showBookmarkEditor() { KFTPWidgets::Bookmarks::Editor editor(this); editor.exec(); } void MainWindow::initBookmarkMenu() { QAction *editBookmarks = actionCollection()->addAction("edit_bookmarks"); editBookmarks->setText(i18n("&Edit Bookmarks...")); editBookmarks->setIcon(KIcon("bookmark-new")); connect(editBookmarks, SIGNAL(triggered()), this, SLOT(showBookmarkEditor())); unplugActionList("bookmarks_list"); plugActionList("bookmarks_list", KFTPBookmarks::Manager::self()->populateBookmarksMenu()); KActionMenu *zeroconfSites = actionCollection()->add("zeroconf_sites"); zeroconfSites->setText(i18n("&FTP Sites Near Me")); KFTPBookmarks::Manager::self()->populateZeroconfMenu(zeroconfSites); if (KFTPCore::Config::showWalletSites()) { KActionMenu *kwalletSites = actionCollection()->add("kwallet_sites"); kwalletSites->setText(i18n("Sites in K&Wallet")); kwalletSites->setIcon(KIcon("wallet-open")); KFTPBookmarks::Manager::self()->populateWalletMenu(kwalletSites); } } void MainWindow::initStatusBar() { statusBar()->insertItem(i18n("idle"), 1, 1); statusBar()->setItemAlignment(1, Qt::AlignLeft); statusBar()->insertItem(i18nc("Download traffic rate", "Down: %1/s", KIO::convertSize(KFTPQueue::Manager::self()->getDownloadSpeed())), 2); statusBar()->insertItem(i18nc("Upload traffic rate", "Up: %1/s", KIO::convertSize(KFTPQueue::Manager::self()->getUploadSpeed())), 3); } void MainWindow::initMainView() { setCentralWidget(new QWidget(this)); QHBoxLayout *mainLayout = new QHBoxLayout(centralWidget()); mainLayout->setMargin(0); mainLayout->setSpacing(0); QSplitter *splitter = new QSplitter(centralWidget()); mainLayout->addWidget(splitter); // Session layouts QWidget *leftSessions = new QWidget(splitter); QWidget *rightSessions = new QWidget(splitter); QHBoxLayout *leftLayout = new QHBoxLayout(leftSessions); QHBoxLayout *rightLayout = new QHBoxLayout(rightSessions); leftLayout->setMargin(0); leftLayout->setSpacing(0); rightLayout->setMargin(0); rightLayout->setSpacing(0); KTabWidget *leftTabs = new KTabWidget(leftSessions); KTabWidget *rightTabs = new KTabWidget(rightSessions); leftTabs->setCloseButtonEnabled(true); leftTabs->setTabBarHidden(true); rightTabs->setCloseButtonEnabled(true); rightTabs->setTabBarHidden(true); leftLayout->addWidget(leftTabs); rightLayout->addWidget(rightTabs); // Create the session manager QTabWidget *logs = new QTabWidget(0); new KFTPSession::Manager(this, logs, leftTabs, rightTabs); // Create docks setDockOptions(QMainWindow::DockOptions(AllowNestedDocks | AllowTabbedDocks | VerticalTabs | AnimatedDocks)); QDockWidget *queueDock = new QDockWidget(i18n("Queue")); queueDock->setObjectName("queue"); queueDock->setWidget(new KFTPWidgets::QueueView(queueDock)); addDockWidget(Qt::BottomDockWidgetArea, queueDock); QDockWidget *failedDock = new QDockWidget(i18n("Failed Transfers")); failedDock->setObjectName("failed_transfers"); failedDock->setWidget(new KFTPWidgets::FailedTransfers::View(failedDock)); addDockWidget(Qt::BottomDockWidgetArea, failedDock); tabifyDockWidget(queueDock, failedDock); QDockWidget *logDock = new QDockWidget(i18n("Log")); logDock->setObjectName("log"); logDock->setWidget(logs); addDockWidget(Qt::BottomDockWidgetArea, logDock); tabifyDockWidget(failedDock, logDock); QDockWidget *graphDock = new QDockWidget(i18n("Traffic")); graphDock->setObjectName("traffic"); graphDock->setWidget(m_trafficGraph); addDockWidget(Qt::BottomDockWidgetArea, graphDock); tabifyDockWidget(logDock, graphDock); } void MainWindow::slotUpdateStatusBar() { // Status bar statusBar()->changeItem(i18nc("Download traffic rate", "Down: %1/s", KIO::convertSize(KFTPQueue::Manager::self()->getDownloadSpeed())), 2); statusBar()->changeItem(i18nc("Upload traffic rate", "Up: %1/s", KIO::convertSize(KFTPQueue::Manager::self()->getUploadSpeed())), 3); } void MainWindow::slotUpdateTrafficGraph() { // Update the traffic graph if (m_trafficGraph) { QList trafficList; trafficList.append((double) KFTPQueue::Manager::self()->getDownloadSpeed() / 1024); trafficList.append((double) KFTPQueue::Manager::self()->getUploadSpeed() / 1024); m_trafficGraph->addSample(trafficList); } } void MainWindow::slotQuickConnect() { KFTPWidgets::Bookmarks::Editor editor(this, true); if (editor.exec()) KFTPBookmarks::Manager::self()->connectWithSite(editor.selectedSite()); } void MainWindow::slotConfigChanged() { } void MainWindow::slotModeAscii() { QAction *transferMode = actionCollection()->action("transfer_mode"); transferMode->setIcon(KIcon("text-x-generic")); transferMode->setText(i18n("&Mode (ASCII)")); KFTPCore::Config::self()->setGlobalMode('A'); } void MainWindow::slotModeBinary() { QAction *transferMode = actionCollection()->action("transfer_mode"); transferMode->setIcon(KIcon("application-octet-stream")); transferMode->setText(i18n("&Mode (Binary)")); KFTPCore::Config::self()->setGlobalMode('I'); } void MainWindow::slotModeAuto() { QAction *transferMode = actionCollection()->action("transfer_mode"); transferMode->setText(i18n("&Mode (Auto)")); transferMode->setIcon(KIcon("application-octet-stream")); KFTPCore::Config::self()->setGlobalMode('X'); } void MainWindow::slotFileQuit() { //m_closeApp = true; close(); } void MainWindow::slotSettingsSave() { KFTPCore::Config::self()->saveConfig(); } void MainWindow::slotSettingsConfig() { if (!m_configDialog) m_configDialog = new KFTPWidgets::ConfigDialog(this); m_configDialog->prepareDialog(); m_configDialog->exec(); } void MainWindow::slotNewSessionLeft() { KFTPSession::Manager::self()->spawnLocalSession(KFTPSession::LeftSide, true); } void MainWindow::slotNewSessionRight() { KFTPSession::Manager::self()->spawnLocalSession(KFTPSession::RightSide, true); } #include "mainwindow.moc" kftpgrabber-0.8.99~svn1214766/src/kftpgrabber.desktop0000644000175000017500000001002511556266156022066 0ustar michaelmichael[Desktop Entry] Name=KFTPGrabber Name[be]=KFTPGrabber Name[bg]=KFTPGrabber Name[cs]=KFTPGrabber Name[da]=KFTPGrabber Name[de]=KFTPGrabber Name[el]=KFTPGrabber Name[en_GB]=KFTPGrabber Name[es]=KFTPGrabber Name[et]=KFTPGrabber Name[fi]=KFTPGrabber Name[fr]=KFTPGrabber Name[ga]=KFTPGrabber Name[gl]=KFTPGrabber Name[hne]=केएफटीपीग्रेबर Name[hr]=KFTPGrabber Name[hu]=KFTPGrabber Name[is]=KFTPGrabber Name[it]=KFTPGrabber Name[ja]=KFTPGrabber Name[km]=KFTPGrabber Name[lt]=KFTPGrabber Name[lv]=KFTPGrabber Name[nb]=KFTPGrabber Name[nds]=KFTPGrabber Name[nl]=KFTPGrabber Name[pa]=KFTP-ਗਰੱਬਰ Name[pl]=KFTPGrabber Name[pt]=KFTPGrabber Name[pt_BR]=KFTPGrabber Name[ro]=KFTPGrabber Name[ru]=KFTPGrabber Name[sv]=KFTPgrabber Name[th]=โปรแกรมรับ-ส่งข้อมูล KFTPGrabber Name[tr]=KFTPGrabber Name[uk]=KFTPGrabber Name[x-test]=xxKFTPGrabberxx Name[zh_CN]=KFTPGrabber Name[zh_TW]=KFTPGrabber GenericName=FTP Client GenericName[be]=Кліент FTP GenericName[bg]=FTP клиент GenericName[cs]=FTP klient GenericName[da]=FTP-klient GenericName[de]=FTP-Programm GenericName[el]=Πελάτης FTP GenericName[en_GB]=FTP Client GenericName[eo]=FTP-kliento GenericName[es]=Cliente de FTP GenericName[et]=FTP-klient GenericName[fi]=FTP-asiakas GenericName[fr]=Client FTP GenericName[ga]=Cliant FTP GenericName[gl]=Cliente FTP GenericName[hi]=एफटीपी क्लाएंट GenericName[hne]=एफटीपी क्लायंट GenericName[hu]=FTP-kliens GenericName[is]=FTP forrit GenericName[it]=Client FTP GenericName[ja]=FTP クライアント GenericName[km]=ម៉ាស៊ីន​ភ្ញៀវ FTP GenericName[lt]=FTP klientas GenericName[lv]=FTP klients GenericName[nb]=FTP-klient GenericName[nds]=FTP-Client GenericName[nl]=FTP-cliënt GenericName[oc]=Client FTP GenericName[pa]=FTP ਕਲਾਇਟ GenericName[pl]=Klient FTP GenericName[pt]=Cliente de FTP GenericName[pt_BR]=Cliente de FTP GenericName[ro]=Client FTP GenericName[ru]=FTP клиент GenericName[sv]=FTP-klient GenericName[th]=โปรแกรมรับ-ส่งข้อมูล ผ่านโพรโตคอล FTP GenericName[tr]=FTP İstemcisi GenericName[uk]=Клієнт FTP GenericName[x-test]=xxFTP Clientxx GenericName[zh_CN]=FTP 客户端 GenericName[zh_TW]=FTP 客戶端程式 Comment=A graphical FTP client Comment[bg]=Графичен FTP клиент Comment[cs]=Grafický FTP klient Comment[da]=En grafisk FTP-klient Comment[de]=Grafisches FTP-Programm Comment[el]=Ένας γραφικός πελάτης FTP Comment[en_GB]=A graphical FTP client Comment[es]=Un cliente gráfico de FTP Comment[et]=Graafiline FTP-klient Comment[fi]=Graafinen FTP-asiakas Comment[fr]=Un client FTP graphique Comment[ga]=Cliant grafach FTP Comment[gl]=Un cliente gráfico de FTP Comment[hne]=ग्राफिकल एफटीपी क्लायंट Comment[hu]=Egy grafikus FTP-kliens Comment[is]=Grafískur FTP biðlari Comment[it]=Un client FTP grafico Comment[ja]=グラフィカルな FTP クライアント Comment[km]=ម៉ាស៊ីន​ភ្ញៀវ FTP មាន​លក្ខណៈ​ក្រាហ្វិក Comment[lt]=Grafinis FTP klientas Comment[lv]=Grafisks FTP klients Comment[nb]=En grafisk FTP-klient Comment[nds]=En graafsch FTP-Client Comment[nl]=Een grafische FTP-cliënt Comment[pa]=ਇੱਕ ਗਰਾਫਿਕਲ FTP ਕਲਾਇਟ Comment[pl]=Graficzny klient FTP Comment[pt]=Um cliente gráfico de FTP Comment[pt_BR]=Um cliente gráfico de FTP Comment[ro]=Un client FTP grafic Comment[ru]=Графические FTP клиент Comment[sv]=En grafisk FTP-klient Comment[th]=โปรแกรมรับ-ส่งข้อมูล ผ่านโพรโตคอล FTP แบบกราฟิก Comment[tr]=Grafiksel FTP İstemcisi Comment[uk]=Графічний клієнт FTP Comment[x-test]=xxA graphical FTP clientxx Comment[zh_CN]=一个图形化的 FTP 客户端 Comment[zh_TW]=圖形 FTP 客戶端程式 Exec=kftpgrabber Icon=kftpgrabber Type=Application Categories=Qt;KDE;Network;FileTransfer; kftpgrabber-0.8.99~svn1214766/src/kftpqueueprocessor.cpp0000644000175000017500000000763011276037142022655 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftpqueueprocessor.h" #include "kftpqueue.h" #include "kftpsession.h" //Added by qt3to4: KFTPQueueProcessor::KFTPQueueProcessor(QObject *parent) : QObject(parent) { m_running = false; } bool KFTPQueueProcessor::isRunning() { return m_running; } void KFTPQueueProcessor::processActiveSite() { if (!m_activeSite) return; // Start the transfer m_activeSite->delayedExecute(); } bool KFTPQueueProcessor::nextSite() { // Select the first server (should be next) if there is none, we are done :) //KFTPQueueTransfers *transfers = FTPQueueManager->getQueueTransferList(); QList sites = KFTPQueue::Manager::self()->topLevelObject()->getChildrenList(); if (sites.count() > 0 && m_running) { if (m_activeSite && m_activeSite->getId() == sites.at(0)->getId()) { // Because this function can be called from slotSiteComplete and signal gets // emitted *before* site is removed we should use the second site on the list m_activeSite = static_cast(sites.at(1)); } else { m_activeSite = static_cast(sites.at(0)); } } else { m_activeSite = 0L; } if (m_activeSite) { // Connect the signals connect(m_activeSite, SIGNAL(destroyed(QObject*)), this, SLOT(slotSiteComplete())); connect(m_activeSite, SIGNAL(siteAborted()), this, SLOT(slotSiteAborted())); return true; } else { // We are done, so we emit the proper signal m_running = false; emit queueComplete(); return false; } return false; } void KFTPQueueProcessor::startProcessing() { m_running = true; // Select the site and process it if (nextSite()) processActiveSite(); } void KFTPQueueProcessor::stopProcessing() { // Stop the queue processing m_running = false; // Abort current transfer if (m_activeSite) { // Disconnect signals m_activeSite->QObject::disconnect(this); m_activeSite->abort(); } m_activeSite = 0L; emit queueAborted(); } void KFTPQueueProcessor::slotSiteComplete() { // Transfer is complete, move to the next if (nextSite()) processActiveSite(); } void KFTPQueueProcessor::slotSiteAborted() { // Transfer has aborted, we should stop stopProcessing(); } #include "kftpqueueprocessor.moc" kftpgrabber-0.8.99~svn1214766/src/queueobject.cpp0000644000175000017500000001566711276037142021230 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "queueobject.h" #include "kftpqueue.h" #include namespace KFTPQueue { QueueObject::QueueObject(QObject *parent, Type type) : QObject(parent), m_aborting(false), m_status(Unknown), m_type(type), m_size(0), m_actualSize(0), m_completed(0), m_resumed(0), m_speed(0) { // Add the transfer if (hasParentObject()) static_cast(parent)->addChildObject(this); // Connect the delayed execution timer connect(&m_delayedExecuteTimer, SIGNAL(timeout()), this, SLOT(execute())); } QueueObject::~QueueObject() { } int QueueObject::index() const { if (m_type == Toplevel) return 0; QList children = parentObject()->getChildrenList(); for (int i = 0; i < children.size(); i++) { if (children.at(i) == this) return i; } Q_ASSERT(false); return -1; } void QueueObject::readyObject() { m_status = Stopped; } void QueueObject::delayedExecute(int msec) { /* Execute the transfer with delay - using a QTimer */ if (msec > 1000) msec = 1000; if (!m_delayedExecuteTimer.isActive()) { m_delayedExecuteTimer.setSingleShot(true); m_delayedExecuteTimer.start(msec); } } void QueueObject::execute() { } QPair QueueObject::getProgress() const { int progress = 0; int resumed = 0; if (m_size) progress = m_completed * 100 / m_size; if (m_resumed) resumed = m_resumed * 100 / m_size; return QPair(progress, resumed); } void QueueObject::addActualSize(filesize_t size) { if (size == 0) return; m_actualSize += size; if (hasParentObject()) parentObject()->addActualSize(size); statisticsUpdated(); } void QueueObject::addSize(filesize_t size) { if (size == 0) return; m_size += size; m_actualSize += size; if (hasParentObject()) parentObject()->addSize(size); statisticsUpdated(); } void QueueObject::addCompleted(filesize_t completed) { if (completed == 0) return; m_completed += completed; if (hasParentObject()) parentObject()->addCompleted(completed); statisticsUpdated(); } void QueueObject::setSpeed(filesize_t speed) { if (speed != 0 && m_speed == speed) return; m_speed = speed; foreach (QueueObject *i, m_children) { m_speed += i->getSpeed(); } if (hasParentObject()) parentObject()->setSpeed(); statisticsUpdated(); } void QueueObject::statisticsUpdated() { if (m_status == Unknown) return; emit objectUpdated(); emit KFTPQueue::Manager::self()->objectChanged(this); } void QueueObject::abort() { } void QueueObject::addChildObject(QueueObject *object) { m_children.append(object); connect(object, SIGNAL(destroyed(QObject*)), this, SLOT(slotChildDestroyed(QObject*))); } void QueueObject::delChildObject(QueueObject *object) { m_children.removeAll(object); } void QueueObject::slotChildDestroyed(QObject *child) { // Remove the transfer delChildObject(static_cast(child)); } QueueObject *QueueObject::findChildObject(long id) { foreach (QueueObject *i, m_children) { if (i->getId() == id) return i; if (i->hasChildren()) { QueueObject *tmp = i->findChildObject(id); if (tmp) return tmp; } } return NULL; } void QueueObject::removeMarkedTransfers() { foreach (QueueObject *i, m_children) { if (i->hasChildren()) i->removeMarkedTransfers(); if (i->isTransfer() && static_cast(i)->isDeleteMarked()) Manager::self()->removeTransfer(static_cast(i)); } } bool QueueObject::canMove() { return true; } void QueueObject::moveChildUp(QueueObject *child) { int pos = m_children.indexOf(child); if (pos != -1) { emit KFTPQueue::Manager::self()->objectRemoved(child); m_children.removeAll(child); m_children.insert(pos - 1, child); emit KFTPQueue::Manager::self()->objectAdded(child); } } void QueueObject::moveChildDown(QueueObject *child) { int pos = m_children.indexOf(child); if (pos != -1) { emit KFTPQueue::Manager::self()->objectRemoved(child); m_children.removeAll(child); m_children.insert(pos + 1, child); emit KFTPQueue::Manager::self()->objectAdded(child); } } void QueueObject::moveChildTop(QueueObject *child) { emit KFTPQueue::Manager::self()->objectRemoved(child); m_children.removeAll(child); m_children.prepend(child); emit KFTPQueue::Manager::self()->objectAdded(child); } void QueueObject::moveChildBottom(QueueObject *child) { emit KFTPQueue::Manager::self()->objectRemoved(child); m_children.removeAll(child); m_children.append(child); emit KFTPQueue::Manager::self()->objectAdded(child); } bool QueueObject::canMoveChildUp(QueueObject *child) { if (!child->canMove()) return false; if (m_children.first() == child) return false; QueueObject *upper = m_children.value(m_children.indexOf(child) - 1); if (upper && !upper->canMove()) return false; return true; } bool QueueObject::canMoveChildDown(QueueObject *child) { if (!child->canMove()) return false; if (m_children.last() == child) return false; QueueObject *lower = m_children.value(m_children.indexOf(child) - 1); if (lower && !lower->canMove()) return false; return true; } } #include "queueobject.moc" kftpgrabber-0.8.99~svn1214766/src/kftpsession.cpp0000644000175000017500000006740011276037142021255 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftpsession.h" #include "browser/detailsview.h" #include "browser/view.h" #include "kftpbookmarks.h" #include "widgets/systemtray.h" #include "widgets/sslerrorsdialog.h" #include "widgets/fingerprintverifydialog.h" #include "misc/config.h" #include "misc/filter.h" #include #include #include #include #include using namespace KFTPEngine; using namespace KFTPCore::Filter; using namespace KFTPWidgets; namespace KFTPSession { ////////////////////////////////////////////////////////////////// //////////////////////// Connection /////////////////////// ////////////////////////////////////////////////////////////////// Connection::Connection(Session *session, bool primary) : QObject(session), m_primary(primary), m_busy(false), m_aborting(false), m_scanning(false) { // Create the actual connection client m_client = new KFTPEngine::Thread(); connect(m_client->eventHandler(), SIGNAL(engineEvent(KFTPEngine::Event*)), this, SLOT(slotEngineEvent(KFTPEngine::Event*))); // If this is not a core session connection, connect if (!primary) { // Connect to the server KUrl url = session->getClient()->socket()->getCurrentUrl(); KFTPBookmarks::Manager::self()->setupClient(session->getSite(), m_client, session->getClient()); m_client->connect(url); } } Connection::~Connection() { m_client->shutdown(); } bool Connection::isConnected() { return !static_cast(parent())->isRemote() || m_client->socket()->isConnected(); } void Connection::acquire(KFTPQueue::Transfer *transfer) { if (m_busy || !static_cast(parent())->isRemote()) return; m_transfer = transfer; m_busy = true; connect(transfer, SIGNAL(transferComplete(long)), this, SLOT(slotTransferCompleted())); connect(transfer, SIGNAL(transferAbort(long)), this, SLOT(slotTransferCompleted())); emit connectionAcquired(); } void Connection::release() { // Disconnect all signals from the transfer if (m_transfer) m_transfer->QObject::disconnect(this); m_transfer = 0L; m_busy = false; emit connectionRemoved(); emit static_cast(parent())->freeConnectionAvailable(); } void Connection::abort() { if (m_scanning) { // Abort scanning m_scanning = false; m_transfer->unlock(); release(); } if (m_aborting || !m_client->socket()->isBusy()) return; // Emit the signal before aborting emit aborting(); // Abort transfer m_aborting = true; m_client->abort(); m_aborting = false; } bool Connection::isBusy() const { return m_busy || m_client->socket()->isBusy(); } void Connection::scanDirectory(KFTPQueue::Transfer *parent) { // Lock the connection and the transfer acquire(parent); parent->lock(); m_scanning = true; if (isConnected()) m_client->scan(parent->getSourceUrl()); } void Connection::addScannedDirectory(KFTPEngine::DirectoryTree *tree, KFTPQueue::Transfer *parent) { if (!m_scanning) return; // Directories DirectoryTree::DirIterator dirEnd = tree->directories()->constEnd(); for (DirectoryTree::DirIterator i = tree->directories()->constBegin(); i != dirEnd; i++) { if (!m_scanning) return; KUrl sourceUrlBase = parent->getSourceUrl(); KUrl destUrlBase = parent->getDestUrl(); sourceUrlBase.addPath((*i)->info().filename()); destUrlBase.addPath((*i)->info().filename()); // Check if we should skip this entry const ActionChain *actionChain = Filters::self()->process(sourceUrlBase, 0, true); if (actionChain && actionChain->getAction(Action::Skip)) continue; // Add directory transfer KFTPQueue::TransferDir *transfer = new KFTPQueue::TransferDir(parent); transfer->setSourceUrl(sourceUrlBase); transfer->setDestUrl(destUrlBase); transfer->setTransferType(parent->getTransferType()); transfer->setId(KFTPQueue::Manager::self()->nextTransferId()); emit KFTPQueue::Manager::self()->objectAdded(transfer); transfer->readyObject(); QCoreApplication::processEvents(QEventLoop::AllEvents, 100); addScannedDirectory(*i, transfer); if (KFTPCore::Config::skipEmptyDirs() && !transfer->hasChildren()) KFTPQueue::Manager::self()->removeTransfer(transfer, false); } // Files DirectoryTree::FileIterator fileEnd = tree->files()->constEnd(); for (DirectoryTree::FileIterator i = tree->files()->constBegin(); i != fileEnd; i++) { if (!m_scanning) return; KUrl sourceUrlBase = parent->getSourceUrl(); KUrl destUrlBase = parent->getDestUrl(); sourceUrlBase.addPath((*i).filename()); destUrlBase.addPath((*i).filename()); // Check if we should skip this entry const ActionChain *actionChain = Filters::self()->process(sourceUrlBase, (*i).size(), false); if (actionChain && actionChain->getAction(Action::Skip)) continue; // Add file transfer KFTPQueue::TransferFile *transfer = new KFTPQueue::TransferFile(parent); transfer->addSize((*i).size()); transfer->setSourceUrl(sourceUrlBase); transfer->setDestUrl(destUrlBase); transfer->setTransferType(parent->getTransferType()); transfer->setId(KFTPQueue::Manager::self()->nextTransferId()); emit KFTPQueue::Manager::self()->objectAdded(transfer); transfer->readyObject(); QCoreApplication::processEvents(QEventLoop::AllEvents, 100); } } void Connection::slotEngineEvent(KFTPEngine::Event *event) { switch (event->type()) { case Event::EventDisconnect: { emit connectionLost(this); break; } case Event::EventConnect: { emit connectionEstablished(); if (m_scanning) { // Connected successfully, let's scan m_client->scan(m_transfer->getSourceUrl()); } break; } case Event::EventError: { ErrorCode error = static_cast(event->getParameter(0).toInt()); if (m_scanning && (error == ConnectFailed || error == LoginFailed || error == OperationFailed)) { // Scanning should be aborted, since there was an error m_scanning = false; m_transfer->unlock(); release(); emit static_cast(parent())->dirScanDone(); } break; } case Event::EventScanComplete: { if (m_scanning) { // We have the listing DirectoryTree *tree = event->getParameter(0).value(); addScannedDirectory(tree, m_transfer); delete tree; m_scanning = false; m_transfer->unlock(); release(); emit static_cast(parent())->dirScanDone(); } break; } case Event::EventReady: { if (!m_busy) { emit static_cast(parent())->freeConnectionAvailable(); } break; } default: break; } } void Connection::slotTransferCompleted() { // Remove the lock release(); } void Connection::reconnect() { if (!m_client->socket()->isConnected()) { KFTPBookmarks::Manager::self()->setupClient(static_cast(parent())->getSite(), m_client); m_client->connect(m_client->socket()->getCurrentUrl()); } } //////////////////////////////////////////////////////// //////////////////// Session //////////////////// //////////////////////////////////////////////////////// Session::Session(Side side) : QObject(), m_side(side), m_remote(false), m_aborting(false), m_registred(false), m_site(0) { // Register this session Manager::self()->registerSession(this); } Session::~Session() { } Session *Session::oppositeSession() const { return Manager::self()->getActive(oppositeSide(m_side)); } KFTPEngine::Thread *Session::getClient() { // Return the first (core) connection's client return m_connections.at(0)->getClient(); } bool Session::isConnected() { // If there are no connections, just check if the session is remote if (m_connections.count() == 0) return !m_remote; return m_connections.at(0)->isConnected(); } void Session::slotClientEngineEvent(KFTPEngine::Event *event) { switch (event->type()) { case Event::EventConnect: { // *************************************************************************** // ****************************** EventConnect ******************************* // *************************************************************************** m_remote = true; m_aborting = false; m_lastUrl = getClient()->socket()->getCurrentUrl(); QString siteName; if (m_site) siteName = m_site->getAttribute("name"); else siteName = m_lastUrl.host(); Manager::self()->getTabs(m_side)->setTabText(Manager::self()->getTabs(m_side)->indexOf(m_fileView), siteName); Manager::self()->getStatTabs()->setTabText(Manager::self()->getStatTabs()->indexOf(m_log), i18n("Log (%1)",siteName)); Manager::self()->getStatTabs()->setCurrentIndex(Manager::self()->getStatTabs()->indexOf(m_log)); Manager::self()->doEmitUpdate(); KUrl homeUrl = getClient()->socket()->getCurrentUrl(); if (m_site && !m_site->getProperty("pathRemote").isEmpty()) homeUrl.setPath(m_site->getProperty("pathRemote")); else homeUrl.setPath(getClient()->socket()->getDefaultDirectory()); m_fileView->setHomeUrl(homeUrl); m_fileView->goHome(); Session *opposite = Manager::self()->getActive(oppositeSide(m_side)); if (m_site && !opposite->isRemote()) { QString localPath = m_site->getProperty("pathLocal"); if (!localPath.isEmpty()) opposite->getFileView()->openUrl(KUrl(localPath)); } break; } case Event::EventDisconnect: { // *************************************************************************** // **************************** EventDisconnect ****************************** // *************************************************************************** m_remote = false; m_aborting = false; Manager::self()->getTabs(m_side)->setTabText(Manager::self()->getTabs(m_side)->indexOf(m_fileView), i18n("Local Session")); Manager::self()->getStatTabs()->setTabText(Manager::self()->getStatTabs()->indexOf(m_log), "[" + i18n("Not Connected") + "]"); Manager::self()->doEmitUpdate(); m_fileView->setHomeUrl(KUrl(KFTPCore::Config::defLocalDir())); m_fileView->goHome(); break; } case Event::EventCommand: m_log->append(event->getParameter(0).toString(), LogView::FtpCommand); break; case Event::EventMultiline: m_log->append(event->getParameter(0).toString(), LogView::FtpMultiline); break; case Event::EventResponse: m_log->append(event->getParameter(0).toString(), LogView::FtpResponse); break; case Event::EventMessage: m_log->append(event->getParameter(0).toString(), LogView::FtpStatus); break; case Event::EventError: { // *************************************************************************** // ****************************** EventError ********************************* // *************************************************************************** ErrorCode error = static_cast(event->getParameter(0).toInt()); QString details = event->getParameter(1).toString(); if (error != ConnectFailed && error != LoginFailed) return; KMessageBox::detailedError(0, i18n("Unable to establish a connection with the remote server."), details); break; } case Event::EventRetrySuccess: { // *************************************************************************** // ************************** EventRetrySuccess ****************************** // *************************************************************************** if (KFTPCore::Config::showRetrySuccessBalloon()) { KFTPWidgets::SystemTray::self()->showMessage(i18n("Information"), i18n("Connection with %1 has been successfully established.", getClient()->socket()->getCurrentUrl().host())); } break; } case Event::EventReloadNeeded: { // We should only do refreshes if the queue is not being processed if (KFTPQueue::Manager::self()->getNumRunning() == 0) m_fileView->reload(); break; } case Event::EventPubkeyPassword: { // A public-key authentication password was requested KPasswordDialog dialog; dialog.setPrompt(i18n("Please provide your private key decryption password.")); if (dialog.exec()) { PubkeyWakeupEvent *response = new PubkeyWakeupEvent(); response->password = dialog.password(); getClient()->wakeup(response); } else { getClient()->abort(); } break; } case Event::EventPeerVerify: { // Peer requires verification QString protocol = getUrl().protocol(); PeerVerifyWakeupEvent *response = new PeerVerifyWakeupEvent(); if (protocol == "ftp") { SslErrorsDialog dialog; dialog.setErrors(event->getParameter(0).toList()); response->peerOk = (bool) dialog.exec(); } else if (protocol == "sftp") { FingerprintVerifyDialog dialog; dialog.setFingerprint(event->getParameter(0).toByteArray(), getUrl()); response->peerOk = (bool) dialog.exec(); } getClient()->wakeup(response); break; } default: break; } } void Session::scanDirectory(KFTPQueue::Transfer *parent, Connection *connection) { // Go trough all files in path and add them as transfers that have parent as their parent // transfer KUrl path = parent->getSourceUrl(); if (path.isLocalFile()) { connect(new DirectoryScanner(parent), SIGNAL(completed()), this, SIGNAL(dirScanDone())); } else if (m_remote) { if (!connection) { if (!isFreeConnection()) { emit dirScanDone(); return; } // Assign a new connection (it might be unconnected!) connection = assignConnection(); } connection->scanDirectory(parent); } } void Session::abort() { if (m_aborting) return; m_aborting = true; emit aborting(); // Abort all connections foreach (Connection *c, m_connections) { c->abort(); } m_aborting = false; } void Session::reconnect(const KUrl &url) { // Set the reconnect url m_reconnectUrl = url; if (m_remote && getClient()->socket()->isConnected()) { abort(); connect(getClient()->eventHandler(), SIGNAL(disconnected()), this, SLOT(slotStartReconnect())); getClient()->disconnect(); } else { // The session is already disconnected, just call the slot slotStartReconnect(); } } void Session::slotStartReconnect() { disconnect(getClient()->eventHandler(), SIGNAL(disconnected()), this, SLOT(slotStartReconnect())); // Reconnect only if this is a remote url if (!m_reconnectUrl.isLocalFile()) { KFTPBookmarks::Manager::self()->setupClient(m_site, getClient()); getClient()->connect(m_reconnectUrl); } // Invalidate the url m_reconnectUrl = KUrl(); } int Session::getMaxThreadCount() { // First get the global thread count int count = KFTPCore::Config::threadCount(); if (!KFTPCore::Config::threadUsePrimary()) count++; // Try to see if threads are disabled for this site if (count > 1 && isRemote()) { if (m_site && m_site->getIntProperty("disableThreads")) return 1; } return count; } bool Session::isFreeConnection() { int max = getMaxThreadCount(); int free = 0; if ((m_connections.count() < max && max > 1) || !isRemote()) return true; foreach (Connection *c, m_connections) { if (!c->isBusy() && (!c->isPrimary() || KFTPCore::Config::threadUsePrimary() || max == 1)) free++; } return free > 0; } Connection *Session::assignConnection() { int max = getMaxThreadCount(); if (m_connections.count() == 0) { // We need a new core connection Connection *c = new Connection(this, true); m_connections.append(c); Manager::self()->doEmitUpdate(); return c; } else { // Find a free connection foreach (Connection *c, m_connections) { if (!c->isBusy() && (!c->isPrimary() || KFTPCore::Config::threadUsePrimary() || max == 1)) return c; } // No free connection has been found, but we may be able to create // another (if we are within limits) if (m_connections.count() < max) { Connection *c = new Connection(this); m_connections.append(c); Manager::self()->doEmitUpdate(); return c; } } return 0; } void Session::disconnectAllConnections() { // Abort any possible transfers first abort(); // Now disconnect all connections foreach (Connection *c, m_connections) { if (c->getClient()->socket()->isConnected()) { c->getClient()->disconnect(); } } } //////////////////////////////////////////////////////// /////////////////////// Manager //////////////////////// //////////////////////////////////////////////////////// Manager *Manager::m_self = 0; Manager *Manager::self() { return m_self; } Manager::Manager(QObject *parent, QTabWidget *stat, KTabWidget *left, KTabWidget *right) : QObject(parent), m_statTabs(stat), m_leftTabs(left), m_rightTabs(right), m_active(0), m_leftActive(0), m_rightActive(0) { Manager::m_self = this; // Connect some signals connect(left, SIGNAL(currentChanged(QWidget*)), this, SLOT(slotActiveChanged(QWidget*))); connect(right, SIGNAL(currentChanged(QWidget*)), this, SLOT(slotActiveChanged(QWidget*))); connect(left, SIGNAL(closeRequest(QWidget*)), this, SLOT(slotSessionCloseRequest(QWidget*))); connect(right, SIGNAL(closeRequest(QWidget*)), this, SLOT(slotSessionCloseRequest(QWidget*))); } void Manager::registerSession(Session *session) { m_active = session; // Create some new stuff and assign it to the session session->assignConnection(); session->m_fileView = new KFTPWidgets::Browser::View(0, session->getClient(), session); session->m_log = new KFTPWidgets::LogView(m_statTabs); // Setup default home URL session->m_fileView->setHomeUrl(KUrl(KFTPCore::Config::defLocalDir())); // Install event filters /* session->getFileView()->getDetailsView()->installEventFilter(this); session->getFileView()->getTreeView()->installEventFilter(this); session->getFileView()->m_toolBarFirst->installEventFilter(this); session->getFileView()->m_toolBarSecond->installEventFilter(this); connect(session->getFileView()->getDetailsView(), SIGNAL(clicked(Q3ListViewItem*)), this, SLOT(slotSwitchFocus())); connect(session->getFileView()->getTreeView(), SIGNAL(clicked(Q3ListViewItem*)), this, SLOT(slotSwitchFocus())); connect(session->getFileView()->m_toolBarFirst, SIGNAL(clicked(int)), this, SLOT(slotSwitchFocus())); connect(session->getFileView()->m_toolBarSecond, SIGNAL(clicked(int)), this, SLOT(slotSwitchFocus())); */ // Connect some signals connect(session->getClient()->eventHandler(), SIGNAL(engineEvent(KFTPEngine::Event*)), session, SLOT(slotClientEngineEvent(KFTPEngine::Event*))); // Assign GUI positions KTabWidget *tabs = getTabs(session->getSide()); m_statTabs->addTab(session->m_log, "[" + i18n("Not Connected") + "]"); tabs->addTab(session->m_fileView, KIcon("system"), i18n("Session")); // Actually add the session m_sessionList.append(session); session->m_registred = true; if (tabs->count() > 1) tabs->setTabBarHidden(false); } KFTPWidgets::Browser::View *Manager::getActiveView() { if (m_active) return m_active->getFileView(); return 0; } Session *Manager::getActiveSession() { return m_active; } bool Manager::eventFilter(QObject *object, QEvent *event) { if (event->type() == QEvent::FocusIn || event->type() == QEvent::MouseButtonPress) { switchFocusToObject(object); } return false; } void Manager::slotSwitchFocus() { switchFocusToObject(QObject::sender()); } void Manager::switchFocusToObject(const QObject *object) { if (!object) return; for (;;) { if (object->inherits("KFTPWidgets::Browser::View")) break; if (!(object = object->parent())) break; } if (object) { // We have the proper object Session *session = find(static_cast(object)); if (session && session != m_active) { m_active = session; // Open the current session's log tab if (session->isRemote()) m_statTabs->setCurrentIndex(m_statTabs->indexOf(session->getLog())); } } } void Manager::unregisterSession(Session *session) { KTabWidget *tabs = getTabs(session->getSide()); if (tabs->count() == 2) tabs->setTabBarHidden(true); // Destroy all objects related to the session and remove it tabs->removePage(session->m_fileView); m_statTabs->removeTab(m_statTabs->indexOf(session->m_log)); if (session->getClient()->socket()->isConnected()) { session->abort(); session->getClient()->disconnect(); } // Delete objects session->m_fileView->deleteLater(); session->m_log->deleteLater(); // Actually remove the session m_sessionList.removeAll(session); delete session; emit update(); } void Manager::doEmitUpdate() { emit update(); } void Manager::disconnectAllSessions() { foreach (Session *s, m_sessionList) { s->disconnectAllConnections(); } } Session *Manager::find(KFTPEngine::Thread *client) { foreach (Session *s, m_sessionList) { if (s->getClient() == client) return s; } return 0; } Session *Manager::find(KFTPWidgets::Browser::View *fileView) { foreach (Session *s, m_sessionList) { if (s->m_fileView == fileView) return s; } return 0; } Session *Manager::find(KFTPWidgets::LogView *log) { foreach (Session *s, m_sessionList) { if (s->m_log == log) return s; } return 0L; } Session *Manager::find(const KUrl &url, bool mustUnlock) { if (url.isLocalFile()) return find(true); foreach (Session *s, m_sessionList) { KUrl tmp = s->getClient()->socket()->getCurrentUrl(); tmp.setPath(url.path()); if (tmp == url && s->isRemote() && s->isConnected() && (!mustUnlock || s->isFreeConnection())) return s; } return 0; } Session *Manager::find(bool local) { foreach (Session *s, m_sessionList) { if (s->m_remote != local) return s; } return 0; } Session *Manager::findLast(const KUrl &url, Side side) { if (url.isLocalFile()) return find(true); foreach (Session *s, m_sessionList) { KUrl tmp = s->m_lastUrl; tmp.setPath(url.path()); if (tmp == url && !s->isRemote() && (s->getSide() || side == IgnoreSide)) return s; } return 0; } Session *Manager::spawnLocalSession(Side side, bool forceNew) { // Creates a new local session Session *session = 0; if (forceNew || (session = find(true)) == 0 || (session->m_side != side && side != IgnoreSide)) { side = side == IgnoreSide ? LeftSide : side; session = new Session(side); session->m_remote = false; getTabs(side)->setTabText(getTabs(side)->indexOf(session->m_fileView), i18n("Local Session")); getStatTabs()->setTabText(getStatTabs()->indexOf(session->m_log), "[" + i18n("Not Connected") + "]"); } setActive(session); return session; } Session *Manager::spawnRemoteSession(Side side, const KUrl &remoteUrl, KFTPBookmarks::Site *site, bool mustUnlock) { // Creates a new remote session and connects it to the correct server Session *session; if (remoteUrl.isLocalFile()) return spawnLocalSession(side); if ((session = find(remoteUrl, mustUnlock)) == 0L || (session->m_side != side && side != IgnoreSide)) { // Try to find the session that was last connected to this URL if ((session = findLast(remoteUrl, side)) == 0L) { // Attempt to reuse a local session if one exists one the right side session = getActive(RightSide); if (session->isRemote()) { side = side == IgnoreSide ? RightSide : side; session = new Session(side); } } // Try to find the site by url if it is not set if (!site) site = KFTPBookmarks::Manager::self()->findSite(remoteUrl); // Set properties session->m_remote = true; session->m_site = site; m_active = session; KFTPBookmarks::Manager::self()->setupClient(site, session->getClient()); session->getClient()->connect(remoteUrl); } return session; } void Manager::setActive(Session *session) { if (!session) return; // Make a session active on its own side Session *oldActive = getActive(session->m_side); if (oldActive) oldActive->m_active = false; session->m_active = true; switch (session->m_side) { case LeftSide: m_leftActive = session; break; case RightSide: m_rightActive = session; break; case IgnoreSide: qDebug("Invalid side specified!"); return; } // Refresh the GUI getTabs(session->m_side)->setCurrentIndex(getTabs(session->m_side)->indexOf(session->m_fileView)); } Session *Manager::getActive(Side side) { switch (side) { case LeftSide: return m_leftActive; case RightSide: return m_rightActive; case IgnoreSide: qDebug("Invalid side specified!"); break; } return NULL; } KTabWidget *Manager::getTabs(Side side) { switch (side) { case LeftSide: return m_leftTabs; case RightSide: return m_rightTabs; case IgnoreSide: qDebug("Invalid side specified!"); break; } return NULL; } void Manager::slotActiveChanged(QWidget *page) { Session *session = find(static_cast(page)); setActive(session); } void Manager::slotSessionCloseRequest(QWidget *page) { Session *session = find(static_cast(page)); if (getTabs(session->m_side)->count() == 1) { KMessageBox::error(0L, i18n("At least one session must remain open on each side.")); return; } if ((session->m_remote && session->getClient()->socket()->isBusy()) || !session->isFreeConnection()) { KMessageBox::error(0L, i18n("Please finish all transfers before closing the session.")); return; } else { // Remove the session if (session->getClient()->socket()->isConnected()) { if (KMessageBox::questionYesNo(0L, i18n("This session is currently connected. Are you sure you wish to disconnect?"), i18n("Close Session")) == KMessageBox::No) return; } unregisterSession(session); } } } #include "kftpsession.moc" kftpgrabber-0.8.99~svn1214766/src/hi64-app-kftpgrabber.png0000644000175000017500000001217311276037142022523 0ustar michaelmichaelPNG  IHDR@@iqsBIT|dtEXtSoftwarewww.inkscape.org< IDATx[ ՙvzfiA!D%1c2ǓĉAǜA4&s&q&I&Y&z#MHY馻y^۽s^uΜUnջw&s5_p쮻DUUGG纻V\9sμc w{{~{"ƿ|;^~B9eg~={?o\{I՗^k.d8O֝3Re˖EXCk\bi^FnɁͻ?e^6ûҥKC]yƇx`a@)G^u<7oڴ΅],XwWКVXأv/dP|g5*t5#7@~᯼rw_Wt+0O mo\r8$ Q+ $A^. g[J)DݖoU#p#ュ$It^5hfn'$s-c QZ}6زa+g}!tc Sqs74y1@)I8(j•в)PS~pN-a`Ǥ9v4+,pv&S^o޶5V,9mR Tq$)5u<8dp"`(NQ,4Loޝ)=[=? {=M B.Ud p)8% RAPJ@ e$cDVrfX1a.׏ ێ!8Nf^#j+M2EaI! JFKӁ`J瓺9,t]b_ޕ@`g@m5WYi3 yRd@ڄ` /\in' _cw(וbK#H5dCF R. < hץ2?sh7$Z `&J [cai<A,jv [BgyAZg0,ViثEd r8&mRd*2٬gZT'%yB`f0,j7P0_} ̖8lo1-&ΈOG=TO+A0 BǦ-j>y `- HԒ-9}"ӼNθK[%-aGHH 0c _̖G#:iTJ AײU433.)F[N[˼Nf 3v >}@L'ar^P[T_yeЧHUQ%]2 %硼n1~%)apНtӰ0ltPg\c~x5B.Y:!44UGJiB嵈by(]*% V޽@`FX1v T"4NŔa@--Pmr^,)AC;h9SF-jFO[jLL "E$+*PZ`$*No y=;F@h{h5ctG.wtlzZđ7CpFř)ާEP N*tApy cd?ec@֟>d1 ~u-Wk EuԷ%;:p{Ht#MEy26U<ā&T8m^a4wPTa/ ^O0tv`b|Ʋ (Eq6wȉF} fF8XVzM|k>%~&$㸺ʋc܌4;}_ 8`}>}bۼb```[;y/mxi~}s-5VBVl߉/V$o8I )u88u](ĩ;y` z֏2a݊x vSpЇrE` ao] i1Oݎs~:( J0>tu GV`l낄3Gٱj*A0_5 =y|6r~~#h(Z,ɘ (}@ w:~# ƛnP08dN|eS~FΈ0[g?2ebhE7Ga*(Q,@6pF.8hr':,qqX|3q5vt;L.\[9~CUHlڰE답?^w͵ƮJH|"!6qai(R-hMrHu;4* t{̹#p\@8w|M9'ջaJvcߕrA*|M 4=qƐMB^*[pt0F@E̅'CV4'@#/bUX"[8Ѳy ep ^ȅ+#{aq[A _bECeY+/hbD{3Y˦A6Pp/)ꎠbEȕ>?bUlӂN'tr3 1mR*{z0 ѷK01!:ܶ-Ng46VTWU+NL6s|τ殿__sw ͨ[x-AP0D?$r_ @)-Z߰:-3&` 22] EA|+soH*mGb˩_/db1HPFe/@l WQ Ef0LH\&iq5Cns=]ĸ0rE}W{RxW6dTٛ.^ RDdJ@|l@{{:f${q7X,v=y|Λ?(Dd')J |'֌Mؾs1&D!eu]ͤ}y镟痢` RHK]W bSPZ;͎Td&& R6ن/o!`0 9`\iL} GHh=Q`-qiS*2_l7v)r]Z;? r=~dP@nt?jпIgKa^V[!5 019`*w/ePm/FAvZB`A-`#/ `XTtH%Jx4:4uGۑ:7MZߜ88Y+`B[kq;,뤊`j0 s=GvgTYu0lGдN<m0A|=;G=i[@wq&r\SQ0~6q%O-KiWikcDzhB}<\#̱CjdtK~Xg珦xۿBB1DÓ!1E EHJm\Jo[gwfvfƦ)w.)Q6Q5M:t`7 ae2!R믎>Etvvnنb<0٬Nd2i:tE4! ;֭]{.T 41 ^lu; P@EqQ#UZu& ʲHtD]_Ͷ(Oǀ0 tqQ' C#\rァ诘bB6Nesg+dyY ,ALCǤ=?$SKSz!6b DՄvPoFП?Rˁ+TPb]}pSĖe ;n݋!11Pbu"+@/qs`)bbLعDVV#" L89{; Lj/d`9ĂIkնǝ4(b"3Fߕa Nw$pG:=p7ۊzk4,9bKn T^ _!v#PU :4|ta~aF; zr~lB&8L aY=c7́"_O'f$0\,<]/ #jn%C>1l P&(8[7j8¦jNNN?Rܡ2~JЍ%0 "$dv7AX(οpiu/?o% ׭|$17XLJF:hҽ*t Iw催ZE~8>]3UC5zul9,Z@ #oeF@yF{#=s>8v9E<ѱz[=k'L.n%ǒV[hsۥ G<[;0)xɒS[l06IENDB`kftpgrabber-0.8.99~svn1214766/src/hi48-app-kftpgrabber.png0000644000175000017500000000776311276037142022536 0ustar michaelmichaelPNG  IHDR00WIDATxZy\yu潹gY!$vud&@8$rRƩmH0EW\PraĐpɄF j5{y;SK%o7~}_w%B9[3RJCccX*qOEc˖x"FQjD*oqdY?}t)nGctzWPW_tu\uU\\ jwH7| himM 0 {IOnٴ?$\U̝;;8}lSB Zs7ujp+G\g^z >'(l]ټn޼Y쒍7Cayד:~;~09:O9E,{'^D`e濺]׉OnTDڻ7Kz◿'紌Bf6\~WXu^zgA/}KKpUq-_[>yW?/ SB\4N@ `ڦD"qY5Ąq]ܱtprx3߼ss@?Oףy~;o򳒭Mp1M c%AeD: JË\o^߬Z%kڇL6QF^}Cw}Qh9Ђ*(Q ('ټ{]㫏؜??QK"arh$԰gё JPQ97sqh'˂6q=x_\ wu.N Wր1jT$H8(IJ)%dBj8 - !XS&@ՠ:_g>O)c5R5bVi( F4 * БK=v/@I a>>{Q2 Y 9%!AdLCfY|I׀?z*Q,5ݚþ A LRS0*Pnsrl47wyZ#O|apmONdMUkLڊ%/\' 8X.|pGs-5X%?yY JŅsw(i*[̠\4၆4# KO h² rc\a`bZOvA,Cp3p paF{z{K68+E z\9!! 4(Hb1\F$D#;#Fd F@s,Xh A"WuJoqΠ* ꙡk fI`,d0j#k(ch Q?<.6.a04ō$ @8Qc }juVF=L79՛q^RGխ?o6+@0EK^jPPՇF@ u [k, Z tʍ*.ag\>HX8C!5cN * BA 0 ^z1Sj4IrEU_ 0(80xŃ[Bp#eaN8UT6T#hy(V>h| -,9̉zKz`)!Xsw'se"G4%4(8z:fyĻf,YnU9o`yp^xyǎ킄c̳,{x/=̳i MrWJHG9="WNYPBte~A7IuayM^fdɣ3q:>}QX6Ǻ Žf1:ΚDlp1B|(4d\%W<>cfVc0SrrI8_(෯*H­nq[ooߖ^[t ZE_J)mA)@?`NtWr{}*b4=Ꝁ!#D(  zFs=h 5TI-p9cX>s:ò=:1^M-_HOwU*%J*K5nҶP-ބ&;4ia Óv^FBp.8K?߭fxtn-^~; R ?& eYՁIYg39ZWWz `T,i:jz* m{[X:udmD3h]q!BIĊy(sr©X=;AE ka&aenėmR4='9Ge? dp( O!1PK'Z.GROWBf("8/n˔oP[GiRc>#=rsQjK&CQK8:60D-xљ_-J9g5en5xo;p;iއ&yʃ`l Ipדۇ% n\v1qY%mϻޭkp9'52:6]j)C r>Dbx N);Uذ29rKBB5q3Pvu"^M ɷ|I޾cwDl`a[gTA4"e;B076 37TNm#`PVYp!|ug`TU5z.e7O>$㟧BZ.k,Ba'мd5` D! *l+Ѿ4b+I9o=3}އ~ -{!%.B[8soRX4h}1#fv~i! *R%E=]{qNWR5=A-E ۹)s, V<p%P:v棭Tt h,f? w]Eǩ \H 1ל:/SXxn /K>8}h97 El`B|m#߹i*`nU})sIENDB`kftpgrabber-0.8.99~svn1214766/src/kftpqueueconverter.cpp0000644000175000017500000001447511276037142022652 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftpqueueconverter.h" #include "kftpqueue.h" #include #include #include KFTPQueueConverter::KFTPQueueConverter(QObject *parent) : QObject(parent) { } void KFTPQueueConverter::importQueue(const QString &filename) { m_xml = QDomDocument("KFTPGrabberQueue"); KFTPQueue::Manager::self()->clearQueue(); // Load from file QIODevice *file = KFilterDev::deviceForFile(filename); m_xml.setContent(file); file->close(); delete file; // Parse XML and create KFTPQueueTransfers QDomNode n = m_xml.documentElement().firstChild(); while (!n.isNull()) { importNode(n); n = n.nextSibling(); } KFTPQueue::Manager::self()->doEmitUpdate(); } void KFTPQueueConverter::exportQueue(const QString &filename) { m_xml = QDomDocument("KFTPGrabberQueue"); m_xml.setContent(QString("")); // Go trough all KFTPQueueTransfers and generate XML QList sites = KFTPQueue::Manager::self()->topLevelObject()->getChildrenList(); foreach (KFTPQueue::QueueObject *i, sites) { foreach (KFTPQueue::QueueObject *t, i->getChildrenList()) generateXML(static_cast(t), m_xml.documentElement()); } // Save to file QIODevice *file = KFilterDev::deviceForFile(filename, "application/x-gzip"); if (!file->open(QIODevice::WriteOnly)) { qDebug("WARNING: Unable to open xml for writing!"); return; } QTextStream fileStream(file); m_xml.save(fileStream, 2); file->close(); delete file; } void KFTPQueueConverter::generateXML(KFTPQueue::Transfer *transfer, QDomNode parent) { // Create the item QDomElement item = m_xml.createElement("item"); parent.appendChild(item); // Create text nodes createTextNode("source", transfer->getSourceUrl().url(), item); createTextNode("dest", transfer->getDestUrl().url(), item); createTextNode("size", QString::number(transfer->getSize()), item); createTextNode("type", transfer->isDir() ? "directory" : "file", item); if (transfer->isDir() && transfer->hasChildren()) { // Transfer has children, add them as well QDomElement tag = m_xml.createElement("children"); item.appendChild(tag); foreach (KFTPQueue::QueueObject *i, transfer->getChildrenList()) { generateXML(static_cast(i), tag); } } } void KFTPQueueConverter::importNode(QDomNode node, QObject *parent) { // Get node data KUrl srcUrl = KUrl(getTextNode("source", node)); KUrl dstUrl = KUrl(getTextNode("dest", node)); filesize_t size = getTextNode("size", node).toULongLong(); bool dir = getTextNode("type", node) == "directory"; KFTPQueue::TransferType transType = KFTPQueue::Download; if (srcUrl.isLocalFile() && !dstUrl.isLocalFile()) { transType = KFTPQueue::Upload; } else if (!srcUrl.isLocalFile() && dstUrl.isLocalFile()) { transType = KFTPQueue::Download; } else if (!srcUrl.isLocalFile() && !dstUrl.isLocalFile()) { transType = KFTPQueue::FXP; } // Create new transfer if (!parent) parent = KFTPQueue::Manager::self()->topLevelObject(); KFTPQueue::Transfer *transfer = 0L; if (dir) transfer = new KFTPQueue::TransferDir(parent); else transfer = new KFTPQueue::TransferFile(parent); transfer->setSourceUrl(srcUrl); transfer->setDestUrl(dstUrl); transfer->addSize(dir ? 0 : size); transfer->setTransferType(transType); if (parent == KFTPQueue::Manager::self()->topLevelObject()) { KFTPQueue::Manager::self()->insertTransfer(transfer); } else { transfer->setId(KFTPQueue::Manager::self()->m_lastQID++); emit KFTPQueue::Manager::self()->objectAdded(transfer); transfer->readyObject(); } QDomNodeList tagNodes = node.toElement().elementsByTagName("children"); if (dir && tagNodes.length() > 0) { // Import all child nodes QDomNode n = node.firstChild(); while (!n.isNull()) { if (n.toElement().tagName() == "children") { n = n.firstChild(); break; } n = n.nextSibling(); } while (!n.isNull()) { importNode(n, transfer); n = n.nextSibling(); } } } void KFTPQueueConverter::createTextNode(const QString &name, const QString &value, QDomNode parent) { QDomElement tag = m_xml.createElement(name); parent.appendChild(tag); QDomText textNode = m_xml.createTextNode(value); tag.appendChild(textNode); } QString KFTPQueueConverter::getTextNode(const QString &name, QDomNode parent) { QDomNodeList tagNodes = parent.toElement().elementsByTagName(name); if (tagNodes.length() > 0) { return tagNodes.item(0).toElement().text().trimmed(); } else { return QString::null; } } #include "kftpqueueconverter.moc" kftpgrabber-0.8.99~svn1214766/src/site.cpp0000644000175000017500000000535011276037142017645 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "site.h" #include "queuegroup.h" #include "kftpqueue.h" namespace KFTPQueue { Site::Site(QueueObject *parent, KUrl url) : QueueObject(parent, QueueObject::Site), m_group(new QueueGroup(this)) { url.setPath("/"); m_siteUrl = url; // Connect to some group signals connect(m_group, SIGNAL(interrupted()), this, SLOT(slotGroupInterrupted())); } void Site::execute() { m_completed = 0; m_resumed = 0; m_status = Running; // Reset and start the group m_group->reset(); m_group->executeNextTransfer(); } void Site::abort() { // If not running, just return if (!isRunning()) return; // Set the aborting flag m_aborting = true; emit siteAborted(); // Signal abort to all child transfers foreach (QueueObject *i, m_children) { if (i->isRunning() && !i->isAborting()) i->abort(); } // Clear all the stuff m_status = Stopped; m_resumed = 0; m_completed = 0; m_aborting = false; m_size = m_actualSize; emit objectUpdated(); } void Site::slotGroupInterrupted() { if (!m_aborting) abort(); } } #include "site.moc" kftpgrabber-0.8.99~svn1214766/src/ui/0000755000175000017500000000000011276037142016607 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/ui/foobar.h0000644000175000017500000000144611276037142020235 0ustar michaelmichael/*************************************************************************** * Copyright (C) 2003 by Jernej Kos * * kostko@jweb-network.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #ifndef FOOBAR_H #define FOOBAR_H /** @author Jernej Kos */ class FooBar{ public: ~FooBar(); }; #endif kftpgrabber-0.8.99~svn1214766/src/ui/kftpsearchlayout.ui0000644000175000017500000002054711276037142022546 0ustar michaelmichael KFTPSearchLayout 0 0 550 409 500 400 Queue Search & Replace 0 Using this dialog, you can do massive replacing of source/destination paths of the queued transfers. <b>Changes cannot be undone.</b> false Search What Destination: false Source: false Search only for transfers on specific server false Server Info Server name: false Host: false Password: false Username: false Port: false 65535 1 21 Replace With Destination: false Source: false KFTPServerLineEdit QWidget
widgets/kftpserverlineedit.h
0 18 0 7 0 image0
789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f kpassdlg.h
kftpgrabber-0.8.99~svn1214766/src/ui/checksum_verifier.ui0000644000175000017500000001765511276037142022661 0ustar michaelmichael VerifierLayout 0 0 500 490 500 490 0 0 0 0 0 0 Progress 0 0 <b>File:</b> false 0 0 none false File list 1 0 20 20 false 0 0 Unprocessed false 20 20 false 0 0 Ok false 20 20 false 0 0 Not found false 20 20 false 0 0 Failed false Qt::Vertical QSizePolicy::Expanding 21 260 K3ListView Q3ListView
k3listview.h
kftpgrabber-0.8.99~svn1214766/src/ui/kftpqueueeditorlayout.ui0000644000175000017500000002721011276037142023626 0ustar michaelmichael KFTPQueueEditorLayout 0 0 628 290 0 Source Server Info Server Info Server name: false Host: false Password: false Username: false Port: false 65535 1 21 Destination Server Info Server Info Server name: false Host: false Password: false Username: false Port: false 65535 1 21 <b>Source:</b> false <b>Destination:</b> false 0 0 0 0 Transfer type: false 7 0 0 0 Download Upload FXP KFTPServerLineEdit QWidget
kftpserverlineedit.h
0 18 0 7 0 image0
KComboBox QComboBox
789c534e494dcbcc4b554829cdcdad8c2fcf4c29c95030e0524611cd48cd4ccf28010a1797249664262b2467241641a592324b8aa363156c15aab914146aadb90067111b1f kpassdlg.h
kftpgrabber-0.8.99~svn1214766/src/ui/quickconnect.ui0000644000175000017500000004721511276037142021645 0ustar michaelmichael QuickConnect 0 0 385 356 5 0 0 0 32767 32766 0 &General 5 1 0 0 Recent connections 0 5 0 0 Select connection: false 0 1 0 0 1 1 0 0 Q3GroupBox::GroupBoxPanel Q3GroupBox::Sunken Quick Connect 0 5 0 0 80 0 URL: false Enter the whole url into this box 0 5 0 0 80 0 Host: false Enter ftp's hostname Port: false 65535 21 0 5 0 0 80 0 Protocol: false 7 0 0 0 FTP FTP over TLS/SSL (explicit) FTP over TLS/SSL (implicit) SFTP over SSH2 Anon&ymous login Check for anonymous login 0 5 0 0 80 0 Username: false Enter account username 0 5 0 0 80 0 Password: false true Enter account password Add to &bookmarks 20 20 Expanding Vertical Advanced Server Encoding 0 1 0 0 Encoding: false 21 421 Expanding Vertical qPixmapFromMimeSource KComboBox QComboBox tabWidget7 urlBox hostBox portBox protocolBox protoAdvanced anonLogin usernameBox passwordBox addBookmark serverEncoding kcombobox.h kpushbutton.h kcombobox.h kpushbutton.h klineedit.h kcombobox.h kftpgrabber-0.8.99~svn1214766/src/ui/config_transfers.ui0000644000175000017500000005761011276037142022513 0ustar michaelmichael TransferSettings 0 0 646 592 0 0 0 0 0 0 0 Co&nnection Active Connection IP Force PORT/EPRT to &use configured IP false IP/hostname: false false 0 0 &Ignore external IP for LAN connections Active Connection Port Range Onl&y use ports from the specified port range false Minimum port: false false 0 0 70 0 false Maximum port: false false 0 0 70 0 Timeouts Control connection timeout (in seconds): false 0 0 70 0 1000 Data transfer timeout (in seconds): false 0 0 70 0 1000 Speed limit Download (KB/s): false 0 0 70 0 99999 Upload (KB/s): false 0 0 70 0 99999 Qt::Vertical QSizePolicy::Expanding 21 20 Dis&k Space Free Disk Space Check Stop transfer if there is &not enough free space false Interval (sec): false false 0 0 false Minimum free space (MiB): false false 0 0 1000 Qt::Vertical QSizePolicy::Expanding 31 191 Thre&ads Threads Number of threads per session: false 0 0 Use the primary connection for transfers Qt::Vertical QSizePolicy::Expanding 21 360 &Miscellaneous Failed Transfers Automatically retry failed transfers false Maximum number of retries before marking as failed: false false 0 0 Other &Queue files (instead of transferring) when "dragged && dropped" Skip &empty directories when queueing Confirm disconnects &before disconnecting Qt::Vertical QSizePolicy::Expanding 21 260 qPixmapFromMimeSource Q3GroupBox QGroupBox
Qt3Support/Q3GroupBox
1
KLineEdit QLineEdit
klineedit.h
klineedit.h kcfg_portForceIp toggled(bool) textLabel5 setEnabled(bool) 46 70 46 91 kcfg_portForceIp toggled(bool) kcfg_portIp setEnabled(bool) 232 75 256 94 kcfg_failedAutoRetry toggled(bool) textLabel1_4 setEnabled(bool) 74 53 78 53 kcfg_failedAutoRetry toggled(bool) kcfg_failedAutoRetryCount setEnabled(bool) 101 53 101 53 kcfg_diskCheckSpace toggled(bool) textLabel6 setEnabled(bool) 87 53 98 53 kcfg_diskCheckSpace toggled(bool) textLabel7 setEnabled(bool) 101 53 101 53 kcfg_diskCheckSpace toggled(bool) kcfg_diskCheckInterval setEnabled(bool) 101 53 101 53 kcfg_diskCheckSpace toggled(bool) kcfg_diskMinFreeSpace setEnabled(bool) 101 53 101 53 kcfg_activeForcePort toggled(bool) textLabel1 setEnabled(bool) 76 192 72 212 kcfg_activeForcePort toggled(bool) textLabel2 setEnabled(bool) 115 195 120 240 kcfg_activeForcePort toggled(bool) kcfg_activeMinPort setEnabled(bool) 586 187 581 217 kcfg_activeForcePort toggled(bool) kcfg_activeMaxPort setEnabled(bool) 598 195 604 254
kftpgrabber-0.8.99~svn1214766/src/ui/foobar.cpp0000644000175000017500000000134611276037142020567 0ustar michaelmichael/*************************************************************************** * Copyright (C) 2003 by Jernej Kos * * kostko@jweb-network.net * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * ***************************************************************************/ #include "foobar.h" FooBar::~FooBar() { } kftpgrabber-0.8.99~svn1214766/src/ui/kftpbookmarkimportlayout.ui0000644000175000017500000002116211276037142024333 0ustar michaelmichael KFTPBookmarkImportLayout 0 0 629 533 Bookmark Import Wizard Step 1: <b>Select Import Plugin</b> 170 430 Image false Please select the appropriate import plugin from the list below. Each plugin can import from one different format. Qt::AlignVCenter true 21 16 Minimum Vertical Available import plugins: false Name true true Description true true Step 2: <b>Select Bookmark File to Import</b> 170 430 Image false Please select the bookmark file from which you would like to import your bookmarks. A default path has already been determined by the import plugin. Qt::AlignVCenter true <b>Bookmark path:</b> false 31 80 Expanding Vertical Step 3: <b>Importing Bookmarks...</b> 170 430 Image false Please wait while the bookmarks are being imported. false <b>Import progress:</b> false 31 241 Expanding Vertical qPixmapFromMimeSource KListView Q3ListView kurlrequester.h kpushbutton.h kprogress.h kftpgrabber-0.8.99~svn1214766/src/ui/config_filters.ui0000644000175000017500000000611311276037142022144 0ustar michaelmichael ConfigFilterLayout 0 0 596 451 0 0 0 0 ASCII E&xtensions Qt::Vertical QSizePolicy::Expanding 20 212 Add Extension Remove Extension: false qPixmapFromMimeSource KLineEdit QLineEdit
klineedit.h
KPushButton QPushButton
kpushbutton.h
kpushbutton.h klineedit.h k3listview.h
kftpgrabber-0.8.99~svn1214766/src/ui/config_general.ui0000644000175000017500000003035011276037142022111 0ustar michaelmichael GeneralSettings 0 0 544 398 0 0 0 0 0 0 0 &General E-mail &Address &Use e-mail address from control center E-mail: false Startup and Exit Confirm program e&xit if there are active transfers Start the program minimi&zed to systray Show &splash screen on startup Show the s&ystray icon Ex&it by default when clicking the X button Qt::Vertical QSizePolicy::Expanding 21 20 &Bookmarks 0 0 Site Defaults Local directory: false Retry delay: false 0 0 Number of retries (0 = infinite): false 0 0 Encoding: false 0 0 0 0 Options Encr&ypt bookmark file &Show sites from KWallet among bookmarks Qt::Vertical QSizePolicy::Expanding 21 30 &Notification Balloons &Show balloon when transfer completes Only show when &queue is empty after transfer Show balloon when connection retr&y succeeds Qt::Vertical QSizePolicy::Expanding 21 111 qPixmapFromMimeSource Q3GroupBox QGroupBox
Qt3Support/Q3GroupBox
1
KComboBox QComboBox
kcombobox.h
KLineEdit QLineEdit
klineedit.h
KUrlRequester QFrame
kurlrequester.h
klineedit.h kurlrequester.h klineedit.h kpushbutton.h kcombobox.h kcfg_globalMail toggled(bool) textLabel8 setDisabled(bool) 44 69 40 96 kcfg_globalMail toggled(bool) kcfg_anonMail setDisabled(bool) 198 75 215 96
kftpgrabber-0.8.99~svn1214766/src/ui/config_log.ui0000644000175000017500000002360511276037142021262 0ustar michaelmichael LogSettings 0 0 688 402 0 0 0 0 0 0 0 &Appearance Log Colors Client command color: false 0 0 Server response color: false 0 0 Multiline response color: false 0 0 Error message color: false 0 0 Status message color: false 0 0 Qt::Vertical QSizePolicy::Expanding 31 111 &Output &File Output &Save log to file false Output file: false false Qt::Vertical QSizePolicy::Expanding 61 171 qPixmapFromMimeSource Q3GroupBox QGroupBox
Qt3Support/Q3GroupBox
1
KColorButton QPushButton
kcolorbutton.h
KFontRequester QWidget
kfontrequester.h
KUrlRequester QFrame
kurlrequester.h
kfontrequester.h kcolorbutton.h kcolorbutton.h kcolorbutton.h kcolorbutton.h kcolorbutton.h kurlrequester.h kpushbutton.h kcfg_saveToFile toggled(bool) textLabel16 setEnabled(bool) 71 68 71 96 kcfg_saveToFile toggled(bool) kcfg_outputFilename setEnabled(bool) 315 70 319 93
kftpgrabber-0.8.99~svn1214766/src/ui/CMakeLists.txt0000644000175000017500000000077211276037142021355 0ustar michaelmichaelINCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(ui_SRCS foobar.cpp ) SET( ui_UI kftpfilteraddpatternlayout.ui quickconnect.ui kftpqueueeditorlayout.ui kftpsearchlayout.ui kftpbookmarkimportlayout.ui config_general.ui config_transfers.ui config_log.ui config_display.ui config_filters.ui checksum_verifier.ui ) KDE4_ADD_UI_FILES(ui_SRCS ${ui_UI} ) KDE4_ADD_LIBRARY(ui STATIC ${ui_SRCS}) kftpgrabber-0.8.99~svn1214766/src/ui/config_display.ui0000644000175000017500000001022011276037142022133 0ustar michaelmichael DisplaySettings 0 0 537 424 0 0 Displa&y File &Browser Show &hidden files and directories Show &directory tree Show filesi&ze in bytes (toggle for "human readable" format) Show &owner and group for each file Show directory &size &Other Interface Elements Show left sidebar 21 40 Expanding Vertical qPixmapFromMimeSource kftpgrabber-0.8.99~svn1214766/src/ui/kftpfilteraddpatternlayout.ui0000644000175000017500000000671311276037142024634 0ustar michaelmichael KFTPFilterAddPatternLayout 0 0 380 110 0 5 2 0 0 Q3GroupBox::GroupBoxPanel Q3GroupBox::Sunken New Pattern Filename pattern: false Color: false 0 0 0 0 qPixmapFromMimeSource klineedit.h kcolorbutton.h kftpgrabber-0.8.99~svn1214766/src/widgets/0000755000175000017500000000000011276037142017640 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/widgets/zeroconflistview.h0000644000175000017500000000412711276037142023431 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPZEROCONFLISTVIEW_H #define KFTPZEROCONFLISTVIEW_H #include "listview.h" namespace KFTPWidgets { /** * This class provides a list view that displays all current FTP servers published via Zeroconf protocol. * * @author Jernej Kos */ class ZeroConfListView : public ListView { Q_OBJECT public: ZeroConfListView(QWidget *parent); private slots: void slotSitesChanged(); void slotSiteExecuted(Q3ListViewItem*); }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/0000755000175000017500000000000011276037142021630 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/importwizard.h0000644000175000017500000000505611276037142024542 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPBOOKMARKIMPORTWIZARD_H #define KFTPBOOKMARKIMPORTWIZARD_H #include "ui/kftpbookmarkimportlayout.h" #include #include class KFTPBookmarkImportPlugin; namespace KFTPWidgets { namespace Bookmarks { class PluginListItem : public K3ListViewItem { friend class ImportWizard; public: PluginListItem(K3ListView *parent, KService::Ptr service); private: KService::Ptr m_service; }; /** * This is a wizard used to import bookmarks via detected KParts plugins. * * @author Jernej Kos */ class ImportWizard : public KFTPBookmarkImportLayout { Q_OBJECT public: ImportWizard(QWidget *parent); private: KService::Ptr m_service; KFTPBookmarkImportPlugin *m_plugin; void displayPluginList(); private slots: virtual void next(); void slotImportProgress(int progress); void slotPluginsSelectionChanged(Q3ListViewItem *i); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/importwizard.cpp0000644000175000017500000001170711276037142025075 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "importwizard.h" #include "kftpapi.h" #include "kftppluginmanager.h" #include "interfaces/kftpbookmarkimportplugin.h" #include "kftpbookmarks.h" #include #include //Added by qt3to4: #include #include #include #include #include #include using namespace KFTPGrabberBase; namespace KFTPWidgets { namespace Bookmarks { PluginListItem::PluginListItem(K3ListView *parent, KService::Ptr service) : K3ListViewItem(parent, service->name(), service->comment()), m_service(service) { setPixmap(0, loadSmallPixmap("filter")); } ImportWizard::ImportWizard(QWidget *parent, const char *name) : KFTPBookmarkImportLayout(parent, name) { m_pluginList->setFullWidth(true); m_pluginList->setAllColumnsShowFocus(true); connect(m_pluginList, SIGNAL(clicked(Q3ListViewItem*)), this, SLOT(slotPluginsSelectionChanged(Q3ListViewItem*))); setNextEnabled(Step1, false); // Set pixmap QString pixmapPath = locate("appdata", "kftpgrabber-bi-wizard.png"); if (!pixmapPath.isNull()) { QPixmap pix(pixmapPath); m_wizardPixmap->setPixmap(pix); m_wizardPixmap_2->setPixmap(pix); m_wizardPixmap_3->setPixmap(pix); } // Disable useless help buttons setHelpEnabled(Step1, false); setHelpEnabled(Step2, false); setHelpEnabled(Step3, false); displayPluginList(); } void ImportWizard::next() { if (currentPage() == Step1) { // Load the plugin m_plugin = KFTPAPI::getInstance()->pluginManager()->loadImportPlugin(m_service); if (!m_plugin) { KMessageBox::error(0, i18n("Unable to load the selected import plugin.")); return; } else { // Get the default plugin path m_importUrl->setURL("~/" + m_plugin->getDefaultPath()); } } else if (currentPage() == Step2) { // Check if the file exists if (!QFileInfo(m_importUrl->url()).exists() || !QFileInfo(m_importUrl->url()).isReadable()) { KMessageBox::error(0, i18n("The selected file does not exist or is not readable.")); return; } } Q3Wizard::next(); if (currentPage() == Step3) { // Start the import setBackEnabled(Step3, false); connect(m_plugin, SIGNAL(progress(int)), this, SLOT(slotImportProgress(int))); m_plugin->import(m_importUrl->url()); } } void ImportWizard::slotImportProgress(int progress) { m_progressBar->setProgress(progress); if (progress == 100) { // Import complete KMessageBox::information(0, i18n("Bookmark importing is complete.")); // Add the imported stuff to the current bookmarks KFTPBookmarks::Manager::self()->importSites(m_plugin->getImportedXml().documentElement()); accept(); } } void ImportWizard::displayPluginList() { KTrader::OfferList plugins = KFTPAPI::getInstance()->pluginManager()->getImportPlugins(); KTrader::OfferList::ConstIterator end(plugins.end()); for (KTrader::OfferList::ConstIterator i(plugins.begin()); i != end; ++i) { KService::Ptr service = *i; new PluginListItem(m_pluginList, service); } } void ImportWizard::slotPluginsSelectionChanged(Q3ListViewItem *i) { if (i) { PluginListItem *item = static_cast(i); m_service = item->m_service; setNextEnabled(Step1, true); } else { setNextEnabled(Step1, false); } } } } #include "importwizard.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/editor.ui0000644000175000017500000006576511276037142023500 0ustar michaelmichael Editor 0 0 447 392 0 0 &General 80 0 Site Name Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 75 true 80 0 Protocol Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter FTP SFTP (via SSH) 69 0 IP Address Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Port QAbstractSpinBox::NoButtons 1 65565 21 User Name Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Anonymous Password Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter true 80 0 Remote Path Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Local Path Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Notes Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Vertical 20 40 Qt::Vertical 20 0 Options 5 Disable use of extended passive mode Disable use of passive mode Use site IP for passive mode connections Disable pre-set active mode IP for this site Use faster directory listing via STAT Do not use multiple transfer threads for this site Qt::Vertical 20 40 Advanced Server Encoding Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Retries Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Vertical 20 0 0 0 Retry to connect on failure true true false Retry delay 0 0 55 0 10 9999 60 Number of retries (0 = infinite) 0 0 55 0 10 Keepalive Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Vertical 20 40 0 0 Use keepalive to keep the connection open true true false Frequency (seconds) 0 0 55 0 30 600 Qt::Vertical 20 40 Security 0 Qt::Vertical 20 40 Qt::Horizontal 40 20 312 0 <i>The protocol currently selected for this site does not support any security configuration options.</i> true Qt::Horizontal 40 20 Qt::Vertical 20 40 SSL Negotiation Type Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter None (plain FTP) AUTH TLS Implicit SSL Data Protection Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Always encrypt the data channel Encrypt only directory listings Do not encrypt the data channel Use client SSL certificate for authentication true true false Certificate Key file Qt::Vertical 20 40 Use public-key authentication true true false Public Key Private Key Qt::Vertical 407 181 KComboBox QComboBox
kcombobox.h
KLineEdit QLineEdit
klineedit.h
KUrlRequester QFrame
kurlrequester.h
1
anonymous toggled(bool) password setDisabled(bool) 392 139 316 165 anonymous toggled(bool) userName setDisabled(bool) 365 137 311 139
kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/sidebar.cpp0000644000175000017500000001121511276037142023745 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Markus Brueffer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include #include #include //Added by qt3to4: #include #include #include #include #include "kftpapi.h" #include "kftpbookmarks.h" #include "editor.h" #include "listview.h" #include "sidebar.h" namespace KFTPWidgets { namespace Bookmarks { KActionCollection *Sidebar::actionCollection() { return KFTPAPI::getInstance()->mainWindow()->actionCollection(); } Sidebar::Sidebar(QWidget *parent, const char *name) : QWidget(parent, name) { Q3VBoxLayout *layout = new Q3VBoxLayout(this); m_toolBar = new KToolBar(this, "bookmarkToolBar"); m_toolBar->setIconSize(16); layout->addWidget(m_toolBar); // Create the list view for editing bookmarks m_tree = new ListView(KFTPBookmarks::Manager::self(), this); m_tree->setAutoUpdate(true); m_tree->setConnectBookmark(true); m_tree->setEditMenuItem(true); layout->addWidget(m_tree); m_editAction = new KAction(i18n("&Edit..."), "document-properties", KShortcut(), this, SLOT(slotEditAction()), actionCollection(), "bookmark_edit2"); connect(m_tree, SIGNAL(bookmarkClicked(Q3ListViewItem*)), this, SLOT(slotClicked(Q3ListViewItem*))); connect(m_tree, SIGNAL(bookmarkNew(ListViewItem*, KFTPBookmarks::Site*)), this, SLOT(slotNewAction(ListViewItem*, KFTPBookmarks::Site*))); // Get the new bookmark data m_tree->fillBookmarkData(); // Init the Actions slotClicked(0L); setMinimumWidth(200); } Sidebar::~Sidebar() { } void Sidebar::refresh() { m_tree->clear(); m_tree->fillBookmarkData(); } void Sidebar::slotEditAction() { ListViewItem* item = static_cast(m_tree->selectedItems().at(0)); if (item) { BookmarkEditor *editor = new BookmarkEditor(item, this); editor->exec(); delete editor; // Update the bookmarks globaly KFTPBookmarks::Manager::self()->emitUpdate(); } } void Sidebar::slotNewAction(ListViewItem*, KFTPBookmarks::Site *site) { BookmarkEditor *editor = new BookmarkEditor(static_cast(m_tree->selectedItems().at(0)), this); if (!editor->exec()) { // If the user clicks Abort, remove the newly created server KFTPBookmarks::Manager::self()->delSite(site); } delete editor; } void Sidebar::slotClicked(Q3ListViewItem *item) { // When nodes are expanded, item is 0, although an item is still selected, so grab it here item = m_tree->selectedItems().at(0); // Enable/Disable actions for the toolbar if (!item) { actionCollection()->action("bookmark_delete")->setEnabled(false); actionCollection()->action("bookmark_subcat")->setEnabled(true); m_editAction->setEnabled(false); return; } actionCollection()->action("bookmark_delete")->setEnabled(true); if (static_cast(item)->m_type == BT_CATEGORY) { m_editAction->setEnabled(false); actionCollection()->action("bookmark_subcat")->setEnabled(true); } else { m_editAction->setEnabled(true); actionCollection()->action("bookmark_subcat")->setEnabled(false); } } } } #include "sidebar.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/editor.h0000644000175000017500000000664011276037142023275 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPBOOKMARKEDITOR_H #define KFTPBOOKMARKEDITOR_H #include #include // Ui files #include "widgets/bookmarks/ui_editor.h" namespace KFTPBookmarks { class Site; class Manager; } class KPushButton; namespace KFTPWidgets { namespace Bookmarks { class TreeView; /** * @author Jernej Kos */ class Editor : public KDialog { Q_OBJECT public: /** * Class constructor. * * @param parent Parent widget * @param quickConnect Should this dialog behave as quick connect */ Editor(QWidget *parent, bool quickConnect = false); /** * Returns the site selected for connection. */ KFTPBookmarks::Site *selectedSite() const { return m_selectedSite; } protected: /** * Saves the currently open item. */ void saveCurrentItem(); /** * Disables FTP-related options. */ void disableOptions(); /** * Enables FTP-related options. */ void enableOptions(); private: QSortFilterProxyModel *m_proxyModel; TreeView *m_treeView; Ui::Editor m_layout; QWidget *m_properties; QModelIndex m_currentIndex; KFTPBookmarks::Manager *m_manager; KFTPBookmarks::Site *m_selectedSite; KPushButton *m_newSite; KPushButton *m_removeSite; KPushButton *m_newCategory; KPushButton *m_duplicateSite; bool m_portChanged; private slots: void slotOkClicked(); void slotCancelClicked(); void slotConnectClicked(); void slotItemClicked(const QModelIndex &index); void slotAnonymousToggled(bool value); void slotProtocolChanged(int index); void slotPortChanged(); void slotCurrentNameChanged(const QString &name); void slotSiteRemoved(KFTPBookmarks::Site *site); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/editor.cpp0000644000175000017500000003634311276037142023633 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "bookmarks/editor.h" #include "bookmarks/treeview.h" #include "bookmarks/model.h" #include "misc/config.h" #include "kftpbookmarks.h" #include #include #include #include #include #include #include using namespace KFTPBookmarks; namespace KFTPWidgets { namespace Bookmarks { Editor::Editor(QWidget *parent, bool quickConnect) : KDialog(parent), m_selectedSite(0), m_portChanged(false) { // Create a copy of the current bookmark manager for our working needs m_manager = new Manager(Manager::self()); KHBox *layout = new KHBox(this); Model *bookmarksModel = new Model(m_manager, this); m_proxyModel = new QSortFilterProxyModel(this); m_proxyModel->setSourceModel(bookmarksModel); m_proxyModel->setSortRole(Model::TypeRole); KVBox *leftPart = new KVBox(layout); m_treeView = new TreeView(m_manager, leftPart); m_treeView->setModel(m_proxyModel); m_properties = new QWidget(layout); m_layout.setupUi(m_properties); m_properties->setEnabled(false); //KHBox *buttons = new KHBox(leftPart); QWidget *widget = new QWidget(leftPart); QGridLayout *buttons = new QGridLayout(widget); buttons->setContentsMargins(0, 0, 0, 0); m_newSite = new KPushButton(KIcon("bookmark-new"), i18n("&Add Site"), widget); m_removeSite = new KPushButton(KIcon("edit-delete"), i18n("&Remove"), widget); m_removeSite->setEnabled(false); m_newCategory = new KPushButton(KIcon("folder-new"), i18n("&Add Category"), widget); m_duplicateSite = new KPushButton(KIcon("edit-copy"), i18n("&Duplicate Site"), widget); m_duplicateSite->setEnabled(false); buttons->addWidget(m_newSite, 0, 0); buttons->addWidget(m_removeSite, 0, 1); buttons->addWidget(m_newCategory, 1, 0); buttons->addWidget(m_duplicateSite, 1, 1); buttons->setSpacing(2); connect(m_newSite, SIGNAL(clicked(bool)), m_treeView, SLOT(slotCreateNewSite())); connect(m_removeSite, SIGNAL(clicked(bool)), m_treeView, SLOT(slotRemove())); connect(m_newCategory, SIGNAL(clicked(bool)), m_treeView, SLOT(slotCreateSubcategory())); connect(m_duplicateSite, SIGNAL(clicked(bool)), m_treeView, SLOT(slotDuplicate())); if (quickConnect) setWindowTitle(i18n("Quick Connect")); else setWindowTitle(i18n("Bookmark Editor")); setButtons(Cancel | Ok | User1); setButtonText(User1, i18n("Connect With Selected Site")); setButtonIcon(User1, KIcon("network-connect")); enableButton(User1, false); setMainWidget(layout); showButton(Ok, !quickConnect); // Some minor setup m_layout.localPath->setMode(KFile::Directory | KFile::LocalOnly); m_layout.notes->setAcceptRichText(false); // Populate the charsets combo foreach (QString description, KGlobal::charsets()->descriptiveEncodingNames()) { m_layout.encoding->addItem(description, KGlobal::charsets()->encodingForName(description)); } connect(m_treeView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(slotItemClicked(const QModelIndex&))); connect(m_layout.anonymous, SIGNAL(toggled(bool)), this, SLOT(slotAnonymousToggled(bool))); connect(m_layout.protocol, SIGNAL(currentIndexChanged(int)), this, SLOT(slotProtocolChanged(int))); connect(m_layout.port, SIGNAL(valueChanged(int)), this, SLOT(slotPortChanged())); connect(m_layout.siteName, SIGNAL(textChanged(const QString&)), this, SLOT(slotCurrentNameChanged(const QString&))); connect(this, SIGNAL(okClicked()), this, SLOT(slotOkClicked())); connect(this, SIGNAL(cancelClicked()), this, SLOT(slotCancelClicked())); connect(this, SIGNAL(user1Clicked()), this, SLOT(slotConnectClicked())); connect(m_manager, SIGNAL(siteRemoved(KFTPBookmarks::Site*)), this, SLOT(slotSiteRemoved(KFTPBookmarks::Site*))); } void Editor::slotOkClicked() { saveCurrentItem(); // Merge our modified bookmarks back to the original ones Manager::self()->setBookmarks(m_manager); delete m_manager; } void Editor::slotCancelClicked() { // Any modifications have been lost delete m_manager; } void Editor::slotConnectClicked() { slotOkClicked(); accept(); } void Editor::slotItemClicked(const QModelIndex &index) { QModelIndex realIndex = m_proxyModel->mapToSource(index); if (realIndex.isValid()) { if (m_currentIndex != realIndex) { // Index has been changed, save the old site saveCurrentItem(); m_currentIndex = realIndex; } Site *site = realIndex.data(Model::SiteRole).value(); m_selectedSite = site; m_layout.tabWidget->setCurrentIndex(0); m_removeSite->setEnabled(true); if (site->isSite()) { enableButton(User1, true); m_duplicateSite->setEnabled(true); m_properties->setEnabled(true); // Populate the properties widget m_layout.siteName->setText(site->getAttribute("name")); m_layout.protocol->setCurrentIndex(site->protocol()); m_layout.ipAddress->setText(site->getProperty("host")); m_layout.port->setValue(site->getIntProperty("port")); if (site->getIntProperty("anonymous")) { m_layout.anonymous->setChecked(true); } else { m_layout.anonymous->setChecked(false); m_layout.userName->setText(site->getProperty("username")); m_layout.password->setText(site->getProperty("password")); } m_layout.remotePath->setText(site->getProperty("pathRemote")); m_layout.localPath->setPath(site->getProperty("pathLocal")); m_layout.notes->setPlainText(site->getProperty("description")); m_layout.disableExtendedPassive->setChecked(site->getIntProperty("disableEPSV")); m_layout.disablePassive->setChecked(site->getIntProperty("disablePASV")); m_layout.useSiteIp->setChecked(site->getIntProperty("pasvSiteIp")); m_layout.disablePresetIp->setChecked(site->getIntProperty("disableForceIp")); m_layout.useStat->setChecked(site->getIntProperty("statListings")); m_layout.disableThreads->setChecked(site->getIntProperty("disableThreads")); QString encoding = site->getProperty("encoding"); if (encoding.isEmpty()) encoding = KFTPCore::Config::defEncoding(); m_layout.encoding->setCurrentIndex(m_layout.encoding->findData(encoding)); m_layout.retry->setChecked(site->getIntProperty("retryEnabled")); m_layout.retryDelay->setValue(site->getIntProperty("retryDelay")); m_layout.retryCount->setValue(site->getIntProperty("retryCount")); m_layout.keepalive->setChecked(site->getIntProperty("keepaliveEnabled")); m_layout.keepaliveFrequency->setValue(site->getIntProperty("keepaliveFrequency")); // Select the proper security widget slotProtocolChanged(site->protocol()); switch (site->protocol()) { case Site::ProtoFtp: { m_layout.sslNegotiationType->setCurrentIndex(site->getIntProperty("sslNegotiationMode")); m_layout.sslProtMode->setCurrentIndex(site->getIntProperty("sslProtMode")); m_layout.sslClientCert->setChecked(site->getIntProperty("sslCertificateEnabled")); m_layout.sslCertPath->setPath(site->getProperty("sslCertificatePath")); m_layout.sslKeyPath->setPath(site->getProperty("sslKeyfilePath")); enableOptions(); break; } case Site::ProtoSftp: { m_layout.sshPubkey->setChecked(site->getIntProperty("sshPubkeyAuth")); m_layout.sshPublicKey->setPath(site->getProperty("sshPublicKey")); m_layout.sshPrivateKey->setPath(site->getProperty("sshPrivateKey")); disableOptions(); break; } } return; } } else { m_removeSite->setEnabled(false); } m_duplicateSite->setEnabled(false); enableButton(User1, false); m_properties->setEnabled(false); // Clear the properties widget m_layout.siteName->clear(); m_layout.protocol->setCurrentIndex(0); m_layout.securityStack->setCurrentIndex(0); m_layout.ipAddress->clear(); m_layout.port->setValue(21); m_layout.anonymous->setChecked(false); m_layout.userName->clear(); m_layout.password->clear(); m_layout.remotePath->clear(); m_layout.localPath->clear(); m_layout.notes->clear(); m_layout.disableExtendedPassive->setChecked(false); m_layout.disablePassive->setChecked(false); m_layout.useSiteIp->setChecked(false); m_layout.disablePresetIp->setChecked(false); m_layout.useStat->setChecked(false); m_layout.disableThreads->setChecked(false); } void Editor::saveCurrentItem() { if (!m_currentIndex.isValid()) return; Site *site = m_currentIndex.data(Model::SiteRole).value(); if (site->isSite()) { site->setAttribute("name", m_layout.siteName->text()); site->setProperty("protocol", m_layout.protocol->currentIndex()); site->setProperty("host", m_layout.ipAddress->text()); site->setProperty("port", m_layout.port->value()); site->setProperty("anonymous", m_layout.anonymous->isChecked()); site->setProperty("username", m_layout.userName->text()); site->setProperty("password", m_layout.password->text()); site->setProperty("pathRemote", m_layout.remotePath->text()); site->setProperty("pathLocal", m_layout.localPath->url().path()); site->setProperty("description", m_layout.notes->toPlainText()); site->setProperty("disableEPSV", m_layout.disableExtendedPassive->isChecked()); site->setProperty("disablePASV", m_layout.disablePassive->isChecked()); site->setProperty("pasvSiteIp", m_layout.useSiteIp->isChecked()); site->setProperty("disableForceIp", m_layout.disablePresetIp->isChecked()); site->setProperty("statListings", m_layout.useStat->isChecked()); site->setProperty("disableThreads", m_layout.disableThreads->isChecked()); site->setProperty("encoding", m_layout.encoding->itemData(m_layout.encoding->currentIndex()).toString()); site->setProperty("retryEnabled", m_layout.retry->isChecked()); site->setProperty("retryDelay", m_layout.retryDelay->value()); site->setProperty("retryCount", m_layout.retryCount->value()); site->setProperty("keepaliveEnabled", m_layout.keepalive->isChecked()); site->setProperty("keepaliveFrequency", m_layout.keepaliveFrequency->value()); switch (site->protocol()) { case Site::ProtoFtp: { site->setProperty("sslNegotiationMode", m_layout.sslNegotiationType->currentIndex()); site->setProperty("sslProtMode", m_layout.sslProtMode->currentIndex()); site->setProperty("sslCertificateEnabled", m_layout.sslClientCert->isChecked()); site->setProperty("sslCertificatePath", m_layout.sslCertPath->url().path()); site->setProperty("sslKeyfilePath", m_layout.sslKeyPath->url().path()); break; } case Site::ProtoSftp: { site->setProperty("sshPubkeyAuth", m_layout.sshPubkey->isChecked()); site->setProperty("sshPublicKey", m_layout.sshPublicKey->url().path()); site->setProperty("sshPrivateKey", m_layout.sshPrivateKey->url().path()); break; } } } } void Editor::disableOptions() { m_layout.anonymous->setChecked(false); m_layout.anonymous->setEnabled(false); m_layout.disableExtendedPassive->setChecked(false); m_layout.disableExtendedPassive->setEnabled(false); m_layout.disablePassive->setChecked(false); m_layout.disablePassive->setEnabled(false); m_layout.useSiteIp->setChecked(false); m_layout.useSiteIp->setEnabled(false); m_layout.disablePresetIp->setChecked(false); m_layout.disablePresetIp->setEnabled(false); m_layout.useStat->setChecked(false); m_layout.useStat->setEnabled(false); } void Editor::enableOptions() { m_layout.anonymous->setEnabled(true); m_layout.disableExtendedPassive->setEnabled(true); m_layout.disablePassive->setEnabled(true); m_layout.useSiteIp->setEnabled(true); m_layout.disablePresetIp->setEnabled(true); m_layout.useStat->setEnabled(true); } void Editor::slotCurrentNameChanged(const QString &name) { if (!m_currentIndex.isValid()) return; Site *site = m_currentIndex.data(Model::SiteRole).value(); if (site->isSite()) { // Current name has changed, so let's update the attribute site->setAttribute("name", name); } } void Editor::slotPortChanged() { m_portChanged = true; } void Editor::slotProtocolChanged(int index) { int securityWidget, port = -1; switch (index) { case Site::ProtoFtp: { securityWidget = 1; if (m_layout.port->value() == 22) port = 21; enableOptions(); break; } case Site::ProtoSftp: { securityWidget = 2; if (m_layout.port->value() == 21) port = 22; disableOptions(); break; } default: securityWidget = 0; break; } m_layout.securityStack->setCurrentIndex(securityWidget); if (!m_portChanged && port > 0) { m_layout.port->setValue(port); m_portChanged = false; } } void Editor::slotAnonymousToggled(bool value) { if (value) { m_layout.userName->setEnabled(false); m_layout.password->setEnabled(false); m_layout.userName->setText("anonymous"); if (!KFTPCore::Config::anonMail().isEmpty()) m_layout.password->setText(KFTPCore::Config::anonMail()); else m_layout.password->setText("userlogin@anonymo.us"); } else { m_layout.userName->setEnabled(true); m_layout.password->setEnabled(true); m_layout.userName->clear(); m_layout.password->clear(); } } void Editor::slotSiteRemoved(KFTPBookmarks::Site *site) { if (m_currentIndex.isValid()) { Site *currentSite = m_currentIndex.data(Model::SiteRole).value(); if (site == currentSite) { slotItemClicked(QModelIndex()); m_currentIndex = QModelIndex(); } } } } } #include "editor.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/model.h0000644000175000017500000001044311276037142023103 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_BOOKMARKSMODEL_H #define KFTPWIDGETS_BOOKMARKSMODEL_H #include namespace KFTPBookmarks { class Site; class Manager; } namespace KFTPWidgets { namespace Bookmarks { /** * A bookmarks model that can be used to display a tree of bookmarked * sites and categories. * * @author Jernej Kos */ class Model : public QAbstractItemModel { Q_OBJECT public: enum { TypeRole = Qt::UserRole + 1, SiteRole }; /** * Class constructor. * * @param bookmarks An optional Manager instance * @param parent An optional parent object */ Model(KFTPBookmarks::Manager *bookmarks = 0, QObject *parent = 0); /** * @overload * Reimplemented from QAbstractItemModel. */ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual Qt::ItemFlags flags(const QModelIndex &index) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QModelIndex parent(const QModelIndex &index) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual Qt::DropActions supportedDropActions() const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QStringList mimeTypes() const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QMimeData *mimeData(const QModelIndexList &indexes) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int col, const QModelIndex &parent); /** * Returns the associated bookmark manager. */ KFTPBookmarks::Manager *manager() const { return m_bookmarks; } private: KFTPBookmarks::Manager *m_bookmarks; private slots: void slotSiteAdded(KFTPBookmarks::Site *site); void slotSiteRemoved(KFTPBookmarks::Site *site); void slotSiteChanged(KFTPBookmarks::Site *site); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/model.cpp0000644000175000017500000001555211276037142023444 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "bookmarks/model.h" #include "kftpbookmarks.h" #include using namespace KFTPBookmarks; namespace KFTPWidgets { namespace Bookmarks { Model::Model(KFTPBookmarks::Manager *bookmarks, QObject *parent) : QAbstractItemModel(parent), m_bookmarks(bookmarks) { if (!m_bookmarks) m_bookmarks = Manager::self(); connect(m_bookmarks, SIGNAL(siteAdded(KFTPBookmarks::Site*)), this, SLOT(slotSiteAdded(KFTPBookmarks::Site*))); connect(m_bookmarks, SIGNAL(siteRemoved(KFTPBookmarks::Site*)), this, SLOT(slotSiteRemoved(KFTPBookmarks::Site*))); connect(m_bookmarks, SIGNAL(siteChanged(KFTPBookmarks::Site*)), this, SLOT(slotSiteChanged(KFTPBookmarks::Site*))); } int Model::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) return 1; } QVariant Model::data(const QModelIndex &index, int role) const { if (index.isValid()) { Site *site = static_cast(index.internalPointer()); switch (role) { case Qt::DisplayRole: return site->getAttribute("name"); case Qt::DecorationRole: { switch (site->type()) { case ST_SITE: return KIcon("bookmarks"); case ST_CATEGORY: return KIcon("folder-bookmark"); default: break; } break; } case TypeRole: return site->isCategory() ? 1 : 0; case SiteRole: return QVariant::fromValue(site); } } return QVariant(); } Qt::ItemFlags Model::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::ItemIsDropEnabled; return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } QModelIndex Model::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); Site *parentSite; if (parent.isValid()) parentSite = static_cast(parent.internalPointer()); else parentSite = m_bookmarks->rootSite(); Site *childSite = parentSite->child(row); if (childSite) return createIndex(row, column, childSite); else return QModelIndex(); } QModelIndex Model::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); Site *childSite = static_cast(index.internalPointer()); Site *parentSite = childSite->getParentSite(); if (parentSite->isRoot()) return QModelIndex(); if (parentSite) return createIndex(parentSite->index(), 0, parentSite); return QModelIndex(); } int Model::rowCount(const QModelIndex &parent) const { Site *parentSite; if (parent.column() > 0) return 0; if (!parent.isValid()) parentSite = m_bookmarks->rootSite(); else parentSite = static_cast(parent.internalPointer()); return parentSite->childCount(); } Qt::DropActions Model::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } QStringList Model::mimeTypes() const { QStringList types; types << "application/vnd.text.list"; return types; } QMimeData *Model::mimeData(const QModelIndexList &indexes) const { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); foreach (QModelIndex index, indexes) { if (index.isValid()) { QString id = data(index, SiteRole).value()->id(); stream << id; } } mimeData->setData("application/vnd.text.list", encodedData); return mimeData; } bool Model::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int col, const QModelIndex &parent) { if (action == Qt::IgnoreAction) return true; if (!data->hasFormat("application/vnd.text.list")) return false; if (col > 0) return false; QByteArray encodedData = data->data("application/vnd.text.list"); QDataStream stream(&encodedData, QIODevice::ReadOnly); QStringList siteIds; int rows = 0; while (!stream.atEnd()) { QString id; stream >> id; siteIds << id; rows++; } Site *parentSite; if (parent.isValid()) parentSite = static_cast(parent.internalPointer()); else parentSite = m_bookmarks->rootSite(); if (parentSite->isSite()) parentSite = parentSite->getParentSite(); foreach (QString id, siteIds) { Site *site = m_bookmarks->findSite(id); if (site) parentSite->reparentSite(site); } return true; } void Model::slotSiteAdded(Site *site) { Site *parentSite = site->getParentSite(); QModelIndex parentIndex; if (parentSite->isRoot()) parentIndex = QModelIndex(); else parentIndex = createIndex(parentSite->index(), 0, parentSite); const int rowNumber = site->index(); beginInsertRows(parentIndex, rowNumber, rowNumber); endInsertRows(); } void Model::slotSiteRemoved(Site *site) { Site *parentSite = site->getParentSite(); QModelIndex parentIndex; if (parentSite->isRoot()) parentIndex = QModelIndex(); else parentIndex = createIndex(parentSite->index(), 0, parentSite); const int rowNumber = site->index(); beginRemoveRows(parentIndex, rowNumber, rowNumber); endRemoveRows(); } void Model::slotSiteChanged(Site *site) { QModelIndex itemIndex = createIndex(site->index(), 0, site); emit dataChanged(itemIndex, itemIndex); } } } #include "model.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/sidebar.h0000644000175000017500000000465211276037142023421 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Markus Brueffer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPBOOKMARKSIDEBAR_H #define KFTPBOOKMARKSIDEBAR_H namespace KFTPBookmarks { class Site; } class KAction; class KToolBar; namespace KFTPWidgets { namespace Bookmarks { class ListViewItem; class ListView; /** @author Markus Brueffer */ class Sidebar : public QWidget { Q_OBJECT public: Sidebar(QWidget *parent = 0, const char *name = 0); ~Sidebar(); private: enum BookmarkType { BT_CATEGORY = 0, BT_SERVER }; KToolBar *m_toolBar; ListView *m_tree; KAction *m_editAction; KActionCollection *actionCollection(); public slots: void refresh(); private slots: void slotClicked(Q3ListViewItem*); /* Action slots */ void slotEditAction(); void slotNewAction(ListViewItem *item, KFTPBookmarks::Site *site); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/treeview.h0000644000175000017500000000522211276037142023634 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_BOOKMARKSTREEVIEW_H #define KFTPWIDGETS_BOOKMARKSTREEVIEW_H #include namespace KFTPBookmarks { class Manager; } namespace KFTPWidgets { namespace Bookmarks { /** * A tree view for displaying bookmark entries. Note that this view * can ONLY be used with a Bookmarks::Model model! Using anything * else will result in problems and even crashes. * * @author Jernej Kos */ class TreeView : public QTreeView { Q_OBJECT public: /** * Class constructor. * * @param parent The parent widget */ TreeView(KFTPBookmarks::Manager *manager, QWidget *parent); protected: virtual bool event(QEvent *event); virtual void contextMenuEvent(QContextMenuEvent *event); private: KFTPBookmarks::Manager *m_manager; QModelIndex m_currentIndex; public slots: void slotCreateNewSite(); void slotCreateSubcategory(); void slotRemove(); void slotDuplicate(); private slots: void slotItemSelected(const QModelIndex &index); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/treeview.cpp0000644000175000017500000001164111556266121024173 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "bookmarks/treeview.h" #include "bookmarks/model.h" #include "kftpbookmarks.h" #include #include #include #include #include #include #include #include using namespace KFTPBookmarks; namespace KFTPWidgets { namespace Bookmarks { TreeView::TreeView(Manager *manager, QWidget* parent) : QTreeView(parent), m_manager(manager) { setAcceptDrops(true); setDragEnabled(true); setUniformRowHeights(true); setSelectionMode(QAbstractItemView::SingleSelection); setEditTriggers(QAbstractItemView::NoEditTriggers); setSortingEnabled(true); //setFrameStyle(QFrame::NoFrame); setDragDropMode(QAbstractItemView::InternalMove); setDropIndicatorShown(true); setAutoExpandDelay(300); setRootIsDecorated(true); viewport()->setAttribute(Qt::WA_Hover); connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(slotItemSelected(const QModelIndex&))); } bool TreeView::event(QEvent* event) { if (event->type() == QEvent::Polish) header()->hide(); return QTreeView::event(event); } void TreeView::contextMenuEvent(QContextMenuEvent *event) { m_currentIndex = indexAt(event->pos()); // Show a context menu QMenu menu(this); menu.addAction(KIcon("bookmark-new"), i18n("&Create new site..."), this, SLOT(slotCreateNewSite())); menu.addAction(KIcon("bookmark-folder"), i18n("Create sub&category..."), this, SLOT(slotCreateSubcategory())); if (m_currentIndex.isValid()) { Site *site = m_currentIndex.data(Model::SiteRole).value(); menu.addAction(KIcon("edit-delete"), i18n("&Remove"), this, SLOT(slotRemove())); if (site->isSite()) menu.addAction(KIcon("edit-copy"), i18n("&Duplicate site"), this, SLOT(slotDuplicate())); } menu.exec(event->globalPos()); } void TreeView::slotItemSelected(const QModelIndex &index) { m_currentIndex = index; } void TreeView::slotCreateNewSite() { Site *parentSite; if (m_currentIndex.isValid()) parentSite = m_currentIndex.data(Model::SiteRole).value(); else parentSite = m_manager->rootSite(); if (parentSite->isSite()) parentSite = parentSite->getParentSite(); Site *site = parentSite->addSite(KInputDialog::getText(i18n("Create site"), i18n("Name"))); m_currentIndex = model()->index(site->index(), 0, m_currentIndex); setCurrentIndex(m_currentIndex); emit clicked(m_currentIndex); } void TreeView::slotCreateSubcategory() { Site *parentSite; if (m_currentIndex.isValid()) parentSite = m_currentIndex.data(Model::SiteRole).value(); else parentSite = m_manager->rootSite(); if (parentSite->isSite()) parentSite = parentSite->getParentSite(); parentSite->addCategory(KInputDialog::getText(i18n("Create subcategory"), i18n("Name"))); } void TreeView::slotRemove() { if (KMessageBox::warningYesNo(this, i18n("Are you sure you wish to remove this site or category?")) != KMessageBox::Yes) return; Site *site = m_currentIndex.data(Model::SiteRole).value(); m_manager->removeSite(site); m_currentIndex = QModelIndex(); setCurrentIndex(m_currentIndex); } void TreeView::slotDuplicate() { Site *site = m_currentIndex.data(Model::SiteRole).value(); site->duplicate(); } } } #include "treeview.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/bookmarks/CMakeLists.txt0000644000175000017500000000103711276037142024371 0ustar michaelmichaelINCLUDE_DIRECTORIES( .. ../.. ../../misc ${CMAKE_CURRENT_BINARY_DIR}/../.. ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(bookmarkwidgets_SRCS model.cpp treeview.cpp #bookmarksdelegate.cpp editor.cpp ) SET(bookmarkwidgets_UI editor.ui ) kde4_add_ui_files(bookmarkwidgets_SRCS ${bookmarkwidgets_UI}) kde4_add_library(bookmarkwidgets STATIC ${bookmarkwidgets_SRCS}) add_dependencies(bookmarkwidgets widgets) kftpgrabber-0.8.99~svn1214766/src/widgets/logview.cpp0000644000175000017500000001133611276037142022024 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2008 by the KFTPGrabber developers * Copyright (C) 2003-2008 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "logview.h" #include "misc/config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace KFTPWidgets { LogView::LogView(QWidget *parent) : QPlainTextEdit(parent) { setReadOnly(true); setMaximumBlockCount(200); setCenterOnScroll(true); setFrameStyle(QFrame::NoFrame); // Init actions m_saveToFileAction = KStandardAction::saveAs(this, SLOT(slotSaveToFile()), this); m_clearLogAction = KStandardAction::clear(this, SLOT(clear()), this); } LogView::~LogView() { } void LogView::append(const QString &str, LineType type) { switch (type) { case FtpResponse: { // Break response into code and text to format them differently QString prefix = str.section(" ", 0, 0); QString text = str.mid(str.indexOf(' ')); appendHtml(QString("%2 %3
").arg(KFTPCore::Config::logResponsesColor().name()) .arg(prefix) .arg(text)); break; } case FtpCommand: { // Hide password if this is a PASS command QString text = str; if (text.left(4) == "PASS") text = "PASS (hidden)"; appendHtml(QString("%2
").arg(KFTPCore::Config::logCommandsColor().name()) .arg(text)); break; } case FtpMultiline: { appendHtml(QString("%2
").arg(KFTPCore::Config::logMultilineColor().name()) .arg(str)); break; } case FtpStatus: { appendHtml(QString("*** %2
").arg(KFTPCore::Config::logStatusColor().name()) .arg(str)); break; } case FtpError: { appendHtml(QString("*** %2
").arg(KFTPCore::Config::logErrorColor().name()) .arg(str)); break; } case Plain: { appendHtml(QString("%1
").arg(str)); break; } } } void LogView::contextMenuEvent(QContextMenuEvent *event) { QMenu menu; menu.addAction(m_saveToFileAction); menu.addSeparator(); menu.addAction(m_clearLogAction); menu.exec(event->globalPos()); } void LogView::slotSaveToFile() { QString savePath = KFileDialog::getSaveFileName(KUrl(), "*.txt"); if (!savePath.isEmpty()) { QFile file(savePath); if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); stream << toPlainText(); file.close(); } else { KMessageBox::error(0L, i18n("Unable to open file for writing.")); } } } } #include "logview.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/verifier.cpp0000644000175000017500000001140311276037142022156 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "verifier.h" #include "listviewitem.h" #include #include #include #include #include #include namespace KFTPWidgets { Verifier::Verifier(QWidget *parent) : KDialog(parent), m_verifier(0) { //, name, true, i18n("Checksum verifier"), Cancel, Cancel, true QWidget *widget = new QWidget(this); ui.setupUi(widget); setMainWidget(widget); // Create columns ui.fileList->addColumn(i18n("Filename")); ui.fileList->addColumn(i18n("Checksum"), 100); ui.fileList->setAllColumnsShowFocus(true); ui.fileList->header()->setStretchEnabled(true, 0); } Verifier::~Verifier() { delete m_verifier; } void Verifier::setFile(const QString &filename) { // Create the verifier m_verifier = new KFTPCore::ChecksumVerifier(filename); ui.currentFile->setText(KUrl(filename).fileName()); connect(m_verifier, SIGNAL(fileList(QList >)), this, SLOT(slotHaveFileList(QList >))); connect(m_verifier, SIGNAL(fileDone(const QString&, KFTPCore::ChecksumVerifier::Result)), this, SLOT(slotFileDone(const QString&, KFTPCore::ChecksumVerifier::Result))); connect(m_verifier, SIGNAL(progress(int)), this, SLOT(slotProgress(int))); connect(m_verifier, SIGNAL(error()), this, SLOT(slotError())); // Start the verification m_verifier->verify(); } void Verifier::slotHaveFileList(QList > list) { for (QList >::iterator i = list.begin(); i != list.end(); ++i) { KFTPWidgets::ListViewItem *item = new KFTPWidgets::ListViewItem(ui.fileList); item->setText(0, (*i).first); item->setText(1, (*i).second); } } void Verifier::slotFileDone(const QString &filename, KFTPCore::ChecksumVerifier::Result result) { KFTPWidgets::ListViewItem *item = static_cast(ui.fileList->findItem(filename, 0)); if (item) { switch (result) { case KFTPCore::ChecksumVerifier::Ok: { //item->setPixmap(0, loadSmallPixmap("dialog-ok")); // "ok" icon should probably be "dialog-success", but we don't have that icon in KDE 4.0 item->setTextColor(0, QColor(0, 200, 0)); item->setTextColor(1, QColor(0, 200, 0)); break; } case KFTPCore::ChecksumVerifier::NotFound: { //item->setPixmap(0, loadSmallPixmap("dialog-error")); item->setTextColor(0, QColor(128, 128, 128)); item->setTextColor(1, QColor(128, 128, 128)); break; } case KFTPCore::ChecksumVerifier::Error: { //item->setPixmap(0, loadSmallPixmap("dialog-error")); item->setTextColor(0, QColor(255, 0, 0)); item->setTextColor(1, QColor(255, 0, 0)); break; } } ui.fileList->ensureItemVisible(item); } } void Verifier::slotProgress(int percent) { ui.checkProgress->setValue(percent); if (percent == 100) { KMessageBox::information(0, i18n("Verification complete.")); } } void Verifier::slotError() { KMessageBox::error(0, i18n("Unable to open checksum file, or file has an incorrect format.")); close(); } } #include "verifier.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/fingerprintverifydialog.ui0000644000175000017500000000762511276037142025145 0ustar michaelmichael FingerprintVerifyDialog 0 0 393 173 0 0 0 0 48 48 Qt::Vertical 20 171 <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600; color:#ff0000;">SECURITY WARNING</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; color:#ff0000;"><span style=" font-weight:400; color:#000000;">The fingerprint of the server you are connecting to cannot be verified. Please check that the fingerprint below is authentic.</span></p></body></html> true 0 0 Fingerprint 5 5 5 5 <b>missing_fingerprint</b> Qt::RichText Qt::AlignCenter Qt::Vertical 20 40 kftpgrabber-0.8.99~svn1214766/src/widgets/listviewitem.h0000644000175000017500000000465611276037142022551 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETSLISTVIEWITEM_H #define KFTPWIDGETSLISTVIEWITEM_H #include #include #include #include namespace KFTPWidgets { /** * This class is a simple QListViewItem replacement that supports displaying * richtext. * * @author Jernej Kos */ class ListViewItem : public K3ListViewItem { public: ListViewItem(Q3ListView *parent); void setRichText(int col, const QString &text); QString richText(int col) { return m_richText[col]; } void setTextColor(int col, QColor color) { m_colors[col] = color; } void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment); void setup(); private: QMap m_richText; QMap m_colors; }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/zeroconflistview.cpp0000644000175000017500000000623211276037142023763 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "zeroconflistview.h" #include "kftpsession.h" #include "misc/zeroconf.h" #include #include #include namespace KFTPWidgets { ZeroConfListView::ZeroConfListView(QWidget *parent) : ListView(parent) { // Set some stuff setMinimumWidth(150); setFullWidth(true); addColumn(i18n("Sites Near You")); setRootIsDecorated(true); setEmptyListText(i18n("No sites published.")); setItemsRenameable(false); connect(KFTPCore::ZeroConf::self(), SIGNAL(servicesUpdated()), this, SLOT(slotSitesChanged())); connect(this, SIGNAL(executed(Q3ListViewItem*)), this, SLOT(slotSiteExecuted(Q3ListViewItem*))); slotSitesChanged(); } void ZeroConfListView::slotSitesChanged() { // Update the site list QList list = KFTPCore::ZeroConf::self()->getServiceList(); clear(); if (!list.isEmpty()) { QList::iterator end(list.end()); for (QList::iterator i(list.begin()); i != end; ++i) { QString name = (*i)->serviceName(); QString ip = (*i)->hostName(); QString port = QString::number((*i)->port()); K3ListViewItem *site = new K3ListViewItem(this, name, ip, port); site->setPixmap(0, SmallIcon("lan")); } } } void ZeroConfListView::slotSiteExecuted(Q3ListViewItem *item) { // Connect to the site //KFTPAPI::getInstance()->mainWindow()->slotQuickConnect(item->text(0), item->text(1), item->text(2).toInt()); } } #include "zeroconflistview.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/listview.cpp0000644000175000017500000000530411276037142022214 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "listview.h" #include #include //Added by qt3to4: #include namespace KFTPWidgets { ListView::ListView(QWidget *parent) : K3ListView(parent) { } ListView::~ListView() { } void ListView::resizeEvent(QResizeEvent *e) { K3ListView::resizeEvent(e); triggerUpdate(); } void ListView::setEmptyListText(const QString &text) { m_emptyListText = text; triggerUpdate(); } void ListView::drawContentsOffset(QPainter * p, int ox, int oy, int cx, int cy, int cw, int ch) { K3ListView::drawContentsOffset(p, ox, oy, cx, cy, cw, ch); if (childCount() == 0 && !m_emptyListText.isEmpty()) { p->setPen(Qt::darkGray); QStringList lines = m_emptyListText.split("\n"); int ypos = 10 + p->fontMetrics().height(); QStringList::Iterator end(lines.end()); for (QStringList::Iterator str( lines.begin() ); str != end; ++str) { p->drawText((viewport()->width()/2)-(p->fontMetrics().width(*str)/2), ypos, *str); ypos += p->fontMetrics().lineSpacing(); } } } } #include "listview.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/popupmessage.cpp0000644000175000017500000001543311276037142023062 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * Copyright (C) 2005 Max Howell * Copyright (C) 2005 Seb Ruiz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "popupmessage.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace KFTPWidgets { PopupMessage::PopupMessage(QWidget *parent, QWidget *anchor, int timeout) : OverlayWidget(parent, anchor), m_anchor(anchor), m_parent(parent), m_maskEffect(Slide), m_dissolveSize(0), m_dissolveDelta(-1), m_offset(0), m_counter(0), m_stage(1), m_timeout(timeout) { setFrameStyle(QFrame::StyledPanel); setWindowFlags(Qt::WX11BypassWM); setMinimumSize(360, 78); QPalette p = QToolTip::palette(); setPalette(p); setAutoFillBackground(true); QHBoxLayout *hbox; QLabel *label; QLabel *alabel; m_layout = new QVBoxLayout(this); m_layout->setMargin(5); m_layout->setSpacing(5); hbox = new QHBoxLayout(); hbox->setParent(m_layout); hbox->setSpacing(12); m_layout->addLayout(hbox); // Setup the icon widget m_icon = new QLabel(this); hbox->addWidget(m_icon); // Setup the text widget m_text = new QLabel(this); m_text->setTextFormat(Qt::RichText); m_text->setWordWrap(true); m_text->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); m_text->setPalette(p); hbox->addWidget(m_text); hbox = new QHBoxLayout(); hbox->setParent(m_layout); hbox->addItem(new QSpacerItem(4, 4, QSizePolicy::Expanding, QSizePolicy::Preferred)); m_layout->addLayout(hbox); m_close = new KPushButton(KStandardGuiItem::close(), this); hbox->addWidget(m_close); connect(m_close, SIGNAL(clicked()), SLOT(close())); } void PopupMessage::addWidget(QWidget *widget) { m_layout->addWidget(widget); adjustSize(); } void PopupMessage::setShowCloseButton(bool show) { m_close->setVisible(show); adjustSize(); } void PopupMessage::setText(const QString &text) { m_text->setText(text); adjustSize(); } void PopupMessage::setImage(const QString &location) { m_icon->setPixmap(QPixmap(location)); adjustSize(); } void PopupMessage::setImage(const QPixmap &pix) { m_icon->setPixmap(pix); adjustSize(); } void PopupMessage::close() { m_stage = 3; killTimer(m_timerId); m_timerId = startTimer(6); } void PopupMessage::display() { m_dissolveSize = 24; m_dissolveDelta = -1; if (m_maskEffect == Dissolve) { m_mask = QPixmap(width(), height()); dissolveMask(); m_timerId = startTimer(1000 / 30); } else { m_timerId = startTimer( 6 ); } show(); } void PopupMessage::timerEvent(QTimerEvent*) { switch(m_maskEffect) { case Plain: plainMask(); break; case Slide: slideMask(); break; case Dissolve: dissolveMask(); break; } } void PopupMessage::countDown() { if (!m_timeout) { killTimer(m_timerId); return; } if (!testAttribute(Qt::WA_UnderMouse)) m_counter++; if (m_counter > 20) { m_stage = 3; killTimer(m_timerId); m_timerId = startTimer(6); } else { killTimer(m_timerId); m_timerId = startTimer(m_timeout / 20); } } void PopupMessage::dissolveMask() { if (m_stage == 1) { repaint(); QPainter maskPainter(&m_mask); m_mask.fill(Qt::black); maskPainter.setBrush(Qt::white); maskPainter.setPen(Qt::white); maskPainter.drawRect(m_mask.rect()); m_dissolveSize += m_dissolveDelta; if (m_dissolveSize > 0) { maskPainter.setCompositionMode(QPainter::CompositionMode_SourceOut); int x, y, s; const int size = 16; for (y = 0; y < height() + size; y += size) { x = width(); s = m_dissolveSize * x / 128; for (; x > size; x -= size, s -= 2) { if (s < 0) break; maskPainter.drawEllipse(x - s / 2, y - s / 2, s, s); } } } else if (m_dissolveSize < 0) { m_dissolveDelta = 1; killTimer(m_timerId); if (m_timeout) { m_timerId = startTimer(40); m_stage = 2; } } setMask(m_mask); } else if (m_stage == 2) { countDown(); } else { deleteLater(); } } void PopupMessage::plainMask() { switch (m_stage) { case 1: { // Raise killTimer(m_timerId); if (m_timeout) { m_timerId = startTimer(40); m_stage = 2; } break; } case 2: { // Counter countDown(); break; } case 3: { // Lower/Remove deleteLater(); break; } } } void PopupMessage::slideMask() { switch (m_stage) { case 1: { // Raise move(0, m_parent->y() - m_offset); m_offset++; if (m_offset > height()) { killTimer(m_timerId); if (m_timeout) { m_timerId = startTimer(40); m_stage = 2; } } break; } case 2: { // Fill in pause timer bar countDown(); break; } case 3: { // Lower m_offset--; move(0, m_parent->y() - m_offset); if (m_offset < 0) deleteLater(); } } } } #include "popupmessage.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/0000755000175000017500000000000011276037142021657 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/widgets/queueview/delegate.cpp0000644000175000017500000000515511276037142024143 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "queueview/delegate.h" #include "queueview/model.h" #include "kftpqueue.h" #include #include using namespace KFTPQueue; namespace KFTPWidgets { namespace Queue { Delegate::Delegate(QObject *parent) : QItemDelegate(parent) { } void Delegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QItemDelegate::paint(painter, option, index); // Retrieve the object and do some drawing QueueObject *object = index.data(Model::ObjectRole).value(); if (index.column() == Model::Progress) { if (object->isRunning()) { // Draw the progress bar only if transfer has already started QStyleOptionProgressBar p; p.minimum = 0; p.maximum = 100; p.rect = option.rect; p.progress = object->getProgress().first; p.textVisible = false; QApplication::style()->drawControl(QStyle::CE_ProgressBar, &p, painter, 0); } } } } } kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/queueview.h0000644000175000017500000000633111276037142024052 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * Copyright (C) 2005 Markus Brueffer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUEVIEW_H #define KFTPQUEUEVIEW_H #include class KToolBar; class KAction; namespace KFTPWidgets { namespace Queue { class TreeView; } /** * A widget for displaying and manipulating the current queue. * * @author Jernej Kos */ class QueueView : public QWidget { Q_OBJECT public: /** * Class constructor. */ QueueView(QWidget *parent); /** * Load queue list layout from the configuration file. */ void loadLayout(); /** * Save queue list layout to the configuration file. */ void saveLayout(); public slots: void updateActions(); protected: /** * Initialize actions. */ void initActions(); /** * Initialize toolbar widgets. */ void initToolBar(); private: // Toolbar Actions KAction *m_loadAction; KAction *m_saveAction; KAction *m_startAction; KAction *m_pauseAction; KAction *m_stopAction; KAction *m_addAction; KAction *m_searchAction; KAction *m_filterAction; //K3ListViewSearchLine *m_searchField; KToolBar *m_toolBar; KToolBar *m_searchToolBar; Queue::TreeView *m_tree; private slots: // Slots for actions void slotLoad(); void slotSave(); void slotStart(); void slotPause(); void slotStop(); void slotAdd(); void slotSearch(); void slotFilter(); void slotDownloadLimitChanged(int value); void slotUploadLimitChanged(int value); void slotThreadCountChanged(int value); }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/delegate.h0000644000175000017500000000413611276037142023606 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_QUEUEDELEGATE_H #define KFTPWIDGETS_QUEUEDELEGATE_H #include namespace KFTPWidgets { namespace Queue { class Delegate : public QItemDelegate { public: /** * Class constructor. */ Delegate(QObject *parent = 0); /** * @overload * Paints the cell contents. */ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/threadview.h0000644000175000017500000000535511276037142024202 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPTHREADVIEW_H #define KFTPTHREADVIEW_H #include #include #include #include "kftpsession.h" namespace KFTPWidgets { class ListView; class ThreadViewItem : public QObject, public Q3ListViewItem { Q_OBJECT public: ThreadViewItem(KFTPSession::Session *session, Q3ListView *parent); ThreadViewItem(KFTPSession::Connection *conn, Q3ListViewItem *parent, int id); void refresh(); virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment); private: int m_id; QPointer m_connection; QPointer m_session; private slots: void slotConnectionAcquired(); void slotUpdateItemRequested(); }; /** * This widget shows all the currently used threads in KFTPGrabber transfers. * * @author Jernej Kos */ class ThreadView : public QWidget { Q_OBJECT public: ThreadView(QWidget *parent = 0, const char *name = 0); ~ThreadView(); private slots: void slotUpdateSessions(); private: KFTPWidgets::ListView *m_threads; }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/model.h0000644000175000017500000000734411276037142023140 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_QUEUEMODEL_H #define KFTPWIDGETS_QUEUEMODEL_H #include namespace KFTPQueue { class QueueObject; } namespace KFTPWidgets { namespace Queue { /** * A queue model that can be used to display the current queue. * * @author Jernej Kos */ class Model : public QAbstractItemModel { Q_OBJECT public: /** * Additional index roles. */ enum { TypeRole = Qt::UserRole + 1, ObjectRole }; /** * Default model columns. */ enum ModelColumns { Name = 0, Size, Source, Destination, Progress, Speed, ETA, ColumnCount }; /** * Class constructor. * * @param parent An optional parent object */ Model(QObject *parent = 0); /** * @overload * Reimplemented from QAbstractItemModel. */ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QModelIndex parent(const QModelIndex &index) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; private slots: void slotObjectAdded(KFTPQueue::QueueObject *object); void slotObjectRemoved(KFTPQueue::QueueObject *object); void slotObjectChanged(KFTPQueue::QueueObject *object); void slotObjectBeforeRemoval(KFTPQueue::QueueObject *object); void slotObjectAfterRemoval(); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/model.cpp0000644000175000017500000002170211276037142023465 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "queueview/model.h" #include "queueobject.h" #include "kftptransfer.h" #include "kftpqueue.h" #include "site.h" #include #include using namespace KFTPQueue; namespace KFTPWidgets { namespace Queue { Model::Model(QObject *parent) : QAbstractItemModel(parent) { connect(Manager::self(), SIGNAL(objectAdded(KFTPQueue::QueueObject*)), this, SLOT(slotObjectAdded(KFTPQueue::QueueObject*))); connect(Manager::self(), SIGNAL(objectRemoved(KFTPQueue::QueueObject*)), this, SLOT(slotObjectRemoved(KFTPQueue::QueueObject*))); connect(Manager::self(), SIGNAL(objectChanged(KFTPQueue::QueueObject*)), this, SLOT(slotObjectChanged(KFTPQueue::QueueObject*))); connect(Manager::self(), SIGNAL(objectBeforeRemoval(KFTPQueue::QueueObject*)), this, SLOT(slotObjectBeforeRemoval(KFTPQueue::QueueObject*))); connect(Manager::self(), SIGNAL(objectAfterRemoval()), this, SLOT(slotObjectAfterRemoval())); } int Model::columnCount(const QModelIndex&) const { return ColumnCount; } QVariant Model::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(orientation); switch (role) { case Qt::DisplayRole: { switch (section) { case Name: return i18n("Name"); case Size: return i18n("Size"); case Source: return i18n("Source"); case Destination: return i18n("Destination"); case Progress: return i18n("Progress"); case Speed: return i18n("Speed"); case ETA: return i18n("ETA"); } } } return QVariant(); } QVariant Model::data(const QModelIndex &index, int role) const { if (index.isValid()) { QueueObject *object = static_cast(index.internalPointer()); Transfer *transfer = static_cast(object); Site *site = static_cast(object); switch (role) { case Qt::DisplayRole: { if (index.column() == Name) { switch (object->getType()) { case QueueObject::Site: return site->getUrl().host(); case QueueObject::Directory: case QueueObject::File: return transfer->getSourceUrl().fileName(); default: break; } } else if (index.column() == Size) { return KIO::convertSize(object->getActualSize()); } else if (object->isRunning()) { switch (index.column()) { case ETA: return KIO::convertSeconds(KIO::calculateRemainingSeconds(object->getSize(), object->getCompleted(), object->getSpeed())); case Speed: return QString("%1/s").arg(KIO::convertSize(object->getSpeed())); } } if (object->isTransfer()) { switch (index.column()) { case Source: return transfer->getSourceUrl().pathOrUrl(); case Destination: return transfer->getDestUrl().pathOrUrl(); case Progress: { if (object->isDir() && object->isLocked()) { return i18n("Scanning..."); } else if (object->isConnecting()) { return i18n("Connecting..."); } else if (object->isWaiting()) { return i18n("Waiting..."); } else if (object->isRunning()) { return QString("%1 %%").arg(object->getProgress().first); } break; } } } break; } case Qt::DecorationRole: { if (index.column() == Name) { switch (object->getType()) { case QueueObject::Site: return KIcon("network-server"); case QueueObject::Directory: return KIcon("folder"); case QueueObject::File: return KIcon("txt"); // FIXME depending on the mimetype + cache! default: break; } } break; } case Qt::FontRole: { if (index.column() == Name && object->isSite()) { QFont font; font.setBold(true); return font; } else if (index.column() == Progress && object->isDir() && object->isLocked()) { QFont font; font.setBold(true); return font; } else if (index.column() == Progress && (object->isConnecting() || object->isWaiting())) { QFont font; font.setBold(true); return font; } break; } case Qt::ForegroundRole: { if (object->isDir() && object->isLocked()) { // A directory scan is in progress return QColor(Qt::darkGreen); } else if (object->isConnecting() || object->isWaiting()) { // Object is connecting or waiting for a free connection return QColor(Qt::darkBlue); } break; } case ObjectRole: return QVariant::fromValue(object); default: break; } } return QVariant(); } QModelIndex Model::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); QueueObject *parentObject; if (parent.isValid()) parentObject = static_cast(parent.internalPointer()); else parentObject = Manager::self()->topLevelObject(); QueueObject *childObject = parentObject->getChildAt(row); if (childObject) return createIndex(row, column, childObject); else return QModelIndex(); } QModelIndex Model::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); QueueObject *childObject = static_cast(index.internalPointer()); QueueObject *parentObject = childObject->parentObject(); if (parentObject && !parentObject->isToplevel()) return createIndex(parentObject->index(), 0, parentObject); return QModelIndex(); } int Model::rowCount(const QModelIndex &parent) const { QueueObject *parentObject; if (parent.column() > 0) return 0; if (!parent.isValid()) parentObject = Manager::self()->topLevelObject(); else parentObject = static_cast(parent.internalPointer()); return parentObject->childCount(); } void Model::slotObjectAdded(QueueObject *object) { QueueObject *parentObject = object->parentObject(); QModelIndex parentIndex; if (parentObject->isToplevel()) parentIndex = QModelIndex(); else parentIndex = createIndex(parentObject->index(), 0, parentObject); const int rowNumber = object->index(); beginInsertRows(parentIndex, rowNumber, rowNumber); endInsertRows(); } void Model::slotObjectRemoved(QueueObject *object) { slotObjectBeforeRemoval(object); slotObjectAfterRemoval(); } void Model::slotObjectBeforeRemoval(KFTPQueue::QueueObject *object) { QueueObject *parentObject = object->parentObject(); QModelIndex parentIndex; if (parentObject->isToplevel()) parentIndex = QModelIndex(); else parentIndex = createIndex(parentObject->index(), 0, parentObject); const int rowNumber = object->index(); beginRemoveRows(parentIndex, rowNumber, rowNumber); } void Model::slotObjectAfterRemoval() { endRemoveRows(); } void Model::slotObjectChanged(QueueObject *object) { QModelIndex startIndex = createIndex(object->index(), 0, object); QModelIndex endIndex = createIndex(object->index(), ColumnCount - 1, object); emit dataChanged(startIndex, endIndex); } } } #include "model.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/queueeditor.cpp0000644000175000017500000002422211276037142024720 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "queueeditor.h" //Added by qt3to4: #include #include "kftpserverlineedit.h" #include "kftpbookmarks.h" #include "kftpqueueeditorlayout.h" #include #include #include #include #include #include #include #include #define REMOTE_PROTOCOL m_transfer->getSourceUrl().isLocalFile() ? m_transfer->getDestUrl().protocol() : m_transfer->getSourceUrl().protocol() namespace KFTPWidgets { QueueEditor::QueueEditor(QWidget *parent, const char *name) : KDialogBase(parent, name, true, "Edit queue", KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok, true) { m_layout = new KFTPQueueEditorLayout(this); setMainWidget(m_layout); connect(m_layout->srcPath, SIGNAL(textChanged(const QString&)), this, SLOT(slotTextChanged())); connect(m_layout->dstPath, SIGNAL(textChanged(const QString&)), this, SLOT(slotTextChanged())); connect(m_layout->srcHost, SIGNAL(textChanged(const QString&)), this, SLOT(slotTextChanged())); connect(m_layout->srcUser, SIGNAL(textChanged(const QString&)), this, SLOT(slotTextChanged())); connect(m_layout->srcPass, SIGNAL(textChanged(const QString&)), this, SLOT(slotTextChanged())); connect(m_layout->dstHost, SIGNAL(textChanged(const QString&)), this, SLOT(slotTextChanged())); connect(m_layout->dstUser, SIGNAL(textChanged(const QString&)), this, SLOT(slotTextChanged())); connect(m_layout->dstPass, SIGNAL(textChanged(const QString&)), this, SLOT(slotTextChanged())); connect(m_layout->srcName, SIGNAL(siteChanged(KFTPBookmarks::Site*)), this, SLOT(slotSourceSiteChanged(KFTPBookmarks::Site*))); connect(m_layout->dstName, SIGNAL(siteChanged(KFTPBookmarks::Site*)), this, SLOT(slotDestSiteChanged(KFTPBookmarks::Site*))); connect(m_layout->transferType, SIGNAL(activated(int)), this, SLOT(slotTransferModeChanged(int))); setMaximumHeight(250); setInitialSize(QSize(500, 250)); enableButtonOk(false); } void QueueEditor::resetTabs() { m_layout->serverTab->setTabEnabled(m_layout->tab, false); m_layout->serverTab->setTabEnabled(m_layout->tab_2, false); } void QueueEditor::resetServerData() { // Source m_layout->srcName->clear(); m_layout->srcHost->setText(""); m_layout->srcPort->setValue(21); m_layout->srcUser->setText(""); m_layout->srcPass->erase(); // Destination m_layout->dstName->clear(); m_layout->dstHost->setText(""); m_layout->dstPort->setValue(21); m_layout->dstUser->setText(""); m_layout->dstPass->erase(); } void QueueEditor::slotTransferModeChanged(int index) { if (m_lastTransferType == index) return; else m_lastTransferType = (KFTPQueue::TransferType) index; resetTabs(); resetServerData(); switch (index) { case 0: { // Download - source: remote dest: local m_layout->serverTab->setTabEnabled(m_layout->tab, true); m_layout->serverTab->showPage(m_layout->tab); break; } case 1: { // Upload - source: local dest: remote m_layout->serverTab->setTabEnabled(m_layout->tab_2, true); m_layout->serverTab->showPage(m_layout->tab_2); break; } case 2: { // FXP - source: remote dest: remote m_layout->serverTab->setTabEnabled(m_layout->tab, true); m_layout->serverTab->setTabEnabled(m_layout->tab_2, true); m_layout->serverTab->showPage(m_layout->tab); break; } } slotTextChanged(); } bool QueueEditor::sourceIsValid() { if (m_lastTransferType == 1) return true; if (m_layout->srcHost->text().trimmed().isEmpty() || m_layout->srcUser->text().trimmed().isEmpty()) return false; else return true; } bool QueueEditor::destIsValid() { if (m_lastTransferType == 0) return true; if (m_layout->dstHost->text().trimmed().isEmpty() || m_layout->dstUser->text().trimmed().isEmpty()) return false; else return true; } void QueueEditor::slotTextChanged() { if (m_layout->srcPath->text().trimmed().isEmpty() || m_layout->dstPath->text().trimmed().isEmpty() || m_layout->srcPath->text().left(1) != "/" || m_layout->dstPath->text().left(1) != "/" || !sourceIsValid() || !destIsValid() ) enableButtonOk(false); else enableButtonOk(true); } void QueueEditor::setData(KFTPQueue::Transfer *transfer) { KUrl sUrl, dUrl; m_layout->srcPath->setText(transfer->getSourceUrl().path()); m_layout->dstPath->setText(transfer->getDestUrl().path()); // Source sUrl = transfer->getSourceUrl(); if (!sUrl.isLocalFile()) { m_layout->srcName->setCurrentSite(KFTPBookmarks::Manager::self()->findSite(sUrl)); m_layout->srcHost->setText(sUrl.host()); m_layout->srcPort->setValue(sUrl.port()); m_layout->srcUser->setText(sUrl.user()); m_layout->srcPass->erase(); m_layout->srcPass->insert(sUrl.pass()); } else { m_layout->serverTab->setTabEnabled(m_layout->tab, false); } // Destination dUrl = transfer->getDestUrl(); if (!dUrl.isLocalFile()) { m_layout->dstName->setCurrentSite(KFTPBookmarks::Manager::self()->findSite(dUrl)); m_layout->dstHost->setText(dUrl.host()); m_layout->dstPort->setValue(dUrl.port()); m_layout->dstUser->setText(dUrl.user()); m_layout->dstPass->erase(); m_layout->dstPass->insert(dUrl.pass()); } else { m_layout->serverTab->setTabEnabled(m_layout->tab_2, false); } // Transfer type m_lastTransferType = transfer->getTransferType(); m_layout->transferType->setCurrentItem(m_lastTransferType); m_transfer = transfer; } void QueueEditor::saveData() { KUrl sUrl, dUrl; if (m_lastTransferType != 1) { sUrl.setProtocol(REMOTE_PROTOCOL); sUrl.setHost(m_layout->srcHost->text()); sUrl.setPort(m_layout->srcPort->value()); sUrl.setUser(m_layout->srcUser->text()); sUrl.setPass(m_layout->srcPass->password()); if (m_transfer->getSourceUrl().pass().isEmpty() && sUrl.pass().isEmpty()) sUrl.setPass(QString::null); } else { sUrl.setProtocol("file"); } sUrl.setPath(m_layout->srcPath->text()); if (m_lastTransferType != 0) { dUrl.setProtocol(REMOTE_PROTOCOL); dUrl.setHost(m_layout->dstHost->text()); dUrl.setPort(m_layout->dstPort->value()); dUrl.setUser(m_layout->dstUser->text()); dUrl.setPass(m_layout->dstPass->password()); if (m_transfer->getDestUrl().pass().isEmpty() && dUrl.pass().isEmpty()) dUrl.setPass(QString::null); } else { dUrl.setProtocol("file"); } dUrl.setPath(m_layout->dstPath->text()); m_transfer->setSourceUrl(sUrl); m_transfer->setDestUrl(dUrl); m_transfer->setTransferType(m_lastTransferType); // If the transfer is a directory, we have to update all child transfers // as well. if (m_transfer->isDir()) recursiveSaveData(static_cast(m_transfer), sUrl, dUrl); } void QueueEditor::recursiveSaveData(KFTPQueue::TransferDir *parent, const KUrl &srcUrl, const KUrl &dstUrl) { KFTPQueue::QueueObject *o; Q3PtrList children = parent->getChildrenList(); KUrl sUrl, dUrl; for (o = children.first(); o; o = children.next()) { KFTPQueue::Transfer *i = static_cast(o); // Modify the urls sUrl = srcUrl; dUrl = dstUrl; sUrl.addPath(i->getSourceUrl().fileName()); dUrl.addPath(i->getDestUrl().fileName()); // Set the urls i->setSourceUrl(sUrl); i->setDestUrl(dUrl); i->setTransferType(m_lastTransferType); i->emitUpdate(); if (i->isDir()) recursiveSaveData(static_cast(i), sUrl, dUrl); } } void QueueEditor::slotSourceSiteChanged(KFTPBookmarks::Site *site) { if (site) { m_layout->srcHost->setText(site->getProperty("host")); m_layout->srcPort->setValue(site->getIntProperty("port")); m_layout->srcUser->setText(site->getProperty("username")); m_layout->srcPass->erase(); m_layout->srcPass->insert(site->getProperty("password")); } else { m_layout->srcHost->clear(); m_layout->srcPort->setValue(21); m_layout->srcUser->clear(); m_layout->srcPass->erase(); } } void QueueEditor::slotDestSiteChanged(KFTPBookmarks::Site *site) { if (site) { m_layout->dstHost->setText(site->getProperty("host")); m_layout->dstPort->setValue(site->getIntProperty("port")); m_layout->dstUser->setText(site->getProperty("username")); m_layout->dstPass->erase(); m_layout->dstPass->insert(site->getProperty("password")); } else { m_layout->dstHost->clear(); m_layout->dstPort->setValue(21); m_layout->dstUser->clear(); m_layout->dstPass->erase(); } } } #include "queueeditor.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/treeview.h0000644000175000017500000000662611276037142023674 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_QUEUETREEVIEW_H #define KFTPWIDGETS_QUEUETREEVIEW_H #include namespace KFTPWidgets { namespace Queue { /** * A tree view for displaying the queue hierarchy. Note that this view * can ONLY be used with a Queue::Model model! Using anything else * will result in problems and even crashes. * * @author Jernej Kos */ class TreeView : public QTreeView { Q_OBJECT public: /** * Class constructor. * * @param parent The parent widget */ TreeView(QWidget *parent); /** * @overload * Reimplemented from QTreeView. */ void setModel(QAbstractItemModel *model); private slots: /** * Ensures that all sites are expanded as items are added as their * children. * * @param parent Parent item index */ void expandSite(const QModelIndex &parent); protected: virtual bool event(QEvent *event); virtual void contextMenuEvent(QContextMenuEvent *event); private: QModelIndex m_currentIndex; private slots: /** * Executes the currently selected transfer. */ void slotStartTransfer(); /** * Aborts the currently selected transfer. */ void slotAbortTransfer(); /** * Removes the currently selected transfer from queue. */ void slotRemoveTransfer(); /** * Clears the complete transfer queue. */ void slotRemoveAll(); /** * Moves the current transfer up. */ void slotMoveUp(); /** * Moves the current transfer down. */ void slotMoveDown(); /** * Moves the current transfer to the top. */ void slotMoveTop(); /** * Moves the current transfer to to bottom. */ void slotMoveBottom(); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/treeview.cpp0000644000175000017500000001615511556266126024234 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "queueview/treeview.h" #include "queueview/model.h" #include "queueview/delegate.h" #include "kftpqueue.h" #include #include #include #include #include #include #include using namespace KFTPQueue; namespace KFTPWidgets { namespace Queue { TreeView::TreeView(QWidget* parent) : QTreeView(parent) { setAcceptDrops(true); setDragEnabled(true); setUniformRowHeights(true); setSelectionMode(QAbstractItemView::SingleSelection); setEditTriggers(QAbstractItemView::NoEditTriggers); setSortingEnabled(true); setFrameStyle(QFrame::NoFrame); setDragDropMode(QAbstractItemView::InternalMove); setDropIndicatorShown(true); setAutoExpandDelay(300); setRootIsDecorated(true); Delegate *delegate = new Delegate(this); setItemDelegate(delegate); viewport()->setAttribute(Qt::WA_Hover); } void TreeView::setModel(QAbstractItemModel *model) { QTreeView::setModel(model); // Ensure that sites are automaticly expanded connect(model, SIGNAL(rowsInserted(const QModelIndex&, int, int)), this, SLOT(expandSite(const QModelIndex&))); } bool TreeView::event(QEvent* event) { if (event->type() == QEvent::Polish) { setColumnWidth(Model::Name, 150); setColumnWidth(Model::Size, 75); setColumnWidth(Model::Source, 250); setColumnWidth(Model::Destination, 250); setColumnWidth(Model::Progress, 140); setColumnWidth(Model::Speed, 70); setColumnWidth(Model::ETA, 80); } return QTreeView::event(event); } void TreeView::expandSite(const QModelIndex &parent) { if (!parent.isValid()) return; QueueObject *object = parent.data(Model::ObjectRole).value(); if (object->isSite()) { // Expand the site if (!isExpanded(parent)) setExpanded(parent, true); } } void TreeView::contextMenuEvent(QContextMenuEvent *event) { m_currentIndex = indexAt(event->pos()); if (!m_currentIndex.isValid()) return; QueueObject *object = m_currentIndex.data(Model::ObjectRole).value(); QueueObject *parent = object->parentObject(); // Show a context menu QMenu menu(this); if (object->isLocked()) { menu.addAction(KIcon("process-stop"), i18n("&Abort Directory Scan"), this, SLOT(slotAbortTransfer())); } else if (object->isRunning()) { menu.addAction(KIcon("process-stop"), i18n("&Abort Transfer"), this, SLOT(slotAbortTransfer())); } else { menu.addAction(KIcon("launch"), i18n("&Start Transfer"), this, SLOT(slotStartTransfer())); } if (object->isTransfer()) { menu.addAction(KIcon("edit-delete"), i18n("&Remove"), this, SLOT(slotRemoveTransfer())); } menu.addAction(i18n("R&emove All"), this, SLOT(slotRemoveAll())); menu.addSeparator(); if (parent->canMoveChildUp(object)) { menu.addAction(KIcon("go-up"), i18n("Move &Up"), this, SLOT(slotMoveUp())); menu.addAction(KIcon("go-top"), i18n("Move To &Top"), this, SLOT(slotMoveTop())); } if (parent->canMoveChildDown(object)) { menu.addAction(KIcon("go-down"), i18n("Move &Down"), this, SLOT(slotMoveDown())); menu.addAction(KIcon("go-bottom"), i18n("Move To &Bottom"), this, SLOT(slotMoveBottom())); } menu.exec(event->globalPos()); } void TreeView::slotStartTransfer() { // Reset a possible preconfigured default action Manager::self()->setDefaultFileExistsAction(); QueueObject *object = m_currentIndex.data(Model::ObjectRole).value(); object->execute(); } void TreeView::slotAbortTransfer() { QueueObject *object = m_currentIndex.data(Model::ObjectRole).value(); object->abort(); } void TreeView::slotRemoveTransfer() { if (KMessageBox::warningYesNo(this, i18n("Are you sure you wish to remove this transfer?"), i18n("Remove Transfer")) == KMessageBox::No) return; QueueObject *object = m_currentIndex.data(Model::ObjectRole).value(); Manager::self()->removeTransfer(static_cast(object)); } void TreeView::slotRemoveAll() { if (KMessageBox::warningYesNo(this, i18n("Are you sure you wish to clear the transfer queue?"), i18n("Clear Queue")) == KMessageBox::No) return; Manager::self()->clearQueue(); } void TreeView::slotMoveUp() { QueueObject *object = m_currentIndex.data(Model::ObjectRole).value(); QueueObject *parent = object->parentObject(); parent->moveChildUp(object); setCurrentIndex(model()->index(object->index(), 0, m_currentIndex.parent())); } void TreeView::slotMoveDown() { QueueObject *object = m_currentIndex.data(Model::ObjectRole).value(); QueueObject *parent = object->parentObject(); parent->moveChildDown(object); m_currentIndex = model()->index(object->index(), 0, m_currentIndex.parent()); setCurrentIndex(m_currentIndex); scrollTo(m_currentIndex); } void TreeView::slotMoveTop() { QueueObject *object = m_currentIndex.data(Model::ObjectRole).value(); QueueObject *parent = object->parentObject(); parent->moveChildTop(object); m_currentIndex = model()->index(object->index(), 0, m_currentIndex.parent()); setCurrentIndex(m_currentIndex); scrollTo(m_currentIndex); } void TreeView::slotMoveBottom() { QueueObject *object = m_currentIndex.data(Model::ObjectRole).value(); QueueObject *parent = object->parentObject(); parent->moveChildBottom(object); m_currentIndex = model()->index(object->index(), 0, m_currentIndex.parent()); setCurrentIndex(m_currentIndex); scrollTo(m_currentIndex); } } } #include "treeview.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/threadview.cpp0000644000175000017500000001416711276037142024536 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "threadview.h" #include "listview.h" #include //Added by qt3to4: #include #include #include namespace KFTPWidgets { ThreadViewItem::ThreadViewItem(KFTPSession::Session *session, Q3ListView *parent) : QObject(parent), Q3ListViewItem(parent), m_connection(0), m_session(session) { refresh(); } ThreadViewItem::ThreadViewItem(KFTPSession::Connection *conn, Q3ListViewItem *parent, int id) : QObject(), Q3ListViewItem(parent), m_id(id), m_connection(conn), m_session(0) { connect(conn, SIGNAL(connectionRemoved()), this, SLOT(slotUpdateItemRequested())); connect(conn, SIGNAL(connectionLost(KFTPSession::Connection*)), this, SLOT(slotUpdateItemRequested())); connect(conn, SIGNAL(connectionEstablished()), this, SLOT(slotUpdateItemRequested())); // Connect the transfer signals if the transfer is already present KFTPQueue::Transfer *transfer = m_connection->getTransfer(); if (transfer) { connect(transfer, SIGNAL(objectUpdated()), this, SLOT(slotUpdateItemRequested())); } else { connect(conn, SIGNAL(connectionAcquired()), this, SLOT(slotConnectionAcquired())); } refresh(); } void ThreadViewItem::slotConnectionAcquired() { if (!m_connection->getTransfer()) return; connect(m_connection->getTransfer(), SIGNAL(objectUpdated()), this, SLOT(slotUpdateItemRequested())); refresh(); } void ThreadViewItem::refresh() { /* if (m_session) { // Set the columns setText(0, i18n("Site session [%1]").arg(m_session->getClient()->socket()->getCurrentUrl().host())); setPixmap(0, loadSmallPixmap("ftp")); } else if (m_connection) { setText(0, i18n("Thread %1").arg(m_id)); setPixmap(0, loadSmallPixmap("server")); setText(1, m_connection->isConnected() ? i18n("idle") : i18n("disconnected")); setText(2, ""); KFTPQueue::Transfer *transfer = m_connection->getTransfer(); if (transfer && transfer->isRunning()) { QString speed; filesize_t rawSpeed = transfer->getSpeed(); speed.sprintf( "%lld KB/s", (rawSpeed / 1024) ); if (rawSpeed > 1024*1024) speed.sprintf("%lld MB/s", (rawSpeed / 1024) / 1024); else if (rawSpeed == 0) speed = ""; if (transfer->getStatus() == KFTPQueue::Transfer::Connecting) { setText(1, i18n("connecting")); } else { setText(1, i18n("transferring")); } if (transfer->getTransferType() == KFTPQueue::FXP && rawSpeed == 0) { KFTPSession::Connection *c = static_cast(transfer)->getOppositeConnection(m_connection); setText(2, i18n("FXP - [%1]").arg(c->getUrl().host())); } else { setText(2, speed); } } } */ } void ThreadViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment) { Q3ListViewItem::paintCell(p, cg, column, width, alignment); } void ThreadViewItem::slotUpdateItemRequested() { refresh(); } ThreadView::ThreadView(QWidget *parent, const char *name) : QWidget(parent, name) { Q3VBoxLayout *layout = new Q3VBoxLayout(this); // Create the list view m_threads = new KFTPWidgets::ListView(this); // Create the columns m_threads->addColumn(i18n("Name"), 400); m_threads->addColumn(i18n("Status"), 120); m_threads->addColumn(i18n("Speed"), 70); // Text when there are no threads m_threads->setEmptyListText(i18n("There are no threads currently running.")); // Multi-select m_threads->setSelectionModeExt(K3ListView::FileManager); m_threads->setAllColumnsShowFocus(true); m_threads->setRootIsDecorated(true); layout->addWidget(m_threads); connect(KFTPSession::Manager::self(), SIGNAL(update()), this, SLOT(slotUpdateSessions())); } ThreadView::~ThreadView() { } void ThreadView::slotUpdateSessions() { /* KFTPSession::SessionList *list = KFTPSession::Manager::self()->getSessionList(); KFTPSession::Session *i; m_threads->clear(); for (i = list->first(); i; i = list->next()) { if (i->isRemote()) { ThreadViewItem *site = new ThreadViewItem(i, m_threads); Q3PtrList *c_list = i->getConnectionList(); if (c_list->count() > 0) { KFTPSession::Connection *conn; int id = 0; for (conn = c_list->first(); conn; conn = c_list->next()) { new ThreadViewItem(conn, site, ++id); } site->setOpen(true); } } } */ } } #include "threadview.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/queueeditor.h0000644000175000017500000000514711276037142024372 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUEEDITOR_H #define KFTPQUEUEEDITOR_H #include "kftpqueue.h" #include "kftpbookmarks.h" #include #include class KFTPQueueEditorLayout; namespace KFTPWidgets { /** @author Jernej Kos */ class QueueEditor : public KDialogBase { Q_OBJECT public: QueueEditor(QWidget *parent = 0, const char *name = 0); void setData(KFTPQueue::Transfer *transfer); void saveData(); private: KFTPQueueEditorLayout *m_layout; KFTPQueue::Transfer *m_transfer; KFTPQueue::TransferType m_lastTransferType; void resetTabs(); void resetServerData(); bool sourceIsValid(); bool destIsValid(); void recursiveSaveData(KFTPQueue::TransferDir *parent, const KUrl &srcUrl, const KUrl &dstUrl); private slots: void slotTextChanged(); void slotTransferModeChanged(int index); void slotSourceSiteChanged(KFTPBookmarks::Site *site); void slotDestSiteChanged(KFTPBookmarks::Site *site); }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/CMakeLists.txt0000644000175000017500000000066611276037142024427 0ustar michaelmichaelINCLUDE_DIRECTORIES( .. ../.. ../../misc ${CMAKE_CURRENT_BINARY_DIR}/../.. ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(queueviewwidget_SRCS model.cpp delegate.cpp treeview.cpp #queueeditor.cpp queueview.cpp threadview.cpp ) kde4_add_library(queueviewwidget STATIC ${queueviewwidget_SRCS}) add_dependencies(queueviewwidget widgets) kftpgrabber-0.8.99~svn1214766/src/widgets/queueview/queueview.cpp0000644000175000017500000002667511276037142024422 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * Copyright (C) 2005 Markus Brueffer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "queueview/queueview.h" #include "queueview/treeview.h" #include "queueview/model.h" //Added by qt3to4: #include #include #include #include "kftpqueue.h" //#include "queueeditor.h" //#include "widgets/searchdialog.h" #include "misc/config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KFTPCore; using namespace KFTPWidgets::Queue; namespace KFTPWidgets { QueueView::QueueView(QWidget *parent) : QWidget(parent) { Q3VBoxLayout *layout = new Q3VBoxLayout(this); m_toolBar = new KToolBar(this, "queueToolBar"); m_toolBar->setIconSize(QSize(16, 16)); m_toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly); layout->addWidget(m_toolBar); /* m_searchToolBar = new KToolBar(this, "searchToolBar"); m_searchToolBar->setContextMenuEnabled(false); m_searchToolBar->setMovable(false);*/ //m_searchToolBar->setFullSize(true); // Create the erase button //m_searchToolBar->insertButton(QApplication::isRightToLeft() ? "clear_left" :"locationbar_erase", 0, SIGNAL(clicked()), this, SLOT(slotSearchEraseClicked()), true); // Create the labels /* QLabel *searchLabel = new QLabel(i18n("Filter: "), m_searchToolBar); m_searchToolBar->addWidget(searchLabel);*/ /*1, 35, */ Model *model = new Model(this); m_tree = new TreeView(this); m_tree->setModel(model); layout->addWidget(m_tree); // Create the search field //m_searchField = new K3ListViewSearchLine(m_searchToolBar, m_queue); // Do some more stuff //m_searchToolBar->setItemAutoSized(1, true); //m_searchToolBar->setStretchableWidget(m_searchField); //m_searchToolBar->updateRects(true); //m_searchToolBar->hide(); //layout->addWidget(m_searchToolBar); // Load the listview layout loadLayout(); // Create the context menu actions initActions(); initToolBar(); updateActions(); setMinimumHeight(150); } void QueueView::saveLayout() { //m_queue->saveLayout(KGlobal::config(), "queueViewLayout"); } void QueueView::loadLayout() { //m_queue->restoreLayout(KGlobal::config(), "queueViewLayout"); } void QueueView::initToolBar() { // Plug all actions m_toolBar->addAction(m_loadAction); m_toolBar->addAction(m_saveAction); m_toolBar->addSeparator(); m_toolBar->addAction(m_startAction); m_toolBar->addAction(m_pauseAction); m_toolBar->addAction(m_stopAction); m_toolBar->addSeparator(); m_toolBar->addAction(m_searchAction); m_toolBar->addAction(m_filterAction); // Create speed control widgets m_toolBar->addSeparator(); QSpinBox *downloadSpeed = new QSpinBox(m_toolBar); downloadSpeed->setMinimum(0); downloadSpeed->setMaximum(10240); downloadSpeed->setToolTip(i18n("Limit download transfer speed")); m_toolBar->addWidget(new QLabel(i18n("Down: "), m_toolBar)); m_toolBar->addWidget(downloadSpeed); downloadSpeed->setValue(Config::downloadSpeedLimit()); connect(downloadSpeed, SIGNAL(valueChanged(int)), this, SLOT(slotDownloadLimitChanged(int))); m_toolBar->addSeparator(); QSpinBox *uploadSpeed = new QSpinBox(m_toolBar); uploadSpeed->setMinimum(0); uploadSpeed->setMaximum(10240); uploadSpeed->setToolTip(i18n("Limit upload transfer speed")); m_toolBar->addWidget(new QLabel(i18n("Up: "), m_toolBar)); m_toolBar->addWidget(uploadSpeed); uploadSpeed->setValue(Config::uploadSpeedLimit()); connect(uploadSpeed, SIGNAL(valueChanged(int)), this, SLOT(slotUploadLimitChanged(int))); // Create thread count control widget m_toolBar->addSeparator(); QSpinBox *threadCount = new QSpinBox(m_toolBar); threadCount->setMinimum(1); threadCount->setMaximum(10); threadCount->setToolTip(i18n("Per-session transfer thread count")); m_toolBar->addWidget(new QLabel(i18n("Threads: "), m_toolBar)); m_toolBar->addWidget(threadCount); threadCount->setValue(Config::threadCount()); connect(threadCount, SIGNAL(valueChanged(int)), this, SLOT(slotThreadCountChanged(int))); } void QueueView::slotDownloadLimitChanged(int value) { Config::setDownloadSpeedLimit(value); Config::self()->emitChange(); } void QueueView::slotUploadLimitChanged(int value) { Config::setUploadSpeedLimit(value); Config::self()->emitChange(); } void QueueView::slotThreadCountChanged(int value) { Config::setThreadCount(value); Config::self()->emitChange(); } void QueueView::initActions() { KActionCollection *actions = new KActionCollection(this); // Create the toolbar actions m_loadAction = new KAction(this); m_loadAction->setText(i18n("&Load Queue From File")); m_loadAction->setIcon(KIcon("document-open")); connect(m_loadAction, SIGNAL(triggered()), this, SLOT(slotLoad())); m_saveAction = new KAction(this); m_saveAction->setText(i18n("&Save Queue to File")); m_saveAction->setIcon(KIcon("document-save-as")); connect(m_saveAction, SIGNAL(triggered()), this, SLOT(slotSave())); m_startAction = new KAction(this); m_startAction->setText(i18n("S&tart")); m_startAction->setIcon(KIcon("media-playback-start")); connect(m_startAction, SIGNAL(triggered()), this, SLOT(slotStart())); m_pauseAction = new KAction(this); m_pauseAction->setText(i18n("&Pause")); m_pauseAction->setIcon(KIcon("media-playback-pause")); connect(m_pauseAction, SIGNAL(triggered()), this, SLOT(slotPause())); m_stopAction = new KAction(this); m_stopAction->setText(i18n("St&op")); m_stopAction->setIcon(KIcon("media-playback-stop")); connect(m_stopAction, SIGNAL(triggered()), this, SLOT(slotStop())); m_searchAction = new KAction(this); m_searchAction->setText(i18n("&Search && Replace...")); m_searchAction->setIcon(KIcon("find")); connect(m_searchAction, SIGNAL(triggered()), this, SLOT(slotSearch())); m_filterAction = new KAction(this); m_filterAction->setText(i18n("Show &Filter")); m_filterAction->setIcon(KIcon("filter")); connect(m_filterAction, SIGNAL(triggered()), this, SLOT(slotFilter())); m_saveAction->setEnabled(false); m_startAction->setEnabled(false); m_pauseAction->setEnabled(false); m_stopAction->setEnabled(false); m_searchAction->setEnabled(false); m_filterAction->setEnabled(true); } void QueueView::updateActions() { /* m_startAction->setEnabled(!KFTPQueue::Manager::self()->isProcessing() && KFTPQueue::Manager::self()->topLevelObject()->hasChildren() && !KFTPQueue::Manager::self()->getNumRunning()); m_stopAction->setEnabled(KFTPQueue::Manager::self()->isProcessing()); m_removeAllAction->setEnabled(!KFTPQueue::Manager::self()->isProcessing()); Q3PtrList selection = m_queue->selectedItems(); QueueViewItem *firstItem = static_cast(selection.first()); m_removeAction->setEnabled((bool) firstItem); if (!firstItem || !firstItem->getObject()) return; bool locked = firstItem->getObject()->isLocked(); bool parentRunning = false; if (firstItem->getObject()->hasParentObject()) parentRunning = firstItem->getObject()->parentObject()->isRunning(); m_launchAction->setEnabled(!firstItem->getObject()->isRunning() && !KFTPQueue::Manager::self()->isProcessing() && !locked); m_abortAction->setEnabled(firstItem->getObject()->isRunning() && !KFTPQueue::Manager::self()->isProcessing()); m_removeAction->setEnabled(!firstItem->getObject()->isRunning() && !KFTPQueue::Manager::self()->isProcessing() && !locked); m_editAction->setEnabled(!firstItem->getObject()->isRunning() && firstItem->getObject()->parentObject()->getType() == KFTPQueue::QueueObject::Site && !locked); // Only allow moving of multi selections if they have the same parent bool allowMove = true; for (Q3ListViewItem *i = selection.first(); i; i = selection.next()) { if (i->parent() != static_cast(firstItem)->parent()) { allowMove = false; break; } } m_moveUpAction->setEnabled(allowMove && KFTPQueue::Manager::self()->canBeMovedUp(firstItem->getObject()) && !locked); m_moveDownAction->setEnabled(allowMove && KFTPQueue::Manager::self()->canBeMovedDown(static_cast(selection.last())->getObject()) && !locked); m_moveTopAction->setEnabled(allowMove && KFTPQueue::Manager::self()->canBeMovedUp(firstItem->getObject()) && !locked); m_moveBottomAction->setEnabled(allowMove && KFTPQueue::Manager::self()->canBeMovedDown(static_cast(selection.last())->getObject()) && !locked); */ } void QueueView::slotSearch() { /* SearchDialog *dialog = new SearchDialog(); dialog->exec(); delete dialog; */ } void QueueView::slotLoad() { /* if (m_queue->childCount() && KMessageBox::warningContinueCancel(0L, i18n("Loading a new queue will overwrite the existing one; are you sure you want to continue?"), i18n("Load Queue")) == KMessageBox::Cancel) return; QString loadPath = KFileDialog::getOpenFileName(); if (!loadPath.isEmpty()) { KFTPQueue::Manager::self()->getConverter()->importQueue(loadPath); } */ } void QueueView::slotSave() { /* QString savePath = KFileDialog::getSaveFileName(); if (!savePath.isEmpty()) { KFTPQueue::Manager::self()->getConverter()->exportQueue(savePath); } */ } void QueueView::slotStart() { // Begin queue processing KFTPQueue::Manager::self()->start(); } void QueueView::slotPause() { } void QueueView::slotStop() { // Abort queue processing KFTPQueue::Manager::self()->abort(); } void QueueView::slotAdd() { } void QueueView::slotFilter() { /* if (m_filterAction->isChecked()) m_searchToolBar->show(); else m_searchToolBar->hide();*/ } } #include "queueview.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/verifier.h0000644000175000017500000000455411276037142021634 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETSVERIFIER_H #define KFTPWIDGETSVERIFIER_H #include "checksumverifier.h" #include #include #include // Layouts #include "ui/ui_checksum_verifier.h" namespace KFTPWidgets { /** * @author Jernej Kos */ class Verifier : public KDialog { Q_OBJECT public: Verifier(QWidget *parent); ~Verifier(); void setFile(const QString &filename); private: Ui::VerifierLayout ui; KFTPCore::ChecksumVerifier *m_verifier; private slots: void slotHaveFileList(QList > list); void slotFileDone(const QString &filename, KFTPCore::ChecksumVerifier::Result result); void slotProgress(int percent); void slotError(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/kftpfilteraddpatternlayout.cpp0000644000175000017500000000657111276037142026034 0ustar michaelmichael#include /**************************************************************************** ** Form implementation generated from reading ui file '/home/kostko/development/kftpgrabber/src/widgets/kftpfilteraddpatternlayout.ui' ** ** Created: Mon Oct 20 18:26:31 2003 ** by: The User Interface Compiler ($Id: kftpfilteraddpatternlayout.cpp,v 1.1.1.1 2004/02/13 13:33:43 kostko Exp $) ** ** WARNING! All changes made in this file will be lost! ****************************************************************************/ #include "kftpfilteraddpatternlayout.h" #include #include #include #include //Added by qt3to4: #include #include #include #include #include #include #include #include /* * Constructs a KFTPFilterAddPatternLayout as a child of 'parent', with the * name 'name' and widget flags set to 'f'. */ KFTPFilterAddPatternLayout::KFTPFilterAddPatternLayout( QWidget* parent, const char* name, Qt::WFlags fl ) : QWidget( parent, name, fl ) { if ( !name ) setName( "KFTPFilterAddPatternLayout" ); KFTPFilterAddPatternLayoutLayout = new Q3GridLayout( this, 1, 1, 11, 6, "KFTPFilterAddPatternLayoutLayout"); groupBox1 = new Q3GroupBox( this, "groupBox1" ); groupBox1->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)5, (QSizePolicy::SizeType)2, 0, 0, groupBox1->sizePolicy().hasHeightForWidth() ) ); groupBox1->setColumnLayout(0, Qt::Vertical ); groupBox1->layout()->setSpacing( 6 ); groupBox1->layout()->setMargin( 11 ); groupBox1Layout = new Q3GridLayout( groupBox1->layout() ); groupBox1Layout->setAlignment( Qt::AlignTop ); layout9 = new Q3HBoxLayout( 0, 0, 6, "layout9"); layout8 = new Q3VBoxLayout( 0, 0, 6, "layout8"); textLabel1 = new QLabel( groupBox1, "textLabel1" ); layout8->addWidget( textLabel1 ); textLabel2 = new QLabel( groupBox1, "textLabel2" ); layout8->addWidget( textLabel2 ); layout9->addLayout( layout8 ); layout7 = new Q3VBoxLayout( 0, 0, 6, "layout7"); kLineEdit1 = new KLineEdit( groupBox1, "kLineEdit1" ); layout7->addWidget( kLineEdit1 ); kColorButton1 = new KColorButton( groupBox1 ); kColorButton1->setObjectName( "kColorButton1" ); kColorButton1->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)0, (QSizePolicy::SizeType)0, 0, 0, kColorButton1->sizePolicy().hasHeightForWidth() ) ); layout7->addWidget( kColorButton1 ); layout9->addLayout( layout7 ); groupBox1Layout->addLayout( layout9, 0, 0 ); KFTPFilterAddPatternLayoutLayout->addWidget( groupBox1, 0, 0 ); languageChange(); resize( QSize(380, 110).expandedTo(minimumSizeHint()) ); clearWState( WState_Polished ); } /* * Destroys the object and frees any allocated resources */ KFTPFilterAddPatternLayout::~KFTPFilterAddPatternLayout() { // no need to delete child widgets, Qt does it all for us } /* * Sets the strings of the subwidgets using the current * language. */ void KFTPFilterAddPatternLayout::languageChange() { setCaption( tr2i18n( "Form1" ) ); groupBox1->setTitle( tr2i18n( "New Pattern" ) ); textLabel1->setText( tr2i18n( "Filename pattern:" ) ); textLabel2->setText( tr2i18n( "Color:" ) ); kColorButton1->setText( QString::null ); } #include "kftpfilteraddpatternlayout.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/overlaywidget.cpp0000644000175000017500000000517411276037142023240 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * Copyright (C) 2005 Max Howell * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "overlaywidget.h" #include namespace KFTPWidgets { OverlayWidget::OverlayWidget(QWidget *parent, QWidget *anchor) : QFrame(parent->parentWidget()), m_parent(parent), m_anchor(anchor) { parent->installEventFilter(this); hide(); } void OverlayWidget::reposition() { setMaximumSize(parentWidget()->size()); adjustSize(); // P is in the alignWidget's coordinates QPoint p; p.setX(m_anchor->width() - width()); p.setY(-height()); // Position in the toplevelWidget's coordinates QPoint pTopLevel = m_anchor->mapTo(topLevelWidget(), p); // Position in the widget's parentWidget coordinates QPoint pParent = parentWidget()->mapFrom(topLevelWidget(), pTopLevel); if (pParent.x() < 0) pParent.rx() = 0; move(pParent); } bool OverlayWidget::event(QEvent *event) { if (event->type() == QEvent::ChildAdded) adjustSize(); return QFrame::event(event); } } kftpgrabber-0.8.99~svn1214766/src/widgets/overlaywidget.h0000644000175000017500000000415611276037142022704 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * Copyright (C) 2005 Max Howell * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETSOVERLAYWIDGET_H #define KFTPWIDGETSOVERLAYWIDGET_H #include #include namespace KFTPWidgets { /** * @author Max Howell */ class OverlayWidget : public QFrame { public: OverlayWidget(QWidget *parent, QWidget *anchor); virtual void reposition(); protected: virtual bool event(QEvent *event); private: QWidget *m_parent; QWidget *m_anchor; }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/fingerprintverifydialog.cpp0000644000175000017500000000556311276037142025311 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "fingerprintverifydialog.h" #include "misc/config.h" #include #include using namespace KFTPCore; namespace KFTPWidgets { FingerprintVerifyDialog::FingerprintVerifyDialog(QWidget *parent) : KDialog(parent) { setCaption(i18n("Fingerprint Verification")); setButtons(Cancel | Ok); setButtonText(Ok, i18n("Continue")); QWidget *widget = new QWidget(this); ui.setupUi(widget); setMainWidget(widget); resize(QSize(440, 170)); ui.icon->setPixmap(DesktopIcon("decrypted")); } void FingerprintVerifyDialog::setFingerprint(const QByteArray &fingerprint, const KUrl &url) { QByteArray f = fingerprint.toHex(); for (int i = 2; i < f.size(); i += 2) { f.insert(i++, ':'); } ui.fingerprint->setText(QString("%1").arg(QString(f))); m_url = url; m_fingerprint = fingerprint; } void FingerprintVerifyDialog::slotButtonClicked(int button) { switch (button) { case Ok: { // Save the fingerprint CertificateStore *store = Config::self()->certificateStore(); store->addFingerprint(m_url, m_fingerprint); store->save(); accept(); break; } case Cancel: reject(); break; } } } #include "fingerprintverifydialog.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/failedtransfers/0000755000175000017500000000000011276037142023014 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/widgets/failedtransfers/view.cpp0000644000175000017500000000417411276037142024500 0ustar michaelmichael/* * This file is part of the KFTPgrabber project * * Copyright (C) 2003-2009 by the KFTPgrabber developers * Copyright (C) 2003-2009 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "failedtransfers/view.h" #include "failedtransfers/model.h" using namespace KFTPQueue; namespace KFTPWidgets { namespace FailedTransfers { View::View(QWidget *parent) : QTreeView(parent) { setSelectionMode(QAbstractItemView::SingleSelection); setEditTriggers(QAbstractItemView::NoEditTriggers); setSortingEnabled(true); setFrameStyle(QFrame::NoFrame); setRootIsDecorated(false); Model *model = new Model(this); setModel(model); } } } #include "view.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/failedtransfers/model.h0000644000175000017500000000674111276037142024275 0ustar michaelmichael/* * This file is part of the KFTPgrabber project * * Copyright (C) 2003-2009 by the KFTPgrabber developers * Copyright (C) 2003-2009 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_FAILEDTRANSFERSMODEL_H #define KFTPWIDGETS_FAILEDTRANSFERSMODEL_H #include namespace KFTPQueue { class FailedTransfer; } namespace KFTPWidgets { namespace FailedTransfers { /** * A model representing a list of failed transfers. * * @author Jernej Kos */ class Model : public QAbstractTableModel { Q_OBJECT public: /** * Additional index roles. */ enum { TypeRole = Qt::UserRole + 1, ObjectRole }; /** * Default model columns. */ enum ModelColumns { Name = 0, ErrorMessage, Size, Source, Destination, ColumnCount }; /** * Class constructor. * * @param parent An optional parent object */ Model(QObject *parent = 0); /** * @overload * Reimplemented from QAbstractItemModel. */ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; private slots: void slotObjectAdded(KFTPQueue::FailedTransfer *transfer); void slotObjectBeforeRemoval(KFTPQueue::FailedTransfer *transfer); void slotObjectAfterRemoval(); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/failedtransfers/model.cpp0000644000175000017500000001134111276037142024620 0ustar michaelmichael/* * This file is part of the KFTPgrabber project * * Copyright (C) 2003-2009 by the KFTPgrabber developers * Copyright (C) 2003-2009 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "failedtransfers/model.h" #include "kftptransfer.h" #include "kftpqueue.h" #include #include using namespace KFTPQueue; namespace KFTPWidgets { namespace FailedTransfers { Model::Model(QObject *parent) : QAbstractTableModel(parent) { connect(Manager::self(), SIGNAL(failedTransferAdded(KFTPQueue::FailedTransfer*)), this, SLOT(slotObjectAdded(KFTPQueue::FailedTransfer*))); connect(Manager::self(), SIGNAL(failedTransferBeforeRemoval(KFTPQueue::FailedTransfer*)), this, SLOT(slotObjectBeforeRemoval(KFTPQueue::FailedTransfer*))); connect(Manager::self(), SIGNAL(failedTransferAfterRemoval()), this, SLOT(slotObjectAfterRemoval())); } int Model::columnCount(const QModelIndex&) const { return ColumnCount; } QVariant Model::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(orientation); switch (role) { case Qt::DisplayRole: { switch (section) { case Name: return i18n("Name"); case ErrorMessage: return i18n("Error Message"); case Size: return i18n("Size"); case Source: return i18n("Source"); case Destination: return i18n("Destination"); } } } return QVariant(); } QVariant Model::data(const QModelIndex &index, int role) const { if (index.isValid()) { FailedTransfer *ftransfer = static_cast(index.internalPointer()); TransferFile *transfer = ftransfer->getTransfer(); switch (role) { case Qt::DisplayRole: { switch (index.column()) { case Name: return transfer->getSourceUrl().fileName(); case ErrorMessage: return ftransfer->getError(); case Size: return KIO::convertSize(transfer->getActualSize()); case Source: return transfer->getSourceUrl().pathOrUrl(); case Destination: return transfer->getDestUrl().pathOrUrl(); } break; } case Qt::DecorationRole: { if (index.column() == Name) { return KIcon("txt"); } break; } case ObjectRole: return QVariant::fromValue(ftransfer); default: break; } } return QVariant(); } QModelIndex Model::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) return QModelIndex(); FailedTransfer *transfer = Manager::self()->failedTransfers()->at(row); if (transfer) return createIndex(row, column, transfer); else return QModelIndex(); } int Model::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return Manager::self()->failedTransfers()->count(); } void Model::slotObjectAdded(KFTPQueue::FailedTransfer *transfer) { const int rowNumber = Manager::self()->failedTransfers()->lastIndexOf(transfer); beginInsertRows(QModelIndex(), rowNumber, rowNumber); endInsertRows(); } void Model::slotObjectBeforeRemoval(KFTPQueue::FailedTransfer *transfer) { const int rowNumber = Manager::self()->failedTransfers()->lastIndexOf(transfer); beginRemoveRows(QModelIndex(), rowNumber, rowNumber); } void Model::slotObjectAfterRemoval() { endRemoveRows(); } } } #include "model.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/failedtransfers/view.h0000644000175000017500000000406611276037142024145 0ustar michaelmichael/* * This file is part of the KFTPgrabber project * * Copyright (C) 2003-2009 by the KFTPgrabber developers * Copyright (C) 2003-2009 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_FAILEDTRANSFERSVIEW_H #define KFTPWIDGETS_FAILEDTRANSFERSVIEW_H #include namespace KFTPWidgets { namespace FailedTransfers { /** * A view of failed transfers. * * @author Jernej Kos */ class View : public QTreeView { Q_OBJECT public: /** * Class constructor. * * @param parent An optional parent object */ View(QWidget *parent = 0); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/failedtransfers/CMakeLists.txt0000644000175000017500000000061711276037142025560 0ustar michaelmichaelINCLUDE_DIRECTORIES( .. ../.. ../../misc ${CMAKE_CURRENT_BINARY_DIR}/../.. ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(failedtransferswidget_SRCS model.cpp view.cpp ) kde4_add_library(failedtransferswidget STATIC ${failedtransferswidget_SRCS}) add_dependencies(failedtransferswidget widgets) kftpgrabber-0.8.99~svn1214766/src/widgets/widgetlister.h0000644000175000017500000001324311276037142022522 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETSWIDGETLISTER_H #define KFTPWIDGETSWIDGETLISTER_H #include #include #include class QPushButton; class QVBoxLayout; class KHBox; namespace KFTPWidgets { /** * This class has been adopted from KDEPIM with slight functional and style * changes. * * @author Jernej Kos * @author Marc Mutz */ class WidgetLister : public QWidget { Q_OBJECT public: /** * Class constructor. * * @param parent Parent widget * @param minWidgets Minimum number of widgets in the list * @param maxWidgets Maximum number of widgets in the list */ WidgetLister(QWidget* parent, int minWidgets, int maxWidgets); /** * Class destructor. */ virtual ~WidgetLister(); /** * Clears all widgets. */ void clear(); /** * Sets the number of currently shown widgets on screen. * * @param number The number of widgets that should be visible */ virtual void setNumberShown(int number); protected slots: /** * Called whenever the user clicks on the 'more' button. Reimplementations * should call this method, because this implementation does all the dirty * work with adding the widgets to the layout (through @ref addWidget) * and enabling/disabling the control buttons. */ virtual void slotMore(); /** * Called whenever the user clicks on the 'fewer' button. Reimplementations * should call this method, because this implementation does all the dirty * work with removing the widgets from the layout (through @ref removeWidget) * and enabling/disabling the control buttons. */ virtual void slotFewer(); /** * Called whenever the user clicks on the 'clear' button. Reimplementations * should call this method, because this implementation does all the dirty * work with removing all but @ref m_minWidgets widgets from the layout and * enabling/disabling the control buttons. */ virtual void slotClear(); protected: /** * Adds a single widget. Doesn't care if there are already @ref m_maxWidgets * on screen and whether it should enable/disable any controls. It simply does * what it is asked to do. You want to reimplement this method if you want to * initialize the the widget when showing it on screen. Make sure you call this * implementaion, though, since you cannot put the widget on screen from derived * classes (@p m_layout is private). Make sure the parent of the QWidget to add is * this WidgetLister. * * @param widget The widget that should be added */ virtual void addWidget(QWidget *widget = 0); /** * Removes a single (always the last) widget. Doesn't care if there are still only * @ref m_minWidgets left on screen and whether it should enable/disable any controls. * It simply does what it is asked to do. You want to reimplement this method if you * want to save the the widget's state before removing it from screen. Make sure you * call this implementaion, though, since you should not remove the widget from * screen from derived classes. */ virtual void removeWidget(); /** * Called to clear a given widget. The default implementation does nothing. * * @param widget The widget that should be cleared */ virtual void clearWidget(QWidget *widget); /** * This method should return a new widget to add to the widget list. * * @param parent The parent widget * @return A valid QWidget */ virtual QWidget *createWidget(QWidget *parent); protected: QList m_widgetList; int m_minWidgets; int m_maxWidgets; signals: /** * This signal is emitted whenever a widget gets added. */ void widgetAdded(QWidget *widget); /** * This signal is emitted whenever a widget gets removed. */ void widgetRemoved(); /** * This signal is emitted whenever the clear button is clicked. */ void clearWidgets(); private: void enableControls(); QPushButton *m_buttonMore; QPushButton *m_buttonFewer; QPushButton *m_buttonClear; QVBoxLayout *m_layout; KHBox *m_buttonBox; }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/browser/0000755000175000017500000000000011276037142021323 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/widgets/browser/dirsortfilterproxymodel.cpp0000644000175000017500000002512711276037142027055 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2007 by the KFTPGrabber developers * Copyright (C) 2007 Jernej Kos * Copyright (C) 2006 by Peter Penz * Copyright (C) 2006 by Dominic Battre * Copyright (C) 2006 by Martin Pool * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "browser/dirsortfilterproxymodel.h" #include "browser/dirmodel.h" #include #include #include namespace KFTPWidgets { namespace Browser { DirSortFilterProxyModel::DirSortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent) { setDynamicSortFilter(true); // Sort by the user visible string for now setSortCaseSensitivity(Qt::CaseInsensitive); sort(DirModel::Name, Qt::AscendingOrder); } DirSortFilterProxyModel::~DirSortFilterProxyModel() { } bool DirSortFilterProxyModel::hasChildren(const QModelIndex& parent) const { const QModelIndex sourceParent = mapToSource(parent); return sourceModel()->hasChildren(sourceParent); } bool DirSortFilterProxyModel::canFetchMore(const QModelIndex& parent) const { const QModelIndex sourceParent = mapToSource(parent); return sourceModel()->canFetchMore(sourceParent); } int DirSortFilterProxyModel::naturalCompare(const QString& a, const QString& b) { // This method chops the input a and b into pieces of // digits and non-digits (a1.05 becomes a | 1 | . | 05) // and compares these pieces of a and b to each other // (first with first, second with second, ...). // // This is based on the natural sort order code code by Martin Pool // http://sourcefrog.net/projects/natsort/ // Martin Pool agreed to license this under LGPL or GPL. const QChar* currA = a.unicode(); // iterator over a const QChar* currB = b.unicode(); // iterator over b if (currA == currB) { return 0; } const QChar* begSeqA = currA; // beginning of a new character sequence of a const QChar* begSeqB = currB; while (!currA->isNull() && !currB->isNull()) { // find sequence of characters ending at the first non-character while (!currA->isNull() && !currA->isDigit()) { ++currA; } while (!currB->isNull() && !currB->isDigit()) { ++currB; } // compare these sequences const QString subA(begSeqA, currA - begSeqA); const QString subB(begSeqB, currB - begSeqB); const int cmp = QString::localeAwareCompare(subA, subB); if (cmp != 0) { return cmp; } if (currA->isNull() || currB->isNull()) { break; } // now some digits follow... if ((*currA == '0') || (*currB == '0')) { // one digit-sequence starts with 0 -> assume we are in a fraction part // do left aligned comparison (numbers are considered left aligned) while (1) { if (!currA->isDigit() && !currB->isDigit()) { break; } else if (!currA->isDigit()) { return -1; } else if (!currB->isDigit()) { return + 1; } else if (*currA < *currB) { return -1; } else if (*currA > *currB) { return + 1; } ++currA; ++currB; } } else { // No digit-sequence starts with 0 -> assume we are looking at some integer // do right aligned comparison. // // The longest run of digits wins. That aside, the greatest // value wins, but we can't know that it will until we've scanned // both numbers to know that they have the same magnitude. int weight = 0; while (1) { if (!currA->isDigit() && !currB->isDigit()) { if (weight != 0) { return weight; } break; } else if (!currA->isDigit()) { return -1; } else if (!currB->isDigit()) { return + 1; } else if ((*currA < *currB) && (weight == 0)) { weight = -1; } else if ((*currA > *currB) && (weight == 0)) { weight = + 1; } ++currA; ++currB; } } begSeqA = currA; begSeqB = currB; } if (currA->isNull() && currB->isNull()) { return 0; } return currA->isNull() ? -1 : + 1; } bool DirSortFilterProxyModel::lessThan(const QModelIndex& left, const QModelIndex& right) const { DirModel *dirModel = static_cast(sourceModel()); const KFileItem leftFileItem = dirModel->itemForIndex(left); const KFileItem rightFileItem = dirModel->itemForIndex(right); // On our priority, folders go above regular files if (leftFileItem.isDir() && !rightFileItem.isDir()) { return true; } else if (!leftFileItem.isDir() && rightFileItem.isDir()) { return false; } // Hidden elements go before visible ones, if they both are // folders or files if (leftFileItem.isHidden() && !rightFileItem.isHidden()) { return true; } else if (!leftFileItem.isHidden() && rightFileItem.isHidden()) { return false; } switch (left.column()) { case DirModel::Name: { // So we are in the same priority, what counts now is their names const QVariant leftData = dirModel->data(left, DirModel::Name); const QVariant rightData = dirModel->data(right, DirModel::Name); const QString leftValueString(leftData.toString()); const QString rightValueString(rightData.toString()); return sortCaseSensitivity() ? (naturalCompare(leftValueString, rightValueString) < 0) : (naturalCompare(leftValueString.toLower(), rightValueString.toLower()) < 0); } case DirModel::Size: { // If we have two folders, what we have to measure is the number of // items that contains each other if (leftFileItem.isDir() && rightFileItem.isDir()) { QVariant leftValue = dirModel->data(left, DirModel::ChildCountRole); int leftCount = leftValue.type() == QVariant::Int ? leftValue.toInt() : DirModel::ChildCountUnknown; QVariant rightValue = dirModel->data(right, DirModel::ChildCountRole); int rightCount = rightValue.type() == QVariant::Int ? rightValue.toInt() : DirModel::ChildCountUnknown; // In the case they two have the same child items, we sort them by // their names. So we have always everything ordered. We also check // if we are taking in count their cases if (leftCount == rightCount) { return sortCaseSensitivity() ? (naturalCompare(leftFileItem.name(), rightFileItem.name()) < 0) : (naturalCompare(leftFileItem.name().toLower(), rightFileItem.name().toLower()) < 0); } // If they had different number of items, we sort them depending // on how many items had each other return leftCount < rightCount; } // If what we are measuring is two files and they have the same size, // sort them by their file names. if (leftFileItem.size() == rightFileItem.size()) { return sortCaseSensitivity() ? (naturalCompare(leftFileItem.name(), rightFileItem.name()) < 0) : (naturalCompare(leftFileItem.name().toLower(), rightFileItem.name().toLower()) < 0); } // If their sizes are different, sort them by their sizes, as expected. return leftFileItem.size() < rightFileItem.size(); } case DirModel::ModifiedTime: { KDateTime leftTime = leftFileItem.time(KFileItem::ModificationTime); KDateTime rightTime = rightFileItem.time(KFileItem::ModificationTime); if (leftTime == rightTime) { return sortCaseSensitivity() ? (naturalCompare(leftFileItem.name(), rightFileItem.name()) < 0) : (naturalCompare(leftFileItem.name().toLower(), rightFileItem.name().toLower()) < 0); } return leftTime > rightTime; } case DirModel::Permissions: { if (leftFileItem.permissionsString() == rightFileItem.permissionsString()) { return sortCaseSensitivity() ? (naturalCompare(leftFileItem.name(), rightFileItem.name()) < 0) : (naturalCompare(leftFileItem.name().toLower(), rightFileItem.name().toLower()) < 0); } return naturalCompare(leftFileItem.permissionsString(), rightFileItem.permissionsString()) < 0; } case DirModel::Owner: { if (leftFileItem.user() == rightFileItem.user()) { return sortCaseSensitivity() ? (naturalCompare(leftFileItem.name(), rightFileItem.name()) < 0) : (naturalCompare(leftFileItem.name().toLower(), rightFileItem.name().toLower()) < 0); } return naturalCompare(leftFileItem.user(), rightFileItem.user()) < 0; } case DirModel::Group: { if (leftFileItem.group() == rightFileItem.group()) { return sortCaseSensitivity() ? (naturalCompare(leftFileItem.name(), rightFileItem.name()) < 0) : (naturalCompare(leftFileItem.name().toLower(), rightFileItem.name().toLower()) < 0); } return naturalCompare(leftFileItem.group(), rightFileItem.group()) < 0; } } // We have set a SortRole and trust the ProxyModel to do the right thing for now return QSortFilterProxyModel::lessThan(left, right); } } } #include "dirsortfilterproxymodel.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/browser/locationnavigator.cpp0000644000175000017500000001060211276037142025551 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "locationnavigator.h" #include "detailsview.h" #include "dirmodel.h" #include namespace KFTPWidgets { namespace Browser { LocationNavigator::Element::Element() : m_url(), m_contentsX(0), m_contentsY(0) { } LocationNavigator::Element::Element(const KUrl &url) : m_url(url), m_contentsX(0), m_contentsY(0) { } LocationNavigator::LocationNavigator(DetailsView *view) : m_view(view), m_historyIndex(0) { connect(view, SIGNAL(contentsMoved(int, int)), this, SLOT(slotContentsMoved(int, int))); } void LocationNavigator::setUrl(const KUrl &url) { if (m_historyIndex > 0) { const KUrl &nextUrl = m_history[m_historyIndex - 1].url(); if (url == nextUrl) { goForward(); return; } } // Check for duplicates if (m_history.count() > m_historyIndex) { const KUrl ¤tUrl = m_history[m_historyIndex].url(); if (currentUrl == url) return; } updateCurrentElement(); m_history.insert(m_historyIndex, Element(url)); emit urlChanged(url); emit historyChanged(url); // Cleanup history when it becomes too big if (m_historyIndex > 100) { m_history.removeFirst(); m_historyIndex--; } } const KUrl& LocationNavigator::url() const { return m_history[m_historyIndex].url(); } const QList LocationNavigator::history(int &index) const { index = m_historyIndex; return m_history; } void LocationNavigator::goBack() { updateCurrentElement(); const int count = m_history.count(); if (m_historyIndex < count - 1) { m_historyIndex++; emit urlChanged(url()); emit historyChanged(url()); } } void LocationNavigator::goForward() { if (m_historyIndex > 0) { m_historyIndex--; emit urlChanged(url()); emit historyChanged(url()); } } void LocationNavigator::goUp() { setUrl(url().upUrl()); } void LocationNavigator::goHome() { setUrl(m_homeUrl); } void LocationNavigator::clear() { Element element = m_history[m_historyIndex]; m_history.clear(); m_historyIndex = 0; m_history.append(element); } void LocationNavigator::slotContentsMoved(int x, int y) { m_history[m_historyIndex].setContentsX(x); m_history[m_historyIndex].setContentsY(y); } void LocationNavigator::updateCurrentElement() { if (m_history.isEmpty()) return; QModelIndex currentIndex = m_view->currentIndex(); if (currentIndex.isValid()) { const KFileItem item = currentIndex.data(DirModel::FileItemRole).value(); m_history[m_historyIndex].setCurrentItem(item); } m_history[m_historyIndex].setContentsX(m_view->horizontalScrollBar()->value()); m_history[m_historyIndex].setContentsY(m_view->verticalScrollBar()->value()); } } } #include "locationnavigator.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/browser/dirmodel.h0000644000175000017500000001705711276037142023305 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * Copyright (C) 2006 David Faure * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_BROWSERDIRMODEL_H #define KFTPWIDGETS_BROWSERDIRMODEL_H #include #include namespace KFTPWidgets { namespace Browser { class DirLister; class DirModelPrivate; /** * A custom directory model implementation based on KDirModel from * the KIO library. We need our own, because we can't use KIO slaves * for remote operations. * * @author Jernej Kos * @author David Faure */ class DirModel : public QAbstractItemModel { Q_OBJECT public: /** * Default model columns. */ enum ModelColumns { Name = 0, Size, ModifiedTime, Permissions, Owner, Group, ColumnCount }; /** * Flag to set when child count is not known. */ enum { ChildCountUnknown = -1 }; /** * Specialized item roles for KFileItemDelegate. */ enum AdditionalRoles { FileItemRole = 0x07A263FF, ChildCountRole = 0x2C4D0A40 }; /** * Drag and drop behavior. */ enum DropsAllowedFlag { NoDrops = 0, DropOnDirectory = 1, DropOnAnyFile = 2, DropOnLocalExecutable = 4 }; Q_DECLARE_FLAGS(DropsAllowed, DropsAllowedFlag) /** * Class constructor. * * @param lister Directory lister instance * @param parent Optional parent object */ DirModel(DirLister *lister, QObject *parent = 0); /** * Class destructor. */ ~DirModel(); /** * Changes the directory lister this model uses. * * @param lister New lister instance */ void setDirLister(DirLister *lister); /** * This method enables or disables this model's support for treeview * behavior. This includes creation of the toplevel node, on the fly * creation of stub directories etc. It will also limit display to * directories only, so you can (and should) use the same directory * lister as for the detailed view (if any). * * You MUST set this to true if you wish to use this model in a tree-view * like fashion, otherwise things will not work as they should! * * @param value True to enable tree-view behavior, false otherwise */ void setTreeViewBehavior(bool value); /** * Returns the directory lister associated with this model. */ DirLister *dirLister() const; KFileItem itemForIndex(const QModelIndex &index) const; QModelIndex indexForItem(const KFileItem &item) const; QModelIndex indexForItem(const KFileItem *item) const; QModelIndex indexForUrl(const KUrl &url) const; void itemChanged(const QModelIndex &index); void setDropsAllowed(DropsAllowed dropsAllowed); /** * @overload * Reimplemented from QAbstractItemModel. */ virtual bool canFetchMore(const QModelIndex &parent) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); /** * @overload * Reimplemented from QAbstractItemModel. */ virtual void fetchMore(const QModelIndex &parent); /** * @overload * Reimplemented from QAbstractItemModel. */ virtual Qt::ItemFlags flags(const QModelIndex &index) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual bool hasChildren(const QModelIndex &parent = QModelIndex()) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QMimeData *mimeData(const QModelIndexList &indexes) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QStringList mimeTypes() const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual QModelIndex parent(const QModelIndex &index) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual int rowCount(const QModelIndex & parent = QModelIndex()) const; /** * @overload * Reimplemented from QAbstractItemModel. */ virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); /** * @overload * Reimplemented from QAbstractItemModel. */ virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); private slots: void slotNewItems(const KFileItemList &items); void slotDeleteItem(const KFileItem &item); void slotRefreshItems(const QList > &items); void slotClear(); void slotUnconditionalClear(); private: virtual bool insertRows(int , int, const QModelIndex& = QModelIndex()) { return false; } virtual bool insertColumns(int, int, const QModelIndex& = QModelIndex()) { return false; } virtual bool removeRows(int, int, const QModelIndex& = QModelIndex()) { return false; } virtual bool removeColumns(int, int, const QModelIndex& = QModelIndex()) { return false; } private: friend class DirModelPrivate; DirModelPrivate *const d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(DirModel::DropsAllowed) } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/browser/filterwidget.h0000644000175000017500000000604011276037142024165 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_BROWSERFILTERWIDGET_H #define KFTPWIDGETS_BROWSERFILTERWIDGET_H #include //Added by qt3to4: #include namespace KFTPWidgets { namespace Browser { class DetailsView; /** * This class is a simple filtering widget that accepts wildcard * patterns and filters listviews. Note that this widget only * filters on the first column. * * @author Jernej Kos */ class FilterWidget : public K3ListViewSearchLine { Q_OBJECT public: /** * Class constructor. * * @param parent The parent widget * @param view The view you want to filter */ FilterWidget(QWidget *parent, DetailsView *view); protected: enum { FilterDirectories = 1, FilterSymlinks = 2, Qt::CaseSensitive = 3 }; /** * @overload * Reimplemented from K3ListViewSearchLine to support wildcard * matching schemes. */ bool itemMatches(const Q3ListViewItem *item, const QString &pattern) const; /** * @overload * Reimplemented from K3ListViewSearchLine to remove multiple * columns selection, since this widget only operates on the * first column. */ Q3PopupMenu *createPopupMenu(); private: bool m_filterDirectories; bool m_filterSymlinks; bool m_caseSensitive; private slots: void slotOptionsMenuActivated(int id); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/browser/actions.cpp0000644000175000017500000006544211276037142023502 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "browser/actions.h" #include "browser/view.h" #include "browser/detailsview.h" #include "browser/dirmodel.h" //#include "browser/propsplugin.h" //#include "browser/filterwidget.h" #include "widgets/popupmessage.h" #include "widgets/bookmarks/editor.h" #include "kftpbookmarks.h" #include "kftpqueue.h" #include "kftpsession.h" #include "verifier.h" #include "misc/config.h" #include "misc/filter.h" #include "misc/customcommands/manager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KFTPEngine; using namespace KFTPCore; using namespace KFTPCore::Filter; namespace KFTPWidgets { namespace Browser { Actions::Actions(View *parent) : QObject(parent), m_view(parent) { } void Actions::initActions() { KActionCollection *actionCollection = new KActionCollection(m_view); // Create all the actions m_goUpAction = KStandardAction::up(this, SLOT(slotGoUp()), actionCollection); m_goBackAction = KStandardAction::back(this, SLOT(slotGoBack()), actionCollection); m_goForwardAction = KStandardAction::forward(this, SLOT(slotGoForward()), actionCollection); m_goHomeAction = KStandardAction::home(this, SLOT(slotGoHome()), actionCollection); m_reloadAction = KStandardAction::redisplay(this, SLOT(slotReload()), actionCollection); m_reloadAction->setText(i18n("&Reload")); m_reloadAction->setShortcut(KShortcut(Qt::Key_F5)); /* m_abortAction = new KAction(i18n("&Abort"), "process-stop", KShortcut(), this, SLOT(slotAbort()), m_actionCollection, "abort"); m_toggleTreeViewAction = new KToggleAction(i18n("&Show Tree View"), "view-sidetree", KShortcut(), this, SLOT(slotShowHideTree()), m_actionCollection, "toggle_tree_view"); m_toggleFilterAction = new KToggleAction(i18n("Show &Filter"), "filter", KShortcut(), this, SLOT(slotShowHideFilter()), m_actionCollection, "toggle_filter"); m_renameAction = new KAction(i18n("&Rename"), KShortcut(Qt::Key_F2), this, SLOT(slotRename()), m_actionCollection, "edit_rename"); m_deleteAction = new KAction(i18n("&Delete"), "edit-delete", KShortcut(Qt::Key_Delete), this, SLOT(slotDelete()), m_actionCollection, "edit_delete"); m_propsAction = new KAction(i18n("&Properties"), KShortcut(), this, SLOT(slotProps()), m_actionCollection, "edit_properties"); m_shredAction = new KAction(i18n("&Shred"), "edit-delete-shred", KShortcut(), this, SLOT(slotShred()), m_actionCollection, "edit_shred"); m_copyAction = KStandardAction::copy(this, SLOT(slotCopy()), m_actionCollection, "edit_copy"); m_pasteAction = KStandardAction::paste(this, SLOT(slotPaste()), m_actionCollection, "edit_paste"); m_filterActions = new KActionMenu(i18n("&Filter Options"), "", m_actionCollection, "edit_filter_options"); m_alwaysSkipAction = new KAction(i18n("Always &skip this file when queuing"), KShortcut(), this, SLOT(slotAlwaysSkip()), m_actionCollection); m_topPriorityAction = new KAction(i18n("Make this file &top priority"), KShortcut(), this, SLOT(slotTopPriority()), m_actionCollection); m_lowPriorityAction = new KAction(i18n("Make this file &lowest priority"), KShortcut(), this, SLOT(slotLowPriority()), m_actionCollection); m_filterActions->insert(m_alwaysSkipAction); m_filterActions->insert(m_topPriorityAction); m_filterActions->insert(m_lowPriorityAction); m_transferAction = new KAction(i18n("&Transfer"), KShortcut(), this, SLOT(slotTransfer()), m_actionCollection, "transfer"); m_queueTransferAction = new KAction(i18n("&Queue Transfer"), "mail-queue", KShortcut(), this, SLOT(slotQueueTransfer()), m_actionCollection, "queue_transfer"); m_createDirAction = new KAction(i18n("&Create Directory..."), "folder-new", KShortcut(), this, SLOT(slotCreateDir()), m_actionCollection, "create_dir"); m_fileEditAction = new KAction(i18n("&Open file"), "document-open", KShortcut(), this, SLOT(slotFileEdit()), m_actionCollection, "open_file"); m_verifyAction = new KAction(i18n("&Verify..."), "dialog-ok", KShortcut(), this, SLOT(slotVerify()), m_actionCollection, "verify"); populateEncodings(); m_moreActions = new KActionMenu(i18n("&More Actions"), "configure", this); m_rawCmdAction = new KAction(i18n("&Manual Command Entry..."), "utilities-terminal", KShortcut(), this, SLOT(slotRawCmd()), m_actionCollection, "send_raw_cmd"); m_exportListingAction = new KAction(i18n("&Export Directory Listing..."), "", KShortcut(), this, SLOT(slotExportListing()), m_actionCollection, "export_listing"); m_showHiddenFilesAction = new KToggleAction(i18n("Show &Hidden Files && Directories"), KShortcut(), this, SLOT(slotShowHiddenFiles()), m_actionCollection, "show_hidden"); m_openExternalAction = new KAction(i18n("Open current directory in &Konqueror..."), "konqueror", KShortcut(), this, SLOT(slotOpenExternal()), m_actionCollection, "open_konqi"); m_markItemsAction = new KAction(i18n("Compare &selected items"), "", KShortcut(Qt::Key_Space), this, SLOT(slotMarkItems()), m_actionCollection, "compare_selected"); m_compareAction = new KAction(i18n("Compare &directories"), "", KShortcut(), this, SLOT(slotCompare()), m_actionCollection, "compare_dirs"); m_showHiddenFilesAction->setChecked(KFTPCore::Config::showHiddenFiles()); m_rawCommandsMenu = CustomCommands::Manager::self()->categories(i18n("Send &Raw Command"), m_view->getSession()); m_rawCommandsMenu->insert(m_rawCmdAction, 0); m_rawCommandsMenu->popupMenu()->insertSeparator(1); m_moreActions->insert(m_rawCommandsMenu); m_moreActions->insert(m_changeEncodingAction); m_moreActions->popupMenu()->insertSeparator(); m_moreActions->insert(m_exportListingAction); m_moreActions->insert(m_openExternalAction); m_moreActions->insert(m_markItemsAction); m_moreActions->insert(m_compareAction); m_moreActions->popupMenu()->insertSeparator(); m_moreActions->insert(m_showHiddenFilesAction); m_moreActions->setStickyMenu(true); m_moreActions->setDelayed(false); */ m_toggleTreeViewAction = new KToggleAction(this); m_toggleTreeViewAction->setText(i18n("&Toggle Tree View")); m_toggleTreeViewAction->setIcon(KIcon("view-sidetree")); connect(m_toggleTreeViewAction, SIGNAL(triggered()), this, SLOT(slotToggleTree())); m_createDirAction = new KAction(this); m_createDirAction->setText(i18n("&Create Directory...")); m_createDirAction->setIcon(KIcon("folder-new")); connect(m_createDirAction, SIGNAL(triggered()), this, SLOT(slotCreateDir())); m_siteChangeAction = new KActionMenu(KIcon("network-server"), i18n("&Change Site"), this); m_quickConnectAction = new KAction(this); m_quickConnectAction->setText(i18n("&Quick Connect...")); m_quickConnectAction->setIcon(KIcon("network-connect")); connect(m_quickConnectAction, SIGNAL(triggered()), this, SLOT(slotQuickConnect())); m_connectAction = new KActionMenu(i18n("&Connect To"), this); m_disconnectAction = new KAction(this); m_disconnectAction->setText(i18n("&Disconnect")); m_disconnectAction->setIcon(KIcon("network-disconnect")); connect(m_disconnectAction, SIGNAL(triggered()), this, SLOT(slotDisconnect())); m_siteChangeAction->addAction(m_quickConnectAction); m_siteChangeAction->addAction(m_connectAction); m_siteChangeAction->addAction(m_disconnectAction); m_siteChangeAction->setStickyMenu(true); m_siteChangeAction->setDelayed(false); actionCollection->addAction("site_change", m_siteChangeAction); } void Actions::populateEncodings() { /* // Charsets m_changeEncodingAction = new KActionMenu(i18n("Change Remote &Encoding"), "charset", m_actionCollection, "changeremoteencoding"); m_changeEncodingAction->setDelayed(false); KMenu *menu = m_changeEncodingAction->popupMenu(); menu->clear(); QStringList charsets = KGlobal::charsets()->descriptiveEncodingNames(); int count = 0; for (QStringList::iterator i = charsets.begin(); i != charsets.end(); ++i) menu->insertItem(*i, this, SLOT(slotCharsetChanged(int)), 0, ++count); menu->insertSeparator(); menu->insertItem(i18n("Default"), this, SLOT(slotCharsetReset(int)), 0, ++count); menu->setItemChecked(count, true); m_defaultCharsetOption = count; m_curCharsetOption = count; */ } void Actions::updateActions() { LocationNavigator *navigator = m_view->locationNavigator(); int index = 0; const QList list = navigator->history(index); m_goUpAction->setEnabled(navigator->url().upUrl() != navigator->url()); m_goBackAction->setEnabled(index < list.count() - 1); m_goForwardAction->setEnabled(index > 0); m_disconnectAction->setEnabled(m_view->session()->isRemote() && m_view->session()->isConnected()); /* m_goUpAction->setEnabled(m_view->url().upUrl() != m_view->url()); // History int index = 0; const Q3ValueList list = m_view->history(index); m_goBackAction->setEnabled(index < static_cast(list.count()) - 1); m_goForwardAction->setEnabled(index > 0); m_abortAction->setEnabled(m_view->m_ftpClient->socket()->isBusy()); m_toggleTreeViewAction->setEnabled(true); m_toggleFilterAction->setEnabled(true); m_quickConnectAction->setEnabled(m_view->url().isLocalFile()); m_connectAction->setEnabled(true); m_disconnectAction->setEnabled(m_view->m_ftpClient->socket()->isConnected()); const KFileItemList *selectedItems = m_view->selectedItems(); if (selectedItems->count() == 1) { m_fileEditAction->setEnabled(!selectedItems->getFirst()->isDir()); m_verifyAction->setEnabled(selectedItems->getFirst()->isLocalFile() && selectedItems->getFirst()->name(true).right(3) == "sfv"); } else { m_fileEditAction->setEnabled(false); m_verifyAction->setEnabled(false); } // Check if we can transfer anything KFTPSession::Session *session = m_view->m_session; KFTPSession::Session *opposite = KFTPSession::Manager::self()->getActive(oppositeSide(m_view->m_session->getSide())); m_renameAction->setEnabled(session->isConnected()); m_deleteAction->setEnabled(session->isConnected()); m_propsAction->setEnabled(true); m_shredAction->setEnabled(!session->isRemote()); m_copyAction->setEnabled(true); m_pasteAction->setEnabled(true); if ((!session->isRemote() && !opposite->isRemote()) || ( (session->isRemote() && opposite->isRemote()) && ( session->getClient()->socket()->protocolName() != opposite->getClient()->socket()->protocolName() || !(session->getClient()->socket()->features() & SF_FXP_TRANSFER) ) ) ) { m_queueTransferAction->setEnabled(false); m_transferAction->setEnabled(false); } else { m_queueTransferAction->setEnabled(true); m_transferAction->setEnabled(true); } if (!session->isRemote() || session->getClient()->socket()->isConnected()) m_createDirAction->setEnabled(true); else m_createDirAction->setEnabled(false); m_changeEncodingAction->setEnabled(session->isRemote()); m_rawCmdAction->setEnabled(!m_view->url().isLocalFile() && m_view->m_ftpClient->socket()->features() & SF_RAW_COMMAND); m_rawCommandsMenu->setEnabled(m_rawCmdAction->isEnabled()); m_openExternalAction->setEnabled(!session->isRemote()); */ } void Actions::slotGoUp() { m_view->goUp(); } void Actions::slotGoBack() { m_view->goBack(); } void Actions::slotGoForward() { m_view->goForward(); } void Actions::slotReload() { m_view->reload(); } void Actions::slotGoHome() { m_view->goHome(); } void Actions::slotQuickConnect() { Bookmarks::Editor editor(0, true); if (editor.exec()) KFTPBookmarks::Manager::self()->connectWithSite(editor.selectedSite(), m_view->session()); } void Actions::slotDisconnect() { if (m_view->session()->isRemote() && m_view->session()->isConnected()) { if (KFTPCore::Config::confirmDisconnects() && KMessageBox::warningYesNo(0, i18n("Do you want to drop current connection?")) == KMessageBox::No) return; m_view->session()->disconnectAllConnections(); } } void Actions::slotShred() { /* // Shred the file if (KMessageBox::warningContinueCancel(0, i18n("Are you sure you want to SHRED this file?"), i18n("Shred File"),KGuiItem(i18n("&Shred"), "editshred")) == KMessageBox::Cancel) return; KShred::shred(m_view->selectedItems()->getFirst()->url().path()); */ } void Actions::slotRename() { /* KFTPWidgets::Browser::DetailsView *view = m_view->getDetailsView(); // Rename the first file in the current selection view->rename(view->K3ListView::selectedItems().at(0), 0); // Enhanced rename: Don't highlight the file extension. (from Konqueror) KLineEdit *le = view->renameLineEdit(); if (le) { const QString txt = le->text(); QString pattern; KMimeType::diagnoseFileName(txt, pattern); if (!pattern.isEmpty() && pattern.at(0) == '*' && pattern.find('*',1) == -1) le->setSelection(0, txt.length()-pattern.trimmed().length()+1); else { int lastDot = txt.findRev('.'); if (lastDot > 0) le->setSelection(0, lastDot); } } */ } void Actions::slotDelete() { /* KFTPSession::Session *session = m_view->getSession(); // Delete a file or directory KUrl::List selection = m_view->selectedURLs(); KUrl::List::ConstIterator i = selection.begin(); QStringList prettyList; for (; i != selection.end(); ++i) { prettyList.append((*i).pathOrUrl()); } if (KMessageBox::warningContinueCancelList(0, i18n("Do you really want to delete this item?", "Do you really want to delete these %n items?", prettyList.count()), prettyList, i18n("Delete Files"), KStandardGuiItem::del(), QString::null, KMessageBox::Dangerous) == KMessageBox::Cancel) return; // Go trough all files and delete them if (!session->isRemote()) { KIO::del(selection); } else { KUrl::List::Iterator end(selection.end()); for (KUrl::List::Iterator i(selection.begin()); i != end; ++i) { if (!(*i).isLocalFile()) session->getClient()->remove(KUrl((*i).url())); } } */ } void Actions::slotCopy() { /* QClipboard *cb = QApplication::clipboard(); cb->setData(m_view->getDetailsView()->dragObject(), QClipboard::Clipboard); */ } void Actions::slotPaste() { /* // Decode the data and try to init transfer KIO::MetaData p_meta; KUrl::List p_urls; if (KURLDrag::decode(QApplication::clipboard()->data(), p_urls, p_meta)) { // Add destination url and call the QueueManager p_meta.insert("DestURL", m_view->url().url()); KURLDrag *drag = new KURLDrag(p_urls, p_meta, m_view, name()); KFTPQueue::Manager::self()->insertTransfer(drag); } */ } void Actions::slotProps() { /* // Show file properties const KFileItemList *selectedItems = m_view->selectedItems(); KFileItem *item = selectedItems->getFirst(); if (selectedItems->count() == 0) { if (m_view->url().isLocalFile()) item = new KFileItem(m_view->url(), 0, 0); else return; } // Show the dialog KPropertiesDialog *propsDialog; if (item->isLocalFile()) { if (selectedItems->count() == 0) propsDialog = new KPropertiesDialog(item); else propsDialog = new KPropertiesDialog(*selectedItems); } else { propsDialog = new KPropertiesDialog(item->name()); propsDialog->insertPlugin(new KFTPWidgets::Browser::PropsPlugin(propsDialog, *selectedItems)); propsDialog->insertPlugin(new KFTPWidgets::Browser::PermissionsPropsPlugin(propsDialog, *selectedItems, m_view->getSession())); } propsDialog->exec(); */ } void Actions::addPriorityItems(int priority) { /* // Add the files to skiplist KUrl::List selection = m_view->selectedURLs(); KUrl::List::Iterator end(selection.end()); for (KUrl::List::Iterator i(selection.begin()); i != end; ++i) { Rule *rule = new Rule(); if (priority == 0) { rule->setName(i18n("Skip '%1'",(*i).filename())); const_cast(rule->conditions())->append(new Condition(Filename, Condition::Is, (*i).filename())); const_cast(rule->actions())->append(new Action(Action::Skip, QVariant())); } else { rule->setName(i18n("Priority '%1'",(*i).filename())); const_cast(rule->conditions())->append(new Condition(Filename, Condition::Is, (*i).filename())); const_cast(rule->actions())->append(new Action(Action::Priority, priority)); } Filters::self()->append(rule); } */ } void Actions::slotAlwaysSkip() { addPriorityItems(0); } void Actions::slotTopPriority() { addPriorityItems(1); } void Actions::slotLowPriority() { addPriorityItems(-1); } void Actions::slotTransfer() { /* // Queue a transfer KFileItemList list(*m_view->selectedItems()); KFileItemListIterator i(list); KFileItem *item; KFTPSession::Session *opposite = KFTPSession::Manager::self()->getActive(oppositeSide(m_view->m_session->getSide())); KFTPQueue::Transfer *transfer = 0L; while ((item = i.current()) != 0) { KUrl destinationUrl = opposite->getFileView()->url(); destinationUrl.addPath(item->name()); transfer = KFTPQueue::Manager::self()->spawnTransfer( item->url(), destinationUrl, item->size(), item->isDir(), list.count() == 1, true, 0L, true ); ++i; } // Execute transfer if (transfer) static_cast(transfer->parentObject())->delayedExecute(); */ } void Actions::slotQueueTransfer() { KFTPSession::Session *oppositeSession = m_view->session()->oppositeSession(); QModelIndexList indexes = m_view->selectedIndexes(); KUrl oppositeUrl = oppositeSession->getFileView()->locationNavigator()->url(); foreach (QModelIndex index, indexes) { KFileItem item = index.data(DirModel::FileItemRole).value(); KUrl destinationUrl = oppositeUrl; destinationUrl.addPath(item.name()); KFTPQueue::Manager::self()->spawnTransfer( item.url(), destinationUrl, item.size(), item.isDir(), indexes.count() == 1, true, 0, indexes.count() > 1 ); } /* // Queue a transfer KFileItemList list(*m_view->selectedItems()); KFileItemListIterator i(list); KFileItem *item; KFTPSession::Session *opposite = KFTPSession::Manager::self()->getActive(oppositeSide(m_view->m_session->getSide())); while ((item = i.current()) != 0) { KUrl destinationUrl = opposite->getFileView()->url(); destinationUrl.addPath(item->name()); KFTPQueue::Manager::self()->spawnTransfer( item->url(), destinationUrl, item->size(), item->isDir(), list.count() == 1, true, 0L, list.count() > 1 ); ++i; } */ } void Actions::slotCreateDir() { /* // Create new directory bool ok; QString newDirName = KInputDialog::getText(i18n("Create Directory"), i18n("Directory name:"), "", &ok); if (ok) { KUrl url = m_view->url(); url.addPath(newDirName); if (url.isLocalFile()) KIO::mkdir(url); else m_view->m_ftpClient->mkdir(url); } */ } void Actions::slotFileEdit() { /* KFileItem *item = m_view->selectedItems()->getFirst(); if (!item->isDir()) { if (item->isLocalFile()) { item->run(); } else { // Create a new transfer to download the file and open it KFTPQueue::TransferFile *transfer = new KFTPQueue::TransferFile(KFTPQueue::Manager::self()); transfer->setSourceUrl(item->url()); transfer->setDestUrl(KUrl(KGlobal::dirs()->saveLocation("tmp") + QString("%1-%2").arg(KRandom::randomString(7)).arg(item->name()))); transfer->addSize(item->size()); transfer->setTransferType(KFTPQueue::Download); transfer->setOpenAfterTransfer(true); KFTPQueue::Manager::self()->insertTransfer(transfer); // Execute the transfer transfer->delayedExecute(); } } */ } void Actions::slotAbort() { /* KFTPSession::Session *session = KFTPSession::Manager::self()->find(m_view); // Abort the session if (session) session->abort(); */ } void Actions::slotRawCmd() { /* bool ok; QString rawCmd = KInputDialog::getText(i18n("Send Raw Command"), i18n("Command:"), "", &ok); if (ok) m_view->m_ftpClient->raw(rawCmd); */ } void Actions::slotToggleTree() { m_view->setTreeVisible(m_toggleTreeViewAction->isChecked()); m_view->m_treeVisibilityChanged = true; } void Actions::slotToggleFilter() { /* if (m_toggleFilterAction->isChecked()) { m_view->m_searchToolBar->show(); m_view->m_searchFilter->clear(); m_view->m_searchFilter->setFocus(); } else { m_view->m_searchFilter->clear(); m_view->m_searchToolBar->hide(); } */ } void Actions::slotCharsetChanged(int id) { /* if (!m_changeEncodingAction->popupMenu()->isItemChecked(id)) { QStringList charsets = KGlobal::charsets()->descriptiveEncodingNames(); QString charset = KGlobal::charsets()->encodingForName(charsets[id - 1]); // Set the current socket's charset m_view->m_ftpClient->socket()->changeEncoding(charset); // Update checked items m_changeEncodingAction->popupMenu()->setItemChecked(id, true); m_changeEncodingAction->popupMenu()->setItemChecked(m_curCharsetOption, false); m_curCharsetOption = id; } */ } void Actions::slotCharsetReset(int id) { /* // Revert to default charset if possible KFTPBookmarks::Site *site = m_view->m_session->getSite(); if (site) { // Set the current socket's charset m_view->m_ftpClient->socket()->changeEncoding(site->getProperty("encoding")); // Update checked items m_changeEncodingAction->popupMenu()->setItemChecked(id, true); m_changeEncodingAction->popupMenu()->setItemChecked(m_curCharsetOption, false); m_curCharsetOption = id; } */ } void Actions::slotExportListing() { /* QString savePath = KFileDialog::getSaveFileName(QString::null, i18n("*.txt|Directory Dump"), 0, i18n("Export Directory Listing")); if (!savePath.isEmpty()) { QFile file(savePath); if (!file.open(QIODevice::WriteOnly)) return; Q3TextStream stream(&file); KFileItemList list(*m_view->items()); KFileItemListIterator i(list); KFileItem *item; while ((item = i.current()) != 0) { stream << item->permissionsString() << "\t"; stream << item->user() << "\t" << item->group() << "\t"; stream << item->timeString() << "\t"; stream << item->name() << "\t"; stream << "\n"; ++i; } file.flush(); file.close(); } */ } void Actions::slotVerify() { /* KFTPWidgets::Verifier *verifier = new KFTPWidgets::Verifier(); verifier->setFile(m_view->selectedItems()->getFirst()->url().path()); verifier->exec(); delete verifier; */ } void Actions::slotShowHiddenFiles() { /* m_view->setShowHidden(m_showHiddenFilesAction->isChecked()); m_view->reload(); */ } void Actions::slotOpenExternal() { /* KFileItem *folder = new KFileItem(m_view->url(), "inode/directory", S_IFDIR); folder->run(); */ } void Actions::slotMarkItems() { /* KFileItemList list(*m_view->selectedItems()); KFileItemListIterator i(list); KFileItem *item; KFTPSession::Session *opposite = KFTPSession::Manager::self()->getActive(oppositeSide(m_view->m_session->getSide())); DetailsView *tView = m_view->getDetailsView(); DetailsView *oView = opposite->getFileView()->getDetailsView(); while ((item = i.current()) != 0) { tView->markItem(item); oView->markItem(item->name()); ++i; } */ } void Actions::slotCompare() { /* KFTPSession::Session *opposite = KFTPSession::Manager::self()->getActive(oppositeSide(m_view->m_session->getSide())); DetailsView *tView = m_view->getDetailsView(); DetailsView *oView = opposite->getFileView()->getDetailsView(); // All items in the other list view should be visible by default Q3ListViewItemIterator j(oView); while (j.current()) { KFileItem *oItem = static_cast(*j)->fileInfo(); oView->setItemVisibility(oItem, true); ++j; } // Compare the two listviews Q3ListViewItemIterator i(tView); while (i.current()) { KFileItem *tItem = static_cast(*i)->fileInfo(); if (tItem) { KFileItem *oItem = oView->fileItem(tItem->name()); if (oItem && (oItem->size() == tItem->size() || oItem->isDir())) { tView->setItemVisibility(tItem, false); oView->setItemVisibility(oItem, false); } else { tView->setItemVisibility(tItem, true); } } ++i; } PopupMessage *popup = new PopupMessage(m_view->getStatusLabel(), m_view); popup->setText(i18n("Identical files on both sides have been hidden. Only different files are now visible.")); popup->setImage(SmallIcon("dialog-information")); popup->setShowCloseButton(false); popup->setShowCounter(false); popup->reposition(); popup->display(); */ } } } #include "actions.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/browser/dirlister.cpp0000644000175000017500000001326211276037142024034 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "dirlister.h" #include "kftpsession.h" #include "engine/thread.h" #include "engine/cache.h" #include #include using namespace KFTPEngine; using namespace KFTPSession; namespace KFTPWidgets { namespace Browser { ReportingDirLister::ReportingDirLister(QObject *parent) : KDirLister(parent) { } ReportingDirLister::~ReportingDirLister() { } void ReportingDirLister::handleError(KIO::Job *job) { emit errorMessage(job->errorString()); } DirLister::DirLister(QObject *parent) : QObject(parent), m_remoteSession(0), m_showHidden(false), m_dirOnly(false), m_ignoreChanges(false), m_mode(None) { m_localLister = new ReportingDirLister(this); m_localLister->setAutoUpdate(true); } DirLister::~DirLister() { } void DirLister::setSession(Session *session) { m_remoteSession = session; } KFileItem *DirLister::rootItem() const { KUrl url = m_lastUrl; url.setPath("/"); return new KFileItem(url, "inode/directory", S_IFDIR); } void DirLister::openUrl(const KUrl &url, KDirLister::OpenUrlFlags flags) { if (m_lastUrl.isLocalFile() != url.isLocalFile()) { emit siteChanged(url); emit clear(); } if (!(flags & KDirLister::Keep)) m_ignoreChanges = false; m_lastUrl = url; m_lastUrl.adjustPath(KUrl::RemoveTrailingSlash); if (url.isLocalFile()) { setRemoteEnabled(false); m_localLister->stop(); m_localLister->setShowingDotFiles(m_showHidden); m_localLister->setDirOnlyMode(m_dirOnly); m_localLister->openUrl(url, flags); } else if (m_remoteSession && m_remoteSession->isConnected()) { setRemoteEnabled(true); if (flags & KDirLister::Reload) { KUrl tmp = url; Cache::self()->invalidateEntry(tmp); } if (!(flags & KDirLister::Keep)) emit clear(); m_remoteSession->getClient()->list(url); } } void DirLister::setRemoteEnabled(bool enabled, bool withoutLocal) { Thread *client = m_remoteSession->getClient(); // Disconnect everything and reset to default mode m_localLister->QObject::disconnect(this); client->eventHandler()->QObject::disconnect(this); if (enabled) { connect(client->eventHandler(), SIGNAL(engineEvent(KFTPEngine::Event*)), this, SLOT(slotRemoteEngineEvent(KFTPEngine::Event*))); m_mode = Remote; } else if (!withoutLocal) { connect(m_localLister, SIGNAL(clear()), this, SIGNAL(clear())); connect(m_localLister, SIGNAL(completed()), this, SIGNAL(completed())); connect(m_localLister, SIGNAL(deleteItem(const KFileItem&)), this, SIGNAL(deleteItem(const KFileItem&))); connect(m_localLister, SIGNAL(refreshItems(const QList >&)), this, SIGNAL(refreshItems(const QList >&))); connect(m_localLister, SIGNAL(newItems(KFileItemList)), this, SIGNAL(newItems(KFileItemList))); connect(m_localLister, SIGNAL(errorMessage(const QString&)), this, SIGNAL(errorMessage(const QString&))); m_mode = Local; } } void DirLister::stop() { if (m_lastUrl.isLocalFile()) m_localLister->stop(); } void DirLister::slotRemoteEngineEvent(KFTPEngine::Event *event) { switch (event->type()) { case Event::EventError: { emit errorMessage(i18n("Could not enter folder %1.", m_lastUrl.path())); setRemoteEnabled(false, true); break; } case Event::EventDirectoryListing: { m_items.clear(); // Populate the item list QList list = event->getParameter(0).value().list(); QList::ConstIterator end(list.end()); for (QList::ConstIterator i(list.begin()); i != end; ++i) { if (!m_showHidden && (*i).filename().at(0) == '.') continue; if (m_dirOnly && !(*i).isDirectory()) continue; m_items.append(KFileItem((*i).toUdsEntry(), m_lastUrl, false, true)); } setRemoteEnabled(false, true); emit newItems(m_items); emit completed(); break; } default: break; } } } } #include "dirlister.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/browser/locationnavigator.h0000644000175000017500000001254211276037142025223 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_BROWSERLOCATIONNAVIGATOR_H #define KFTPWIDGETS_BROWSERLOCATIONNAVIGATOR_H #include #include #include #include namespace KFTPWidgets { namespace Browser { class DetailsView; /** * This class contains the current navigational history and enables * moving through it. * * @author Jernej Kos */ class LocationNavigator : public QObject { Q_OBJECT public: /** * An Element instance represents one history element. The class contains * information about the URL, the selected item and the contents position. */ class Element { public: /** * Class constructor. */ Element(); /** * Class constructor. * * @param url Element's URL */ Element(const KUrl &url); /** * Returns the element's URL. */ const KUrl &url() const { return m_url; } /** * Set currently selected item. * * @param item The item that is currently selected */ void setCurrentItem(const KFileItem &item) { m_currentItem = item; } /** * Returns the selected filename. */ const KFileItem ¤tItem() const { return m_currentItem; } /** * Set current contents X position. * * @param x Contents X position */ void setContentsX(int x) { m_contentsX = x; } /** * Returns the saved contents X position. */ int contentsX() const { return m_contentsX; } /** * Set current contents Y position. * * @param y Contents Y position */ void setContentsY(int y) { m_contentsY = y; } /** * Returns the saved contents Y position. */ int contentsY() const { return m_contentsY; } private: KUrl m_url; KFileItem m_currentItem; int m_contentsX; int m_contentsY; }; /** * Class constructor. * * @param view Parent view */ LocationNavigator(DetailsView *view); /** * Set a new current URL. Calling this will emit the urlChanged signal. * * @param url Wanted URL */ void setUrl(const KUrl &url); /** * Returns the current URL. */ const KUrl &url() const; /** * Returns the current history elements. * * @param index Variable to save the current history position to * @return Current history element list */ const QList history(int &index) const; /** * Go one history hop back. */ void goBack(); /** * Go one history hop forward. */ void goForward(); /** * Go up in the directory structure. */ void goUp(); /** * Go the the predefined home URL. */ void goHome(); /** * Set the home URL. * * @param url URL to use as home URL */ void setHomeUrl(const KUrl &url) { m_homeUrl = url; } /** * Clear current history. */ void clear(); signals: /** * This signal is emitted whenever the current URL changes. * * @param url The new URL */ void urlChanged(const KUrl &url); /** * This signal is emitted whenever the history is updated. * * @param url Current URL */ void historyChanged(const KUrl &url); private slots: void slotContentsMoved(int x, int y); private: DetailsView *m_view; int m_historyIndex; QList m_history; KUrl m_homeUrl; void updateCurrentElement(); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/browser/view.cpp0000644000175000017500000003705511276037142023013 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "browser/view.h" #include "browser/detailsview.h" #include "browser/treeview.h" #include "browser/actions.h" //#include "browser/filterwidget.h" #include "browser/dirlister.h" #include "browser/dirmodel.h" #include "browser/dirsortfilterproxymodel.h" #include "widgets/popupmessage.h" #include "kftpbookmarks.h" #include "misc/config.h" #include "kftpsession.h" #include "engine/ftpsocket.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KFTPEngine; namespace KFTPWidgets { namespace Browser { class HistoryPixmapProvider : public KPixmapProvider { public: QPixmap pixmapFor(const QString &text, int size = 0) { Q_UNUSED(text) Q_UNUSED(size) return KIcon("folder").pixmap(16, 16); } }; View::View(QWidget *parent, KFTPEngine::Thread *client, KFTPSession::Session *session) : QWidget(parent), m_session(session), m_ftpClient(client), m_freezeUrlUpdates(false), m_treeVisibilityChanged(false) { m_connTimer = new QTimer(this); // Create the GUI init(); populateToolbar(); // Let us be up to date with bookmark changes connect(KFTPBookmarks::Manager::self(), SIGNAL(update()), this, SLOT(updateBookmarks())); // Some other stuff connect(m_ftpClient->eventHandler(), SIGNAL(engineEvent(KFTPEngine::Event*)), this, SLOT(slotEngineEvent(KFTPEngine::Event*))); connect(m_connTimer, SIGNAL(timeout()), this, SLOT(slotDurationUpdate())); // Config updates to hide/show the tree connect(KFTPCore::Config::self(), SIGNAL(configChanged()), this, SLOT(slotConfigUpdate())); slotConfigUpdate(); } View::~View() { } void View::init() { // Init actions m_actions = new Actions(this); m_actions->initActions(); // Layout QVBoxLayout *layout = new QVBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); // Create the toolbars m_toolBarFirst = new KToolBar(this, false, false); m_toolBarSecond = new KToolBar(this, false, false); //m_searchToolBar = new KToolBar(this, false, false); m_toolBarFirst->setContextMenuPolicy(Qt::NoContextMenu); m_toolBarFirst->setMovable(false); //m_toolBarFirst->setFullSize(true); m_toolBarSecond->setContextMenuPolicy(Qt::NoContextMenu); m_toolBarSecond->setMovable(false); //m_toolBarSecond->setFullSize(true); /* m_searchToolBar->setContextMenuEnabled(false); m_searchToolBar->setMovable(false); //m_searchToolBar->setFullSize(true); QLabel *filterLabel = new QLabel(i18n("Filter: "), m_searchToolBar); m_searchToolBar->insertWidget(1, 35, filterLabel); */ // Create the labels QLabel *pathLabel = new QLabel(i18n("Path: "), m_toolBarSecond); m_toolBarSecond->addWidget(pathLabel); // Create the history combo m_historyCombo = new KHistoryComboBox(true, m_toolBarSecond); m_toolBarSecond->addWidget(m_historyCombo); m_historyCombo->setPixmapProvider(new HistoryPixmapProvider()); m_historyCombo->setMaxCount(25); m_historyCombo->setMaxVisibleItems(25); m_historyCombo->setDuplicatesEnabled(false); m_historyCombo->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); connect(m_historyCombo, SIGNAL(activated(const QString&)), this, SLOT(slotHistoryActivated(const QString&))); connect(m_historyCombo->lineEdit(), SIGNAL(returnPressed()), this, SLOT(slotHistoryActivated())); // Create a splitter m_splitter = new QSplitter(this); m_splitter->setOpaqueResize(true); m_splitter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); // Create a status bar QHBoxLayout *statusLayout = new QHBoxLayout(this); statusLayout->setMargin(0); m_connDurationMsg = new QLabel(this); m_connDurationMsg->setAlignment(Qt::AlignCenter); m_connDurationMsg->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); m_connDurationMsg->setMinimumWidth(100); m_statusIcon = new QPushButton(this); m_statusIcon->setFlat(true); m_statusIcon->setIcon(KIcon("object-locked")); m_statusIcon->setEnabled(false); connect(m_statusIcon, SIGNAL(clicked()), this, SLOT(slotDisplayCertInfo())); m_statusMsg = new QLabel(this); m_statusMsg->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); m_statusMsg->setText(i18n("Idle.")); statusLayout->addWidget(m_statusMsg, 1); statusLayout->addWidget(m_connDurationMsg); statusLayout->addWidget(m_statusIcon); // Add toolbars to the layout layout->addWidget(m_toolBarFirst); layout->addWidget(m_toolBarSecond); layout->addWidget(m_splitter/*, 10*/); //layout->addWidget(m_searchToolBar); layout->addLayout(statusLayout); m_dirLister = new DirLister(this); m_dirLister->setSession(m_session); connect(m_dirLister, SIGNAL(completed()), m_actions, SLOT(updateActions())); connect(m_dirLister, SIGNAL(errorMessage(const QString&)), this, SLOT(showError(const QString&))); // Create the tree view m_treeView = new TreeView(m_splitter, this); m_splitter->addWidget(m_treeView); m_treeView->hide(); m_dirModel = new DirModel(m_dirLister, this); m_dirModel->setDropsAllowed(DirModel::DropOnDirectory); m_proxyModel = new DirSortFilterProxyModel(this); m_proxyModel->setSourceModel(m_dirModel); // Create the details view m_detailsView = new DetailsView(m_splitter, this); m_detailsView->setModel(m_proxyModel); m_detailsView->sortByColumn(DirModel::Name, Qt::AscendingOrder); m_splitter->addWidget(m_detailsView); m_locationNavigator = new LocationNavigator(m_detailsView); connect(m_locationNavigator, SIGNAL(urlChanged(const KUrl&)), this, SLOT(slotUrlChanged(const KUrl&))); connect(m_locationNavigator, SIGNAL(historyChanged(const KUrl&)), this, SLOT(slotHistoryChanged(const KUrl&))); openUrl(KUrl(KFTPCore::Config::defLocalDir())); // TODO // Create the filter widget /* m_searchFilter = new FilterWidget(m_searchToolBar, m_detailsView); m_searchToolBar->setItemAutoSized(2, true); m_searchToolBar->setStretchableWidget(m_searchFilter); m_searchToolBar->updateRects(true); m_searchToolBar->hide(); */ } void View::slotUrlChanged(const KUrl &url) { if (!m_freezeUrlUpdates) connect(m_dirLister, SIGNAL(completed()), this, SLOT(slotListingCompleted())); else m_freezeUrlUpdates = false; m_dirLister->openUrl(url); } void View::slotListingCompleted() { int index = 0; const QList history = m_locationNavigator->history(index); if (!history.isEmpty()) { LocationNavigator::Element element = history[index]; const KFileItem fileItem = element.currentItem(); if (!fileItem.isNull()) { m_detailsView->setCurrentIndex(m_proxyModel->mapFromSource(m_dirModel->indexForItem(fileItem))); m_detailsView->horizontalScrollBar()->setValue(element.contentsX()); m_detailsView->verticalScrollBar()->setValue(element.contentsY()); } } disconnect(m_dirLister, SIGNAL(completed()), this, SLOT(slotListingCompleted())); emit urlChanged(m_locationNavigator->url()); } void View::openUrl(const KUrl &url) { m_locationNavigator->setUrl(url); } void View::openIndex(const QModelIndex &index) { KFileItem item = index.data(DirModel::FileItemRole).value(); if (item.isDir()) { m_freezeUrlUpdates = true; openUrl(item.url()); } } void View::setShowHidden(bool value) { m_dirLister->setShowingDotFiles(value); } void View::setHomeUrl(const KUrl &url) { m_locationNavigator->setHomeUrl(url); } void View::goHome() { m_locationNavigator->goHome(); } void View::goBack() { m_locationNavigator->goBack(); } void View::goForward() { m_locationNavigator->goForward(); } void View::goUp() { m_locationNavigator->goUp(); } void View::reload() { m_dirLister->openUrl(m_locationNavigator->url(), KDirLister::Reload); } void View::rename(const KUrl &source, const QString &name) { KUrl dest(source.upUrl()); dest.addPath(name); if (source.isLocalFile()) KIO::rename(source, dest, KIO::HideProgressInfo); else m_session->getClient()->rename(source, dest); } void View::slotConfigUpdate() { if (!m_treeVisibilityChanged) setTreeVisible(KFTPCore::Config::showTree()); m_detailsView->setColumnHidden(DirModel::Owner, !KFTPCore::Config::showOwnerGroup()); m_detailsView->setColumnHidden(DirModel::Group, !KFTPCore::Config::showOwnerGroup()); } void View::setTreeVisible(bool visible) { m_treeView->setVisible(visible); m_actions->m_toggleTreeViewAction->setChecked(visible); } void View::populateToolbar() { // Add the actions to the toolbar m_toolBarFirst->addAction(m_actions->m_siteChangeAction); m_toolBarFirst->addSeparator(); m_toolBarFirst->addAction(m_actions->m_goUpAction); m_toolBarFirst->addAction(m_actions->m_goBackAction); m_toolBarFirst->addAction(m_actions->m_goForwardAction); m_toolBarFirst->addAction(m_actions->m_reloadAction); m_toolBarFirst->addSeparator(); m_toolBarFirst->addAction(m_actions->m_goHomeAction); m_toolBarFirst->addAction(m_actions->m_createDirAction); m_toolBarFirst->addSeparator(); m_toolBarFirst->addAction(m_actions->m_toggleTreeViewAction); /*m_actions->m_siteChangeAction->plug(m_toolBarFirst); m_toolBarFirst->insertSeparator(); m_actions->m_goUpAction->plug(m_toolBarFirst); m_actions->m_goBackAction->plug(m_toolBarFirst); m_actions->m_goForwardAction->plug(m_toolBarFirst); m_actions->m_reloadAction->plug(m_toolBarFirst); m_toolBarFirst->insertSeparator(); m_actions->m_goHomeAction->plug(m_toolBarFirst); m_actions->m_createDirAction->plug(m_toolBarFirst); m_toolBarFirst->insertSeparator(); m_actions->m_abortAction->plug(m_toolBarFirst); m_actions->m_toggleTreeViewAction->plug(m_toolBarFirst); m_actions->m_toggleFilterAction->plug(m_toolBarFirst); m_toolBarFirst->insertSeparator(); m_actions->m_moreActions->plug(m_toolBarFirst);*/ } void View::updateBookmarks() { // Repopulate bookmarks menu on updates m_actions->m_connectAction->menu()->clear(); KFTPBookmarks::Manager::self()->populateBookmarksMenu(m_actions->m_connectAction, m_session); } void View::slotHistoryActivated() { KUrl dest = m_locationNavigator->url(); dest.setPath(m_historyCombo->lineEdit()->text()); openUrl(dest); } void View::slotHistoryActivated(const QString &text) { KUrl dest = m_locationNavigator->url(); dest.setPath(text); openUrl(dest); } void View::slotHistoryChanged(const KUrl &url) { QString path = url.path(KUrl::RemoveTrailingSlash); m_historyCombo->addToHistory(path); m_historyCombo->setCurrentIndex(0); } void View::slotDisplayCertInfo() { /* if (m_ftpClient->socket()->protocolName() == "ftp" && m_ftpClient->socket()->isEncrypted()) { KSSLInfoDlg *sslInfo = new KSSLInfoDlg(true, this); sslInfo->exec(); } else if (m_ftpClient->socket()->protocolName() == "sftp") { KMessageBox::information(this, i18n("This is a SSH encrypted connection. No certificate info is currently available.")); } else { KSSLInfoDlg *sslInfo = new KSSLInfoDlg(false, this); sslInfo->exec(); } */ } void View::slotDurationUpdate() { m_connDuration = m_connDuration.addSecs(1); m_connDurationMsg->setText(m_connDuration.toString("hh:mm:ss")); } void View::slotEngineEvent(KFTPEngine::Event *event) { switch (event->type()) { case Event::EventState: { // Set new state m_statusMsg->setText(event->getParameter(0).toString()); break; } case Event::EventConnect: case Event::EventDisconnect: { // Change encryption icon m_statusIcon->setIcon(KIcon(m_ftpClient->socket()->isEncrypted() ? "object-locked" : "object-unlocked")); m_statusIcon->setEnabled(m_ftpClient->socket()->isConnected()); // Start or stop the duration timer if (m_ftpClient->socket()->isConnected()) { m_connTimer->start(1000); m_connDuration.setHMS(0, 0, 0); } else { m_connTimer->stop(); m_connDurationMsg->setText(""); } // Reset selected charset to default /* KMenu *menu = m_actions->m_changeEncodingAction->popupMenu(); menu->setItemChecked(m_actions->m_defaultCharsetOption, true); menu->setItemChecked(m_actions->m_curCharsetOption, false); m_actions->m_curCharsetOption = m_actions->m_defaultCharsetOption; */ break; } default: break; } /* if (m_ftpClient->socket()->isBusy()) { m_tree->setEnabled(false); m_detailsView->setEnabled(false); m_toolBarSecond->setEnabled(false); } else if (KFTPQueue::Manager::self()->getNumRunning(m_ftpClient->socket()->getCurrentUrl()) == 0) { m_tree->setEnabled(true); m_detailsView->setEnabled(true); m_toolBarSecond->setEnabled(true); } */ // Update actions m_actions->updateActions(); } void View::showError(const QString &message) { if (m_infoMessage) delete m_infoMessage; m_infoMessage = new PopupMessage(m_statusMsg, this); m_infoMessage->setText(i18n("Error
") + message); m_infoMessage->setImage(KIcon("dialog-error").pixmap(32, 32)); m_infoMessage->setShowCloseButton(false); m_infoMessage->reposition(); m_infoMessage->display(); } void View::showMessage(const QString &message) { if (m_infoMessage) delete m_infoMessage; m_infoMessage = new PopupMessage(m_statusMsg, this); m_infoMessage->setText(i18n("Information
") + message); m_infoMessage->setImage(KIcon("info").pixmap(32, 32)); m_infoMessage->setShowCloseButton(false); m_infoMessage->reposition(); m_infoMessage->display(); } void View::openContextMenu(const QModelIndexList &indexes, const QPoint &pos) { QMenu menu(this); m_currentIndexes = indexes; // TODO // ContextMenu menu(pos, indexes); // menu.open(); menu.addAction(KIcon("list-add"), i18n("&Queue Transfer"), m_actions, SLOT(slotQueueTransfer())); menu.exec(pos); } } } #include "view.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/browser/propsplugin.h0000644000175000017500000000536511276037142024067 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPFILEPROPSPLUGIN_H #define KFTPFILEPROPSPLUGIN_H #include "engine/directorylisting.h" #include #include namespace KFTPSession { class Session; } namespace KFTPWidgets { namespace Browser { /** * This is a plugin for displaying remote file properties using the * standard KDE file properties dialog. * * @author Jernej Kos */ class PropsPlugin : public KPropsDlgPlugin { Q_OBJECT public: PropsPlugin(KPropertiesDialog *props, KFileItemList items); void applyChanges(); }; /** * This is a plugin for displaying remote file permissions and their * changing using the standard KDE file properties dialog. * * @author Jernej Kos */ class PermissionsPropsPlugin : public KPropsDlgPlugin { Q_OBJECT public: PermissionsPropsPlugin(KPropertiesDialog *props, KFileItemList items, KFTPSession::Session *session); void applyChanges(); private: KFileItemList m_items; KFTPSession::Session *m_session; static mode_t fperm[3][4]; QString m_perms[3]; QCheckBox *m_permsCheck[3][4]; QCheckBox *m_cbRecursive; }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/browser/detailsview.h0000644000175000017500000000575011276037142024023 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_BROWSERDETAILSVIEW_H #define KFTPWIDGETS_BROWSERDETAILSVIEW_H #include "browser/locationnavigator.h" #include #include namespace KFTPSession { class Session; } namespace KFTPWidgets { namespace Browser { class DirLister; class TreeView; class View; /** * This class represents a detailed list view for displaying local and * remote directory contents. It is based upon QTreeView but uses * a custom (wrapped) DirLister for actual listings. * * @author Jernej Kos */ class DetailsView : public QTreeView { Q_OBJECT public: DetailsView(QWidget *parent, View *view); virtual ~DetailsView(); protected: virtual bool event(QEvent* event); virtual void contextMenuEvent(QContextMenuEvent* event); virtual void mouseReleaseEvent(QMouseEvent* event); virtual void dragEnterEvent(QDragEnterEvent* event); virtual void dropEvent(QDropEvent* event); virtual void scrollContentsBy(int dx, int dy); signals: /** * This signals gets emitted when user scrolls the widget. * * @param x New X position * @param y New Y position */ void contentsMoved(int x, int y); /** * This signal is emitted when items change. */ void itemsChanged(); private: QStyleOptionViewItem m_viewOptions; View *m_view; }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/browser/dirlister.h0000644000175000017500000001370411276037142023502 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_BROWSERDIRLISTER_H #define KFTPWIDGETS_BROWSERDIRLISTER_H #include #include #include namespace KFTPSession { class Session; } namespace KFTPEngine { class Event; } namespace KFTPWidgets { namespace Browser { /** * A wrapped KDirLister for proper error reporting. */ class ReportingDirLister : public KDirLister { Q_OBJECT public: /** * Class constructor. */ ReportingDirLister(QObject *parent); /** * Class destructor. */ virtual ~ReportingDirLister(); signals: /** * Emitted when an error ocurrs. */ void errorMessage(const QString &message); protected: /** * @overload * Reimplemented from KDirLister for error handling. */ virtual void handleError(KIO::Job *job); }; /** * This class is a wrapper around KDirLister to support remote listings * via engine sockets. * * @author Jernej Kos */ class DirLister : public QObject { Q_OBJECT public: /** * Current mode of operation. */ enum Mode { None, Local, Remote }; /** * Class constructor. * * @param parent Parent object */ DirLister(QObject *parent); /** * Class destructor. */ ~DirLister(); /** * Set the remote session. If you do not set a valid session, remote operations * will always fail. * * @param session A valid session */ void setSession(KFTPSession::Session *session); /** * Changes the "show hidden files" setting. * * @param value True to enable showing hidden files, false otherwise */ void setShowingDotFiles(bool value) { m_showHidden = value; } /** * Changes the "show only directories" setting. * * @param value True to list only directories, false otherwise */ void setDirOnlyMode(bool value) { m_dirOnly = value; } /** * Sets the ignore changes flag. Note that this does not change the * behavior of this directory lister, it is just a flag for its * subscribers (like the DirModel) to use. * * @param value True to set the ignore changes flag, false otherwise */ void setIgnoreChanges(bool value) { m_ignoreChanges = value; } /** * Fetch a specific location. * * @param url The URL to fetch * @param flags see KDirLister */ void openUrl(const KUrl &url, KDirLister::OpenUrlFlags _flags = KDirLister::NoFlags ); /** * Returns the last open URL. */ KUrl lastUrl() const { return m_lastUrl; } /** * Returns a file item representing the root directory. */ KFileItem *rootItem() const; /** * Returns the session associated with this directory lister. */ KFTPSession::Session *session() const { return m_remoteSession; } /** * Returns the state of ignore changes flag. */ bool ignoringChanges() const { return m_ignoreChanges; } /** * Stop the current listing operation. */ void stop(); protected: void setRemoteEnabled(bool enabled, bool withoutLocal = false); private: ReportingDirLister *m_localLister; KFTPSession::Session *m_remoteSession; KFileItemList m_items; KUrl m_lastUrl; bool m_showHidden; bool m_dirOnly; bool m_ignoreChanges; Mode m_mode; private slots: void slotRemoteEngineEvent(KFTPEngine::Event *event); signals: /** * Emitted when the listing operation has been completed. */ void completed(); /** * Emitted when there are new items. */ void newItems(KFileItemList items); /** * Emitted when an item has to be removed. */ void deleteItem(const KFileItem &item); /** * Emitted when items should be refreshed. */ void refreshItems(const QList > &items); /** * Emitted when all items should be cleared. */ void clear(); /** * Emitted when an error ocurrs and a message should be displayed. * * @param message The message. */ void errorMessage(const QString &message); /** * Emitted when site changes from local to remote or vice-versa. * * @param url New site URL */ void siteChanged(const KUrl &url); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/browser/dirsortfilterproxymodel.h0000644000175000017500000000656111276037142026523 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2007 by the KFTPGrabber developers * Copyright (C) 2007 Jernej Kos * Copyright (C) 2006 by Peter Penz * Copyright (C) 2006 by Dominic Battre * Copyright (C) 2006 by Martin Pool * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_BROWSERDIRSORTFILTERPROXYMODEL_H #define KFTPWIDGETS_BROWSERDIRSORTFILTERPROXYMODEL_H #include namespace KFTPWidgets { namespace Browser { /** * Acts as proxy model for DirModel to sort and filter KFileItems. * * A natural sorting is done. This means that items like: * - item_10.png * - item_1.png * - item_2.png * are sorted like * - item_1.png * - item_2.png * - item_10.png * * It is assured that directories are always sorted before files. * * @author Jernej Kos, Dominic Battre, Martin Pool and Peter Penz */ class DirSortFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT public: DirSortFilterProxyModel(QObject* parent = 0); virtual ~DirSortFilterProxyModel(); /** * Reimplemented from QAbstractItemModel. Returns true for directories. */ virtual bool hasChildren(const QModelIndex& parent = QModelIndex()) const; /** * Reimplemented from QAbstractItemModel. * Returns true for 'empty' directories so they can be populated later. */ virtual bool canFetchMore(const QModelIndex& parent) const; /** * Does a natural comparing of the strings. -1 is returned if \a a * is smaller than \a b. +1 is returned if \a a is greater than \a b. 0 * is returned if both values are equal. */ static int naturalCompare(const QString& a, const QString& b); protected: /** * Reimplemented from QAbstractItemModel to use naturalCompare. */ virtual bool lessThan(const QModelIndex& left, const QModelIndex& right) const; }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/browser/filterwidget.cpp0000644000175000017500000000751711276037142024532 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "browser/filterwidget.h" #include "browser/detailsview.h" #include #include #include #include namespace KFTPWidgets { namespace Browser { FilterWidget::FilterWidget(QWidget *parent, DetailsView *view) : K3ListViewSearchLine(parent, view), m_filterDirectories(true), m_filterSymlinks(true), m_caseSensitive(false) { connect(view, SIGNAL(itemsChanged()), this, SLOT(updateSearch())); } bool FilterWidget::itemMatches(const Q3ListViewItem *item, const QString &pattern) const { if (!pattern.isEmpty()) { const KFileListViewItem *i = dynamic_cast(item); if (i) { if (i->fileInfo()->isDir() && !m_filterDirectories) return true; else if (i->fileInfo()->isLink() && !m_filterSymlinks) return true; } QRegExp filter(pattern); filter.setCaseSensitive(m_caseSensitive); filter.setWildcard(true); return filter.search(item->text(0)) > -1; } return true; } Q3PopupMenu *FilterWidget::createPopupMenu() { Q3PopupMenu *popup = KLineEdit::createPopupMenu(); Q3PopupMenu *subMenu = new Q3PopupMenu(popup); connect(subMenu, SIGNAL(activated(int)), this, SLOT(slotOptionsMenuActivated(int))); popup->insertSeparator(); popup->insertItem(i18n("Filter Options"), subMenu); subMenu->insertItem(i18n("Filter Directories"), FilterWidget::FilterDirectories); subMenu->setItemChecked(FilterWidget::FilterDirectories, m_filterDirectories); subMenu->insertItem(i18n("Filter Symlinks"), FilterWidget::FilterSymlinks); subMenu->setItemChecked(FilterWidget::FilterSymlinks, m_filterSymlinks); subMenu->insertItem(i18n("Case Sensitive"), FilterWidget::CaseSensitive); subMenu->setItemChecked(FilterWidget::CaseSensitive, m_caseSensitive); return popup; } void FilterWidget::slotOptionsMenuActivated(int id) { switch (id) { case FilterDirectories: m_filterDirectories = !m_filterDirectories; break; case FilterSymlinks: m_filterSymlinks = !m_filterSymlinks; break; case Qt::CaseSensitive: m_caseSensitive = !m_caseSensitive; break; default: break; } updateSearch(); } } } #include "filterwidget.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/browser/detailsview.cpp0000644000175000017500000001104011276037142024343 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "browser/detailsview.h" #include "browser/view.h" #include #include #include #include #include namespace KFTPWidgets { namespace Browser { DetailsView::DetailsView(QWidget *parent, View *view) : QTreeView(parent), m_view(view) { setAcceptDrops(true); setRootIsDecorated(false); setSortingEnabled(true); setUniformRowHeights(true); setSelectionBehavior(SelectItems); setDragDropMode(QAbstractItemView::DragDrop); setDropIndicatorShown(false); setSelectionMode(QAbstractItemView::ExtendedSelection); viewport()->setAttribute(Qt::WA_Hover); m_viewOptions = QTreeView::viewOptions(); KFileItemDelegate *delegate = new KFileItemDelegate(this); setItemDelegate(delegate); connect(this, SIGNAL(doubleClicked(const QModelIndex&)), view, SLOT(openIndex(const QModelIndex&))); } DetailsView::~DetailsView() { } bool DetailsView::event(QEvent* event) { if (event->type() == QEvent::Polish) { // Assure that by respecting the available width that: // - the 'Name' column is stretched as large as possible // - the remaining columns are as small as possible QHeaderView *headerView = header(); headerView->setStretchLastSection(false); headerView->setResizeMode(QHeaderView::ResizeToContents); //headerView->setResizeMode(0, QHeaderView::Stretch); // hide columns if this is indicated by the settings /* const DetailsModeSettings* settings = DolphinSettings::instance().detailsModeSettings(); Q_ASSERT(settings != 0); if (!settings->showDate()) { hideColumn(KDirModel::ModifiedTime); } if (!settings->showPermissions()) { hideColumn(KDirModel::Permissions); } if (!settings->showOwner()) { hideColumn(KDirModel::Owner); } if (!settings->showGroup()) { hideColumn(KDirModel::Group); } if (!settings->showType()) { hideColumn(KDirModel::Type); } */ } return QTreeView::event(event); } void DetailsView::contextMenuEvent(QContextMenuEvent* event) { m_view->openContextMenu(selectedIndexes(), event->globalPos()); } void DetailsView::mouseReleaseEvent(QMouseEvent* event) { QTreeView::mouseReleaseEvent(event); // TODO //m_controller->triggerActivation(); } void DetailsView::dragEnterEvent(QDragEnterEvent* event) { if (event->mimeData()->hasUrls()) { event->acceptProposedAction(); } } void DetailsView::dropEvent(QDropEvent* event) { const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); if (!urls.isEmpty()) { event->acceptProposedAction(); // TODO } QTreeView::dropEvent(event); } void DetailsView::scrollContentsBy(int dx, int dy) { QTreeView::scrollContentsBy(dx, dy); const int x = horizontalScrollBar()->value(); const int y = verticalScrollBar()->value(); emit contentsMoved(x, y); } } } #include "detailsview.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/browser/treeview.h0000644000175000017500000000573311276037142023336 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPFILEDIRTREEVIEW_H #define KFTPFILEDIRTREEVIEW_H #include #include namespace KFTPSession { class Session; } namespace KFTPWidgets { namespace Browser { class DirLister; class DirModel; class DirSortFilterProxyModel; class View; class TreeView : public QTreeView { Q_OBJECT public: TreeView(QWidget *parent, View *view); protected: virtual bool event(QEvent* event); virtual void dragEnterEvent(QDragEnterEvent* event); virtual void dragLeaveEvent(QDragLeaveEvent* event); virtual void dragMoveEvent(QDragMoveEvent* event); virtual void dropEvent(QDropEvent* event); virtual void contextMenuEvent(QContextMenuEvent *event); private: View *m_view; DirModel *m_dirModel; DirSortFilterProxyModel *m_proxyModel; bool m_dragging; // TODO: remove this property when the issue #160611 is solved in Qt 4.4 QRect m_dropRect; // TODO: remove this property when the issue #160611 is solved in Qt 4.4 private slots: /** * Selects and expands the currently viewed entry. */ void selectCurrent(); signals: /** * Emitted when URLs are dropped to some index. * * @param url A list of URLs * @param index The index they were dropped on */ void urlsDropped(const KUrl::List& urls, const QModelIndex& index); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/browser/propsplugin.cpp0000644000175000017500000002444611276037142024423 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "browser/propsplugin.h" #include "kftpsession.h" #include #include #include #include //Added by qt3to4: #include #include #include #include #include #include using namespace KFTPEngine; namespace KFTPWidgets { namespace Browser { PropsPlugin::PropsPlugin(KPropertiesDialog *props, KFileItemList items) : KPropsDlgPlugin(props) { QFrame *frame = properties->addPage(i18n("&General")); frame->setMinimumWidth(320); frame->setMinimumHeight(300); // Some differences between a single file and multiple files KFileItem item = items.first(); KUrl fileUrl = item.url(); filesize_t fileSize = item.size(); QString nameText; QString iconText; QString mimeComment; if (items.count() == 1) { bool isDir = false; // Guess file type if (item.isDir()) { iconText = "folder"; isDir = true; mimeComment = i18n("Remote folder"); } else if (item.isLink()) { // We can't know if the sym-linked file is realy a directory, but most of // the time it is. So if we can't determine the MIME type, set it to directory. KMimeType::Ptr mimeType = KMimeType::findByURL(fileUrl, 0, false, true); if (mimeType->name() == KMimeType::defaultMimeType()) { iconText = "folder"; isDir = true; mimeComment = i18n("Remote folder"); } else { iconText = mimeType->icon(QString::null, false); mimeComment = mimeType->comment(); } } else { KMimeType::Ptr mimeType = KMimeType::findByURL(fileUrl, 0, false, true); iconText = mimeType->icon(QString::null, false); mimeComment = mimeType->comment(); } if (mimeComment.isEmpty()) { mimeComment = i18n("Unknown"); } nameText = item.name(); } else { // Count files and folders selected int countFiles = 0; int countFolders = 0; fileSize = 0; foreach(const KFileItem& item, items) { if (item.isDir()) countFolders++; else countFiles++; fileSize += item.size(); } iconText = "kmultiple"; nameText = KIO::itemsSummaryString(countFiles + countFolders, countFiles, countFolders, 0, false); } Q3VBoxLayout *vbl = new Q3VBoxLayout(frame, 0, KDialog::spacingHint(), "vbl"); Q3GridLayout *grid = new Q3GridLayout(0, 3); grid->setColStretch(0, 0); grid->setColStretch(1, 0); grid->setColStretch(2, 1); grid->addColSpacing(1, KDialog::spacingHint()); vbl->addLayout(grid); // Display file name and icon QLabel *iconLabel = new QLabel(frame); int bsize = 66 + 2 * iconLabel->style().pixelMetric(QStyle::PM_ButtonMargin); iconLabel->setFixedSize(bsize, bsize); iconLabel->setPixmap(DesktopIcon(iconText)); grid->addWidget(iconLabel, 0, 0, Qt::AlignLeft); QLabel *nameLabel = new QLabel(frame); nameLabel->setText(nameText); grid->addWidget(nameLabel, 0, 2); KSeparator *sep = new KSeparator(Qt::Horizontal, frame); grid->addMultiCellWidget(sep, 2, 2, 0, 2); // Display file information QLabel *l; int currentRow = 3; if (items.count() == 1) { l = new QLabel(i18n("Type:"), frame); grid->addWidget(l, currentRow, 0); l = new QLabel(mimeComment, frame); grid->addWidget(l, currentRow++, 2); } l = new QLabel(i18n("Location:"), frame); grid->addWidget(l, currentRow, 0); l = new KSqueezedTextLabel(frame); l->setText(fileUrl.directory()); grid->addWidget(l, currentRow++, 2); l = new QLabel(i18n("Size:"), frame); grid->addWidget(l, currentRow, 0); l = new QLabel(frame); grid->addWidget(l, currentRow++, 2); l->setText(QString::fromLatin1("%1 (%2)").arg(KIO::convertSize(fileSize)) .arg(KGlobal::locale()->formatNumber(fileSize, 0))); sep = new KSeparator(Qt::Horizontal, frame); grid->addMultiCellWidget(sep, currentRow, currentRow, 0, 2); currentRow++; // Display modification time if (items.count() == 1) { l = new QLabel(i18n("Created:"), frame); grid->addWidget(l, currentRow, 0); QDateTime dt; dt.setTime_t(item.time(KIO::UDS_MODIFICATION_TIME)); l = new QLabel(KGlobal::locale()->formatDateTime(dt), frame); grid->addWidget(l, currentRow++, 2); } vbl->addStretch(1); } void PropsPlugin::applyChanges() { } mode_t PermissionsPropsPlugin::fperm[3][4] = { {S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID}, {S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID}, {S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX} }; PermissionsPropsPlugin::PermissionsPropsPlugin(KPropertiesDialog *_props, KFileItemList items, KFTPSession::Session *session) : KPropsDlgPlugin(_props), m_items(items), m_session(session), m_cbRecursive(0) { QFrame *frame = properties->addPage(i18n("&Permissions")); frame->setMinimumWidth(320); frame->setMinimumHeight(300); // Some differences between a single file and multiple files KFileItem *item = items.at(0); KUrl fileUrl = item.url(); bool isDir = false; if (items.count() == 1) { // Guess file type if (item.isDir()) { isDir = true; } else if (item.isLink()) { // We can't know if the sym-linked file is realy a directory, but most of // the time it is. So if we can't determine the MIME type, set it to directory. KMimeType::Ptr mimeType = KMimeType::findByURL(fileUrl, 0, false, true); if (mimeType->name() == KMimeType::defaultMimeType()) isDir = true; } } else { // Check for directories KFileItemListIterator i(items); for (; i.current(); ++i) { if ((*i)->isDir()) { isDir = true; break; } } } Q3BoxLayout *box = new Q3VBoxLayout(frame, 0, KDialog::spacingHint()); Q3GroupBox *gb = new Q3GroupBox(0, Qt::Vertical, i18n("Access Permissions"), frame); gb->layout()->setSpacing(KDialog::spacingHint()); gb->layout()->setMargin(KDialog::marginHint()); box->addWidget(gb); Q3GridLayout *gl = new Q3GridLayout(gb->layout(), 6, 6, 15); QLabel *l = new QLabel(i18n("Class"), gb); gl->addWidget(l, 1, 0); if (isDir) l = new QLabel(i18n("Show\nEntries"), gb); else l = new QLabel(i18n("Read"), gb); gl->addWidget(l, 1, 1); if (isDir) l = new QLabel(i18n("Write\nEntries"), gb); else l = new QLabel(i18n("Write"), gb); gl->addWidget(l, 1, 2); if (isDir) l = new QLabel(i18n("Enter folder", "Enter"), gb); else l = new QLabel(i18n("Exec"), gb); QSize size = l->sizeHint(); size.setWidth(size.width() + 15); l->setFixedSize(size); gl->addWidget(l, 1, 3); l = new QLabel(i18n("Special"), gb); gl->addMultiCellWidget(l, 1, 1, 4, 5); l = new QLabel(i18n("User"), gb); gl->addWidget(l, 2, 0); l = new QLabel(i18n("Group"), gb); gl->addWidget(l, 3, 0); l = new QLabel(i18n("Others"), gb); gl->addWidget(l, 4, 0); l = new QLabel(i18n("Set UID"), gb); gl->addWidget(l, 2, 5); l = new QLabel(i18n("Set GID"), gb); gl->addWidget(l, 3, 5); l = new QLabel(i18n("Sticky"), gb); gl->addWidget(l, 4, 5); mode_t permissions = item.permissions(); // Display checkboxes for (int row = 0; row < 3; ++row) { for (int col = 0; col < 4; ++col) { QCheckBox *cb = new QCheckBox(gb); connect(cb, SIGNAL(clicked()), this, SLOT(setDirty())); m_permsCheck[row][col] = cb; cb->setChecked(permissions & fperm[row][col]); gl->addWidget(cb, row + 2, col + 1); } } gl->setColStretch(6, 10); box->addStretch(10); if (isDir) { m_cbRecursive = new QCheckBox(i18n("Apply changes to all subfolders and their contents"), frame); connect(m_cbRecursive, SIGNAL(clicked()), this, SLOT(changed())); box->addWidget(m_cbRecursive); } } void PermissionsPropsPlugin::applyChanges() { // Generate new permissions =) int newPerms[4] = {0,}; for (int row = 0; row < 3; ++row) { for (int col = 0; col < 4; ++col) { if (!m_permsCheck[row][col]->isChecked()) continue; int x = col < 3 ? col : row; int c = 0; switch (x) { case 0: c = 4; break; case 1: c = 2; break; case 2: c = 1; break; } if (col < 3) { newPerms[row + 1] += c; } else { newPerms[0] += c; } } } // Actually do a chmod int mode = newPerms[0] * 1000 + newPerms[1] * 100 + newPerms[2] * 10 + newPerms[3]; bool recursive = m_cbRecursive && m_cbRecursive->isChecked(); KFileItemListIterator i(m_items); for (; i.current(); ++i) { if ((*i)->isDir()) m_session->getClient()->chmod((*i)->url(), mode, recursive); else m_session->getClient()->chmod((*i)->url(), mode); } } } } #include "propsplugin.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/browser/treeview.cpp0000644000175000017500000001221211276037142023657 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "browser/treeview.h" #include "browser/view.h" #include "browser/dirmodel.h" #include "browser/dirlister.h" #include "browser/dirsortfilterproxymodel.h" #include #include #include #include #include #include #include namespace KFTPWidgets { namespace Browser { TreeView::TreeView(QWidget* parent, View *view) : QTreeView(parent), m_view(view), m_dragging(false) { setAcceptDrops(true); setUniformRowHeights(true); setSelectionMode(QAbstractItemView::SingleSelection); setEditTriggers(QAbstractItemView::NoEditTriggers); setSortingEnabled(true); setFrameStyle(QFrame::NoFrame); setDragDropMode(QAbstractItemView::DragDrop); setDropIndicatorShown(false); setAutoExpandDelay(300); setRootIsDecorated(false); viewport()->setAttribute(Qt::WA_Hover); m_dirModel = new DirModel(view->dirLister(), this); m_dirModel->setDropsAllowed(DirModel::DropOnDirectory); m_dirModel->setTreeViewBehavior(true); m_proxyModel = new DirSortFilterProxyModel(this); m_proxyModel->setSourceModel(m_dirModel); setModel(m_proxyModel); KFileItemDelegate *delegate = new KFileItemDelegate(this); setItemDelegate(delegate); connect(this, SIGNAL(clicked(const QModelIndex&)), view, SLOT(openIndex(const QModelIndex&))); connect(view->dirLister(), SIGNAL(completed()), this, SLOT(selectCurrent())); } void TreeView::selectCurrent() { QModelIndex index = m_dirModel->indexForUrl(m_view->locationNavigator()->url()); if (index.isValid()) { QModelIndex proxyIndex = m_proxyModel->mapFromSource(index); if (!selectionModel()->isSelected(proxyIndex)) { setExpanded(proxyIndex, true); scrollTo(proxyIndex); selectionModel()->clearSelection(); selectionModel()->setCurrentIndex(proxyIndex, QItemSelectionModel::Select); } } } void TreeView::contextMenuEvent(QContextMenuEvent *event) { m_view->openContextMenu(selectedIndexes(), event->globalPos()); } bool TreeView::event(QEvent* event) { if (event->type() == QEvent::Polish) { // Hide all columns except of the 'Name' column hideColumn(DirModel::Size); hideColumn(DirModel::ModifiedTime); hideColumn(DirModel::Permissions); hideColumn(DirModel::Owner); hideColumn(DirModel::Group); header()->hide(); } return QTreeView::event(event); } void TreeView::dragEnterEvent(QDragEnterEvent* event) { if (event->mimeData()->hasUrls()) { event->acceptProposedAction(); } QTreeView::dragEnterEvent(event); m_dragging = true; } void TreeView::dragLeaveEvent(QDragLeaveEvent* event) { QTreeView::dragLeaveEvent(event); // TODO: remove this code when the issue #160611 is solved in Qt 4.4 m_dragging = false; setDirtyRegion(m_dropRect); } void TreeView::dragMoveEvent(QDragMoveEvent* event) { QTreeView::dragMoveEvent(event); // TODO: remove this code when the issue #160611 is solved in Qt 4.4 const QModelIndex index = indexAt(event->pos()); setDirtyRegion(m_dropRect); m_dropRect = visualRect(index); setDirtyRegion(m_dropRect); } void TreeView::dropEvent(QDropEvent* event) { const KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); if (urls.isEmpty()) { QTreeView::dropEvent(event); } else { event->acceptProposedAction(); const QModelIndex index = indexAt(event->pos()); if (index.isValid()) { emit urlsDropped(urls, index); } } m_dragging = false; } } } #include "treeview.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/browser/actions.h0000644000175000017500000001151411276037142023136 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPFILEDIRVIEWACTIONS_H #define KFTPFILEDIRVIEWACTIONS_H #include #include #include #include #include #include namespace KFTPWidgets { namespace Browser { class View; /** * This class contains all per-view actions. * * @author Jernej Kos */ class Actions : public QObject { Q_OBJECT friend class View; friend class DetailsView; public: /** * Class constructor. * * @param parent Parent view widget */ Actions(View *parent); /** * Initialize view's action collection and it's actions. */ void initActions(); public slots: /** * Properly enable/disable the available actions. */ void updateActions(); private: View *m_view; int m_curCharsetOption; int m_defaultCharsetOption; KAction *m_goUpAction; KAction *m_goBackAction; KAction *m_goForwardAction; KAction *m_goHomeAction; KAction *m_reloadAction; KAction *m_abortAction; KToggleAction *m_toggleTreeViewAction; KToggleAction *m_toggleFilterAction; KAction *m_renameAction; KAction *m_deleteAction; KAction *m_propsAction; KAction *m_shredAction; KAction *m_copyAction; KAction *m_pasteAction; KActionMenu *m_filterActions; KAction *m_alwaysSkipAction; KAction *m_topPriorityAction; KAction *m_lowPriorityAction; KAction *m_transferAction; KAction *m_queueTransferAction; KAction *m_createDirAction; KAction *m_fileEditAction; KAction *m_verifyAction; KActionMenu *m_moreActions; KActionMenu *m_rawCommandsMenu; KAction *m_rawCmdAction; KActionMenu *m_changeEncodingAction; KAction *m_exportListingAction; KAction *m_showHiddenFilesAction; KAction *m_openExternalAction; KAction *m_markItemsAction; KAction *m_compareAction; KActionMenu *m_siteChangeAction; KAction *m_quickConnectAction; KActionMenu *m_connectAction; KAction *m_disconnectAction; private: /** * Populates the encodings list. */ void populateEncodings(); /** * A helper function to add the currently selected item(s) to the * priority list with the given priority. * * @param priority The priority to use */ void addPriorityItems(int priority); public slots: void slotGoUp(); void slotGoBack(); void slotGoForward(); void slotGoHome(); void slotReload(); void slotAbort(); void slotToggleTree(); void slotToggleFilter(); void slotRename(); void slotDelete(); void slotProps(); void slotShred(); void slotCopy(); void slotPaste(); void slotAlwaysSkip(); void slotTopPriority(); void slotLowPriority(); void slotTransfer(); void slotQueueTransfer(); void slotCreateDir(); void slotFileEdit(); void slotVerify(); void slotRawCmd(); void slotCharsetChanged(int); void slotCharsetReset(int); void slotExportListing(); void slotShowHiddenFiles(); void slotOpenExternal(); void slotMarkItems(); void slotCompare(); void slotQuickConnect(); void slotDisconnect(); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/browser/view.h0000644000175000017500000001566611276037142022464 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPFILEDIRVIEW_H #define KFTPFILEDIRVIEW_H #include "browser/locationnavigator.h" #include #include #include #include #include #include #include #include namespace KFTPSession { class Session; class Manager; } class KToolBar; class KHistoryComboBox; namespace KFTPEngine { class Thread; class Event; } namespace KFTPWidgets { class PopupMessage; namespace Browser { class DetailsView; class ListView; class TreeView; class Actions; class FilterWidget; class DirLister; class DirModel; class DirSortFilterProxyModel; /** * @author Jernej Kos */ class View : public QWidget { Q_OBJECT friend class Actions; friend class DetailsView; friend class ListView; friend class TreeView; friend class KFTPSession::Manager; friend class KFTPSession::Session; public: /** * Class constructor. */ View(QWidget *parent, KFTPEngine::Thread *client, KFTPSession::Session *session); /** * Class destructor. */ ~View(); /** * Changes the visibility of tree widget. * * @param visible True to display the tree widget, false to hide it */ void setTreeVisible(bool visible); /** * Changes the "show hidden files" setting. * * @param value True to enable showing hidden files, false otherwise */ void setShowHidden(bool value); /** * Set the home URL. * * @param url URL to use as home URL */ void setHomeUrl(const KUrl &url); /** * Go one history hop back. */ void goBack(); /** * Go one history hop forward. */ void goForward(); /** * Go up in the directory structure. */ void goUp(); /** * Go the the predefined home URL. */ void goHome(); /** * Reload the current directory listing. */ void reload(); /** * Renames the provided source file to a new name. */ void rename(const KUrl &source, const QString &name); /** * Returns the details view widget. */ DetailsView *detailsView() const { return m_detailsView; } /** * Returns the tree view widget. */ TreeView *treeView() const { return m_treeView; } /** * Returns the status label widget. */ QLabel *statusLabel() const { return m_statusMsg; } /** * Returns the associated session. */ KFTPSession::Session *session() const { return m_session; } /** * Returns the location navigator. */ LocationNavigator *locationNavigator() const { return m_locationNavigator; } /** * Returns the directory lister. */ DirLister *dirLister() const { return m_dirLister; } /** * Opens the context menu for the specified index at the specified * position. * * @param indexes A list of selected indexes * @param pos Menu position */ void openContextMenu(const QModelIndexList &indexes, const QPoint &pos); /** * Returns the indexes selected by the last operation that requested * a context menu. */ QModelIndexList selectedIndexes() const { return m_currentIndexes; } public slots: /** * Open an URL. Note that if a remote URL is specified the session needs to * be connected to the specified host! * * @param url URL to open */ void openUrl(const KUrl &url); /** * Opens an URL held by the specified index. * * @param index A valid model index */ void openIndex(const QModelIndex &index); /** * Displays an error popup message. */ void showError(const QString &message); /** * Displays a nice popup message. */ void showMessage(const QString &message); protected: /** * Initialize the widget. */ void init(); /** * Populate the toolbar. */ void populateToolbar(); private: KFTPSession::Session *m_session; KFTPEngine::Thread *m_ftpClient; DetailsView *m_detailsView; TreeView *m_treeView; QModelIndexList m_currentIndexes; Actions *m_actions; KToolBar *m_toolBarFirst; KToolBar *m_toolBarSecond; //KToolBar *m_searchToolBar; QLabel *m_statusMsg; QLabel *m_connDurationMsg; QPushButton *m_statusIcon; QSplitter *m_splitter; QPointer m_infoMessage; QTimer *m_connTimer; QTime m_connDuration; KHistoryComboBox *m_historyCombo; //FilterWidget *m_searchFilter; LocationNavigator *m_locationNavigator; DirLister *m_dirLister; DirModel *m_dirModel; DirSortFilterProxyModel *m_proxyModel; bool m_freezeUrlUpdates; bool m_treeVisibilityChanged; public slots: void updateBookmarks(); private slots: void slotHistoryActivated(); void slotHistoryActivated(const QString &text); void slotHistoryChanged(const KUrl &url); void slotUrlChanged(const KUrl &url); void slotListingCompleted(); void slotDisplayCertInfo(); void slotDurationUpdate(); void slotEngineEvent(KFTPEngine::Event *event); void slotConfigUpdate(); signals: /** * Emitted when the URL has been changed. * * @param url The new URL */ void urlChanged(const KUrl &url); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/browser/dirmodel.cpp0000644000175000017500000006136111276037142023635 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * Copyright (C) 2006 David Faure * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "browser/dirmodel.h" #include "browser/dirlister.h" #include "kftpsession.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace KFTPWidgets { namespace Browser { class DirModelNode; class DirModelDirNode; /** * An internal node representation. Used to construct a virtual tree * that is used by the model. */ class DirModelNode { public: /** * Possible node types: * FilesystemEntry - an actual entry in the filesystem * CustomEntry - a "fake" shortcut entry */ enum Type { FilesystemEntry, CustomEntry }; /** * Constructs a new filesystem entry node. * * @param parent Parent directory node * @param item The KFileItem describing the file */ DirModelNode(DirModelDirNode *parent, const KFileItem &item) : m_parent(parent), m_item(item), m_preview(), m_type(FilesystemEntry), m_dirty(false) { } /** * Constructs a new custom entry node. * * @param parent Parent directory node * @param url Shortcut destination URL * @param icon Wanted item icon * @param text Wanted item text */ DirModelNode(DirModelDirNode *parent, const KUrl &url, QIcon icon, const QString &text) : m_parent(parent), m_item(url, "inode/directory", S_IFDIR), m_preview(), m_icon(icon), m_text(text), m_type(CustomEntry), m_dirty(false) { } /** * Returns the underlying KFileItem. */ KFileItem item() const { return m_item; } /** * Returns the node's parent node. */ DirModelDirNode *parent() const { return m_parent; } /** * Returns the row number relative to the parent node. */ int rowNumber() const; QIcon preview() const { return m_preview; } QIcon icon() const { return m_icon; } QString text() const { return m_text; } Type type() const { return m_type; } bool dirty() const { return m_dirty; } void addPreview(const QPixmap &pix) { m_preview.addPixmap(pix); } void setPreview(const QIcon &icn) { m_preview = icn; } /** * Changes this node's file item. * * @param item New file item */ void setFileItem(const KFileItem &item) { m_item = item; } /** * Sets the dirty state of this file node. */ void setDirty(bool value) { m_dirty = value; } private: DirModelDirNode *m_parent; KFileItem m_item; QIcon m_preview; QIcon m_icon; QString m_text; Type m_type; bool m_dirty; }; /** * An internal directory node that can contain other nodes. */ class DirModelDirNode : public DirModelNode { public: /** * Class constructor. * * @see DirModelNode::DirModelNode */ DirModelDirNode(DirModelDirNode *parent, const KFileItem &item) : DirModelNode(parent, item), m_childNodes(), m_childCount(DirModel::ChildCountUnknown), m_populated(false) { } /** * Class constructor. * * @see DirModelNode::DirModelNode */ DirModelDirNode(DirModelDirNode *parent, const KUrl &url, QIcon icon, const QString &text) : DirModelNode(parent, url, icon, text), m_childNodes(), m_childCount(DirModel::ChildCountUnknown), m_populated(false) { } /** * Class destructor. */ ~DirModelDirNode() { qDeleteAll(m_childNodes); } QList m_childNodes; QHash m_childHash; int childCount() const { return m_childNodes.isEmpty() ? m_childCount : m_childNodes.count(); } void setChildCount(int count) { m_childCount = count; } bool isPopulated() const { return m_populated; } void setPopulated(bool populated) { m_populated = populated; } void append(DirModelNode *node); void remove(int row); private: int m_childCount; bool m_populated; }; int DirModelNode::rowNumber() const { if (!m_parent) return 0; return m_parent->m_childNodes.indexOf(const_cast(this)); } void DirModelDirNode::append(DirModelNode *node) { m_childNodes.append(node); if (node->type() == FilesystemEntry) m_childHash.insert(node->item().name(), node); } void DirModelDirNode::remove(int row) { DirModelNode *node = m_childNodes.takeAt(row); if (node->type() == FilesystemEntry) m_childHash.remove(node->item().name()); delete node; } class DirModelPrivate { public: DirModelPrivate(DirModel* model) : q(model), m_dirLister(0), m_rootNode(new DirModelDirNode(0, KFileItem())), m_dropsAllowed(DirModel::NoDrops), m_treeViewBehavior(false) { } ~DirModelPrivate() { delete m_rootNode; } void clear() { delete m_rootNode; m_rootNode = new DirModelDirNode(0, KFileItem()); if (m_treeViewBehavior) { q->beginInsertRows(QModelIndex(), 0, 0); // Create the virtual root node QString text; KUrl url; KIcon icon; if (m_dirLister->session()->isRemote()) { url = m_dirLister->session()->getUrl(); url.setPath("/"); text = url.host(); icon = KIcon("network-wired"); } else { url = KUrl("file:///"); text = i18n("Root Directory"); icon = KIcon("computer"); } m_slashNode = new DirModelDirNode(m_rootNode, url, icon, text); m_rootNode->append(m_slashNode); m_toplevelUrl = url; q->endInsertRows(); } else { m_slashNode = m_rootNode; } } QPair createStubs(const KUrl &_url) const; QPair nodeForUrl(const KUrl& url) const; DirModelNode *nodeForIndex(const QModelIndex& index) const; QModelIndex indexForNode(DirModelNode* node, int rowNumber = -1) const; bool isDir(DirModelNode *node) const { return (node == m_rootNode) || node->item().isDir(); } DirModel *q; DirLister *m_dirLister; DirModelDirNode *m_rootNode; DirModelDirNode *m_slashNode; DirModel::DropsAllowed m_dropsAllowed; bool m_treeViewBehavior; KUrl m_toplevelUrl; }; QPair DirModelPrivate::createStubs(const KUrl &_url) const { KUrl url(_url); url.adjustPath(KUrl::RemoveTrailingSlash); const QString urlStr = url.path(); DirModelDirNode *dirNode = m_slashNode; KUrl nodeUrl = m_toplevelUrl; foreach (QString p, urlStr.split('/', QString::SkipEmptyParts)) { DirModelNode *node = dirNode->m_childHash[p]; if (!node) { // Create a stub entry KUrl tmp = nodeUrl; tmp.cd(p); const int rowCount = dirNode->m_childNodes.count(); q->beginInsertRows(indexForNode(dirNode), rowCount, rowCount); DirModelDirNode *stub = new DirModelDirNode(dirNode, KFileItem(tmp, "inode/directory", S_IFDIR)); dirNode->append(stub); dirNode = stub; q->endInsertRows(); } else { dirNode = static_cast(node); } nodeUrl = dirNode->item().url(); } return qMakePair(0, static_cast(dirNode)); } QPair DirModelPrivate::nodeForUrl(const KUrl& _url) const // O(n*m) { KUrl url(_url); url.adjustPath(KUrl::RemoveTrailingSlash); if (url == m_toplevelUrl) return qMakePair(0, static_cast(m_slashNode)); const QString pathStr = url.path(); DirModelDirNode *dirNode = m_slashNode; KUrl nodeUrl = m_toplevelUrl; if (!pathStr.startsWith(nodeUrl.path())) return qMakePair(0, static_cast(0)); while (nodeUrl != url) { Q_ASSERT(pathStr.startsWith(nodeUrl.path())); bool foundChild = false; QList::ConstIterator it = dirNode->m_childNodes.constBegin(); const QList::ConstIterator end = dirNode->m_childNodes.constEnd(); int row = 0; for (; it != end ; ++it, ++row) { const KUrl u = (*it)->item().url(); if (u == url) return qMakePair(row, *it); if (pathStr.startsWith(u.path() + '/')) { Q_ASSERT(isDir(*it)); dirNode = static_cast(*it); foundChild = true; break; } } if (!foundChild) return qMakePair(0, static_cast(0)); nodeUrl = dirNode->item().url(); } return qMakePair(0, static_cast(0)); } // node -> index. If rowNumber is set (or node is root): O(1). Otherwise: O(n). QModelIndex DirModelPrivate::indexForNode(DirModelNode* node, int rowNumber) const { if (node == m_rootNode) return QModelIndex(); Q_ASSERT(node->parent()); return q->createIndex(rowNumber == -1 ? node->rowNumber() : rowNumber, 0, node); } // index -> node. O(1) DirModelNode* DirModelPrivate::nodeForIndex(const QModelIndex& index) const { return index.isValid() ? static_cast(index.internalPointer()) : m_rootNode; } DirModel::DirModel(DirLister *lister, QObject *parent) : QAbstractItemModel(parent), d(new DirModelPrivate(this)) { setDirLister(lister); } DirModel::~DirModel() { delete d; } void DirModel::setTreeViewBehavior(bool value) { d->m_treeViewBehavior = value; d->clear(); } void DirModel::setDirLister(DirLister *lister) { if (d->m_dirLister) { d->clear(); delete d->m_dirLister; } d->m_dirLister = lister; if (!d->m_dirLister->parent()) d->m_dirLister->setParent(this); // Connect the lister connect(d->m_dirLister, SIGNAL(newItems(KFileItemList)), this, SLOT(slotNewItems(KFileItemList))); connect(d->m_dirLister, SIGNAL(deleteItem(const KFileItem&)), this, SLOT(slotDeleteItem(const KFileItem&))); connect(d->m_dirLister, SIGNAL(refreshItems(const QList >&)), this, SLOT(slotRefreshItems(const QList >&))); connect(d->m_dirLister, SIGNAL(clear()), this, SLOT(slotClear())); connect(d->m_dirLister, SIGNAL(siteChanged(const KUrl&)), this, SLOT(slotUnconditionalClear())); } DirLister *DirModel::dirLister() const { return d->m_dirLister; } void DirModel::slotNewItems(const KFileItemList &items) { if (!items.count()) return; KUrl dir(items.first().url().upUrl()); dir.adjustPath(KUrl::RemoveTrailingSlash); if (!d->m_treeViewBehavior) { if (d->m_dirLister->ignoringChanges()) return; d->m_toplevelUrl = dir; } QPair result = d->nodeForUrl(dir); // O(n*m) if (!result.second && d->m_treeViewBehavior) { // There is no parent node, but stubs have been enabled so we can // create one on the fly. result = d->createStubs(dir); } Q_ASSERT(result.second); Q_ASSERT(d->isDir(result.second)); DirModelDirNode *dirNode = static_cast(result.second); if (d->m_treeViewBehavior) { // Mark all children as clean foreach (DirModelNode *node, dirNode->m_childNodes) node->setDirty(false); } const QModelIndex index = d->indexForNode(dirNode, result.first); // O(1) int newItemsCount = items.count(); // Determine how many rows are actually new KFileItemList::ConstIterator it = items.begin(); const KFileItemList::ConstIterator end = items.end(); for (; it != end; ++it) { if (dirNode->m_childHash.contains((*it).name()) || (d->m_treeViewBehavior && !(*it).isDir())) newItemsCount--; } // Process the items - append or overwrite int newRowCount = dirNode->m_childNodes.count() + newItemsCount; if (newItemsCount > 0) beginInsertRows(index, dirNode->m_childNodes.count(), newRowCount - 1); for (it = items.begin(); it != end ; ++it) { if (d->m_treeViewBehavior && !(*it).isDir()) continue; DirModelNode *node = dirNode->m_childHash.value((*it).name()); if (!node) { node = (*it).isDir() ? new DirModelDirNode(dirNode, *it) : new DirModelNode(dirNode, *it); node->setDirty(true); dirNode->append(node); } else { node->setFileItem(*it); node->setDirty(true); } } if (newItemsCount > 0) endInsertRows(); if (d->m_treeViewBehavior) { // Remove any nodes that are not dirty for (int i = 0; i < dirNode->m_childNodes.size(); i++) { if (!dirNode->m_childNodes.at(i)->dirty()) { dirNode->remove(i); beginRemoveRows(index, i, i); endRemoveRows(); i--; } } } } void DirModel::slotDeleteItem(const KFileItem &item) { const QPair result = d->nodeForUrl(item.url()); // O(n*m) const int rowNumber = result.first; DirModelNode *node = result.second; if (!node) return; DirModelDirNode *dirNode = node->parent(); if (!dirNode) return; dirNode->remove(rowNumber); QModelIndex parentIndex = d->indexForNode(dirNode); // O(n) beginRemoveRows(parentIndex, rowNumber, rowNumber); endRemoveRows(); } void DirModel::slotRefreshItems(const QList > &items) { QModelIndex topLeft, bottomRight; for (QList >::ConstIterator fit = items.begin(), fend = items.end(); fit != fend; ++fit) { const QModelIndex index = indexForUrl((*fit).first.url()); // O(n*m); maybe we could look up to the parent only once d->nodeForIndex(index)->setFileItem((*fit).second); if (!topLeft.isValid() || index.row() < topLeft.row()) topLeft = index; if (!bottomRight.isValid() || index.row() > bottomRight.row()) bottomRight = index; } bottomRight = bottomRight.sibling(bottomRight.row(), ColumnCount-1); emit dataChanged(topLeft, bottomRight); } void DirModel::slotClear() { if (!d->m_treeViewBehavior) slotUnconditionalClear(); } void DirModel::slotUnconditionalClear() { const int numRows = d->m_rootNode->m_childNodes.count(); beginRemoveRows(QModelIndex(), 0, numRows); endRemoveRows(); d->clear(); } void DirModel::itemChanged(const QModelIndex& index) { emit dataChanged(index, index); } int DirModel::columnCount(const QModelIndex &) const { return ColumnCount; } QVariant DirModel::data(const QModelIndex &index, int role) const { if (index.isValid()) { DirModelNode *node = static_cast(index.internalPointer()); const KFileItem item = node->item(); if (node->type() == DirModelNode::FilesystemEntry) { switch (role) { case Qt::DisplayRole: { switch (index.column()) { case Name: return item.text(); case Size: // FIXME //return KIO::convertSize(item->size()); // Default to "file size in bytes" like in kde3's filedialog return KGlobal::locale()->formatNumber(item.size(), 0); case ModifiedTime: return item.timeString(KFileItem::ModificationTime); case Permissions: return item.permissionsString(); case Owner: return item.user(); case Group: return item.group(); } break; } case Qt::DecorationRole: { if (index.column() == Name) { // FIXME is this really needed ? probably not if (!node->preview().isNull()) return node->preview(); QStringList overlays = item.overlays(); return KIcon(item.iconName(), 0, overlays); } break; } case FileItemRole: return QVariant::fromValue(item); case ChildCountRole: { if (!item.isDir()) { return ChildCountUnknown; } else { DirModelDirNode *dirNode = static_cast(node); int count = dirNode->childCount(); if (count == ChildCountUnknown && item.isReadable()) { const QString path = item.localPath(); // Only for local directories if (!path.isEmpty()) { DIR *dir = ::opendir(QFile::encodeName(path)); if (dir) { count = 0; struct dirent *dirEntry = 0; while ((dirEntry = ::readdir(dir))) { if (dirEntry->d_name[0] == '.') { // Skip '.' if (dirEntry->d_name[1] == '\0') continue; // Skip '..' if (dirEntry->d_name[1] == '.' && dirEntry->d_name[2] == '\0') continue; } count++; } ::closedir(dir); } dirNode->setChildCount(count); } } return count; } } } } else if (node->type() == DirModelNode::CustomEntry) { switch (role) { case Qt::DisplayRole: return node->text(); case Qt::DecorationRole: return node->icon(); case FileItemRole: return QVariant::fromValue(item); } } } return QVariant(); } void DirModel::sort(int column, Qt::SortOrder order) { // FIXME Not implemented - we should probably use QSortFilterProxyModel instead. return QAbstractItemModel::sort(column, order); } bool DirModel::setData(const QModelIndex &index, const QVariant &value, int role) { switch (role) { case Qt::DisplayRole: // TODO handle renaming here? break; case Qt::DecorationRole: { if (index.column() == Name) { DirModelNode *node = static_cast(index.internalPointer()); if (value.type() == QVariant::Icon) { const QIcon icon(qvariant_cast(value)); node->setPreview(icon); } else if (value.type() == QVariant::Pixmap) { node->addPreview(qvariant_cast(value)); } emit dataChanged(index, index); return true; } break; } default: break; } return false; } int DirModel::rowCount(const QModelIndex &parent) const { DirModelDirNode* parentNode = static_cast(d->nodeForIndex(parent)); return parentNode->m_childNodes.count(); } QModelIndex DirModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); DirModelNode* childNode = static_cast(index.internalPointer()); DirModelNode* parentNode = childNode->parent(); return d->indexForNode(parentNode); // O(n) } QStringList DirModel::mimeTypes() const { return QStringList() << QLatin1String("text/uri-list") << QLatin1String( "application/x-kde-cutselection" ) // TODO << QLatin1String( "text/plain" ) << QLatin1String( "application/x-kde-urilist" ); } QMimeData *DirModel::mimeData(const QModelIndexList &indexes) const { KUrl::List urls; foreach (const QModelIndex &index, indexes) { urls << d->nodeForIndex(index)->item().url(); } QMimeData *data = new QMimeData(); urls.populateMimeData(data); return data; } KFileItem DirModel::itemForIndex(const QModelIndex &index) const { if (!index.isValid()) { return *d->m_dirLister->rootItem(); } else { KFileItem item = static_cast(index.internalPointer())->item(); return item; } } QModelIndex DirModel::indexForItem(const KFileItem *item) const { return indexForUrl(item->url()); // O(n*m) } QModelIndex DirModel::indexForItem(const KFileItem &item) const { return indexForUrl(item.url()); // O(n*m) } QModelIndex DirModel::indexForUrl(const KUrl &url) const { const QPair result = d->nodeForUrl(url); // O(n*m) (m is the depth from the root) if (!result.second) return QModelIndex(); return d->indexForNode(result.second, result.first); // O(1) } QModelIndex DirModel::index(int row, int column, const QModelIndex &parent) const { DirModelNode *parentNode = d->nodeForIndex(parent); // O(1) DirModelNode *childNode = static_cast(parentNode)->m_childNodes.value(row); // O(1) if (childNode) return createIndex(row, column, childNode); else return QModelIndex(); } QVariant DirModel::headerData(int section, Qt::Orientation orientation, int role) const { Q_UNUSED(orientation); switch (role) { case Qt::DisplayRole: { switch (section) { case Name: return i18nc("@title:column", "Name"); case Size: return i18nc("@title:column", "Size"); case ModifiedTime: return i18nc("@title:column", "Date"); case Permissions: return i18nc("@title:column", "Permissions"); case Owner: return i18nc("@title:column", "Owner"); case Group: return i18nc("@title:column", "Group"); } } } return QVariant(); } bool DirModel::hasChildren(const QModelIndex & parent) const { if (!parent.isValid()) return true; const KFileItem parentItem = static_cast(parent.internalPointer())->item(); return parentItem.isDir(); } Qt::ItemFlags DirModel::flags(const QModelIndex &index) const { Qt::ItemFlags f = Qt::ItemIsEnabled; if (index.column() == Name) { f |= Qt::ItemFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled); } // Allow dropping onto this item? if (d->m_dropsAllowed != NoDrops) { if (!index.isValid()) { if (d->m_dropsAllowed & DropOnDirectory) { f |= Qt::ItemIsDropEnabled; } } else { KFileItem item = itemForIndex(index); if (item.isNull()) { return f; } else if (item.isDir()) { if (d->m_dropsAllowed & DropOnDirectory) { f |= Qt::ItemIsDropEnabled; } } else { if (d->m_dropsAllowed & DropOnAnyFile) { f |= Qt::ItemIsDropEnabled; } } } } return f; } bool DirModel::canFetchMore(const QModelIndex &parent) const { if (!parent.isValid()) return false; DirModelNode *node = static_cast(parent.internalPointer()); const KFileItem item = node->item(); return item.isDir() && !static_cast(node)->isPopulated() && static_cast(node)->m_childNodes.isEmpty(); } void DirModel::fetchMore(const QModelIndex &parent) { if (!parent.isValid()) return; DirModelNode *parentNode = static_cast(parent.internalPointer()); const KFileItem parentItem = parentNode->item(); DirModelDirNode *dirNode = static_cast(parentNode); if (dirNode->isPopulated()) return; dirNode->setPopulated(true); const KUrl url = parentItem.url(); d->m_dirLister->setIgnoreChanges(true); d->m_dirLister->openUrl(url, KDirLister::Keep); } bool DirModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { Q_UNUSED(data); Q_UNUSED(action); Q_UNUSED(row); Q_UNUSED(column); Q_UNUSED(parent); return false; } void DirModel::setDropsAllowed(DropsAllowed dropsAllowed) { d->m_dropsAllowed = dropsAllowed; } } } #include "dirmodel.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/browser/CMakeLists.txt0000644000175000017500000000076611276037142024074 0ustar michaelmichaelINCLUDE_DIRECTORIES( .. ../.. ../../misc ${CMAKE_CURRENT_BINARY_DIR}/../.. ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(browser_SRCS dirlister.cpp dirmodel.cpp dirsortfilterproxymodel.cpp locationnavigator.cpp detailsview.cpp view.cpp actions.cpp treeview.cpp #propsplugin.cpp #filterwidget.cpp ) kde4_add_library(browser STATIC ${browser_SRCS}) add_dependencies(browser widgets bookmarkwidgets) kftpgrabber-0.8.99~svn1214766/src/widgets/configdialog.h0000644000175000017500000000415511276037142022443 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCONFIGDIALOG_H #define KFTPCONFIGDIALOG_H #include namespace KFTPWidgets { class ConfigFilter; /** * KFTPgrabber global configuration dialog. * * @author Jernej Kos */ class ConfigDialog : public KConfigDialog { Q_OBJECT public: ConfigDialog(QWidget *parent, const QString &name = QString::null); void prepareDialog(); private: ConfigFilter *m_configFilter; private slots: void slotSettingsChanged(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/searchdialog.cpp0000644000175000017500000001234611276037142022777 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "widgets/searchdialog.h" #include "kftpsearchlayout.h" #include "kftpserverlineedit.h" #include "kftpbookmarks.h" #include "kftpqueue.h" #include #include #include #include //Added by qt3to4: #include #include #include #include namespace KFTPWidgets { SearchDialog::SearchDialog(QWidget *parent, const char *name) : KDialogBase(parent, name, true, i18n("Search & Replace"), Ok|Cancel, Ok) { // Create the main widget m_layout = new KFTPSearchLayout(this); // Set the dialog options setMainWidget(m_layout); setInitialSize(QSize(500,400)); connect(m_layout->searchServer, SIGNAL(clicked()), this, SLOT(slotSearchServerClicked())); connect(m_layout->searchServerName, SIGNAL(siteChanged(KFTPBookmarks::Site*)), this, SLOT(slotSiteChanged(KFTPBookmarks::Site*))); } QString SearchDialog::replaceCap(QStringList cap, const QString &text) { QString tmp = text; QStringList::Iterator end( cap.end() ); for(QStringList::Iterator i( cap.begin() ); i != end; ++i) { tmp.replace("$" + QString::number(cap.findIndex(*i)), *i); } return tmp; } void SearchDialog::replace(KFTPQueue::Transfer *i) { QRegExp s, d; s.setPattern(m_layout->searchSrcPath->text()); d.setPattern(m_layout->searchDstPath->text()); KUrl tmp = i->getSourceUrl().isLocalFile() ? i->getDestUrl() : i->getSourceUrl(); tmp.setPath("/"); KUrl match; match.setProtocol("ftp"); match.setHost(m_layout->searchServerHost->text()); match.setPort(m_layout->searchServerPort->value()); match.setUser(m_layout->searchServerUser->text()); match.setPass(m_layout->searchServerPass->password()); match.setPath("/"); if (s.search(i->getSourceUrl().path()) != -1 && d.search(i->getDestUrl().path()) != -1 && (!m_layout->searchServer->isChecked() || tmp.url() == match.url())) { // Do the replacing KUrl newSource = i->getSourceUrl(); KUrl newDest = i->getDestUrl(); newSource.setPath(replaceCap(s.capturedTexts(), m_layout->replaceSrcPath->text())); newDest.setPath(replaceCap(d.capturedTexts(), m_layout->replaceDstPath->text())); i->setSourceUrl(newSource); i->setDestUrl(newDest); i->emitUpdate(); } } void SearchDialog::searchAndReplace(KFTPQueue::QueueObject *parent) { if (parent->isLocked()) return; Q3PtrList list = parent->getChildrenList(); KFTPQueue::QueueObject *i; for (i = list.first(); i; i = list.next()) { if (i->hasChildren() && !i->isLocked()) { searchAndReplace(i); } if (i->isTransfer() && !i->isLocked()) replace(static_cast(i)); } } void SearchDialog::searchAndReplace() { searchAndReplace(KFTPQueue::Manager::self()->topLevelObject()); } void SearchDialog::slotOk() { searchAndReplace(); accept(); } void SearchDialog::slotSearchServerClicked() { m_layout->groupBox1->setEnabled(m_layout->searchServer->isChecked()); } void SearchDialog::slotSiteChanged(KFTPBookmarks::Site *site) { if (site) { m_layout->searchServerHost->setText(site->getProperty("host")); m_layout->searchServerPort->setValue(site->getIntProperty("port")); m_layout->searchServerUser->setText(site->getProperty("username")); m_layout->searchServerPass->erase(); m_layout->searchServerPass->insert(site->getProperty("password")); } else { m_layout->searchServerHost->clear(); m_layout->searchServerPort->setValue(21); m_layout->searchServerUser->clear(); m_layout->searchServerPass->erase(); } } } #include "searchdialog.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/searchdialog.h0000644000175000017500000000506111276037142022440 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETSSEARCHDIALOG_H #define KFTPWIDGETSSEARCHDIALOG_H #include #include namespace KFTPQueue { class Transfer; class QueueObject; } namespace KFTPBookmarks { class Site; } class KFTPSearchLayout; namespace KFTPWidgets { /** * This dialog provides search & replace functionality for queued transfers. * * @author Jernej Kos */ class SearchDialog : public KDialogBase { Q_OBJECT public: /** * Class constructor. */ SearchDialog(QWidget *parent = 0, const char *name = 0); private: KFTPSearchLayout *m_layout; void replace(KFTPQueue::Transfer *i); QString replaceCap(QStringList cap, const QString &text); void searchAndReplace(KFTPQueue::QueueObject *parent); void searchAndReplace(); private slots: virtual void slotOk(); void slotSearchServerClicked(); void slotSiteChanged(KFTPBookmarks::Site *site); }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/sslerrorsdialog.cpp0000644000175000017500000000626111276037142023567 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "sslerrorsdialog.h" #include "misc/config.h" #include #include #include Q_DECLARE_METATYPE(QSslError) using namespace KFTPCore; namespace KFTPWidgets { SslErrorsDialog::SslErrorsDialog(QWidget *parent) : KDialog(parent) { setCaption(i18n("SSL Negotiation Failed")); setButtons(Cancel | Ok | User1); setButtonText(Ok, i18n("Continue")); setButtonText(User1, i18n("View Certificate...")); QWidget *widget = new QWidget(this); ui.setupUi(widget); setMainWidget(widget); ui.icon->setPixmap(DesktopIcon("decrypted")); } void SslErrorsDialog::setErrors(const QVariantList &errors) { foreach (QVariant error, errors) { QSslError e = error.value(); ui.errors->addItem(new QListWidgetItem(KIcon("no"), e.errorString())); m_certificate = e.certificate(); switch (e.error()) { case QSslError::CertificateExpired: { ui.trustCertificate->setEnabled(false); break; } default: break; } } } void SslErrorsDialog::slotButtonClicked(int button) { switch (button) { case Ok: { if (ui.trustCertificate->isChecked()) { // Save site certificate to trusted certificates CertificateStore *store = Config::self()->certificateStore(); store->addCertificate(m_certificate); store->save(); } accept(); break; } case Cancel: reject(); break; case User1: { // Show certificate information dialog break; } } } } #include "sslerrorsdialog.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/trafficgraph.cpp0000644000175000017500000007414611276037142023020 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 1999-2002 Chris Schlaeger * Copyright (C) 2006-2007 John Tapsell * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include #include #include #include #include #include #include #include #include #include #include #include "trafficgraph.h" namespace KFTPWidgets { QHash TrafficGraph::sSvgRenderer ; TrafficGraph::TrafficGraph( QWidget *parent) : QWidget( parent) { mPrecision = 0; mBezierCurveOffset = 0; mSamples = 0; mMinValue = mMaxValue = 0.0; mNiceMinValue = mNiceMaxValue = 0.0; mNiceRange = 0; mUseAutoRange = true; mScaleDownBy = 1; mShowThinFrame = true; // Anything smaller than this does not make sense. setMinimumSize( 16, 16 ); QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); sizePolicy.setHeightForWidth(false); setSizePolicy( sizePolicy ); mShowVerticalLines = true; mVerticalLinesColor = QColor("black"); mVerticalLinesDistance = 30; mVerticalLinesScroll = true; mVerticalLinesOffset = 0; mHorizontalScale = 1; mShowHorizontalLines = true; mHorizontalLinesColor = QColor("black"); mHorizontalLinesCount = 5; mShowLabels = true; mShowTopBar = false; mStackBeams = true; mFillBeams = true; mBackgroundColor = QColor(0,0,0); } TrafficGraph::~TrafficGraph() { } QString TrafficGraph::translatedUnit() const { return mUnit; } void TrafficGraph::setTranslatedUnit(const QString &unit) { mUnit= unit; } bool TrafficGraph::addBeam( const QColor &color ) { QLinkedList< QList >::Iterator it; //When we add a new beam, go back and set the data for this beam to 0 for all the other times. This is because it makes it easier for //moveSensors for(it = mBeamData.begin(); it != mBeamData.end(); ++it) { (*it).append(0); } mBeamColors.append(color); mBeamColorsDark.append(color.dark(150)); return true; } void TrafficGraph::addSample( const QList& sampleBuf ) { if(mSamples < 4) { //It might be possible, under some race conditions, for addSample to be called before mSamples is set //This is just to be safe kDebug(1215) << "Error - mSamples is only " << mSamples; updateDataBuffers(); kDebug(1215) << "mSamples is now " << mSamples; if(mSamples < 4) return; } mBeamData.prepend(sampleBuf); Q_ASSERT(sampleBuf.count() == mBeamColors.count()); if((unsigned int)mBeamData.size() > mSamples) { mBeamData.removeLast(); // we have too many. Remove the last item if((unsigned int)mBeamData.size() > mSamples) mBeamData.removeLast(); // If we still have too many, then we have resized the widget. Remove one more. That way we will slowly resize to the new size } if(mBezierCurveOffset >= 2) mBezierCurveOffset = 0; else mBezierCurveOffset++; Q_ASSERT((uint)mBeamData.size() >= mBezierCurveOffset); /* If the vertical lines are scrolling, increment the offset * so they move with the data. */ if ( mVerticalLinesScroll ) { mVerticalLinesOffset = ( mVerticalLinesOffset + mHorizontalScale) % mVerticalLinesDistance; } update(); } void TrafficGraph::reorderBeams( const QList& newOrder ) { if(newOrder.count() != mBeamColors.count()) { kDebug(1215) << "neworder has " << newOrder.count() << " and beam colors is " << mBeamColors.count(); return; } QLinkedList< QList >::Iterator it; for(it = mBeamData.begin(); it != mBeamData.end(); ++it) { if(newOrder.count() != (*it).count()) { kDebug(1215) << "Serious problem in move sample. beamdata[i] has " << (*it).count() << " and neworder has " << newOrder.count(); } else { QList newBeam; for(int i = 0; i < newOrder.count(); i++) { int newIndex = newOrder[i]; newBeam.append((*it).at(newIndex)); } (*it) = newBeam; } } QList< QColor> newBeamColors; QList< QColor> newBeamColorsDark; for(int i = 0; i < newOrder.count(); i++) { int newIndex = newOrder[i]; newBeamColors.append(mBeamColors.at(newIndex)); newBeamColorsDark.append(mBeamColorsDark.at(newIndex)); } mBeamColors = newBeamColors; mBeamColorsDark = newBeamColorsDark; } void TrafficGraph::changeRange( int beam, double min, double max ) { // Only the first beam affects range calculation. if ( beam > 1 ) return; mMinValue = min; mMaxValue = max; calculateNiceRange(); } QList &TrafficGraph::beamColors() { return mBeamColors; } void TrafficGraph::removeBeam( uint pos ) { if(pos >= (uint)mBeamColors.size()) return; mBeamColors.removeAt( pos ); QLinkedList< QList >::Iterator i; for(i = mBeamData.begin(); i != mBeamData.end(); ++i) { if( (uint)(*i).size() >= pos) (*i).removeAt(pos); } } void TrafficGraph::setScaleDownBy( double value ) { if(mScaleDownBy == value) return; mScaleDownBy = value; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache calculateNiceRange(); } double TrafficGraph::scaleDownBy() const { return mScaleDownBy; } void TrafficGraph::setTitle( const QString &title ) { if(mTitle == title) return; mTitle = title; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } QString TrafficGraph::title() const { return mTitle; } void TrafficGraph::setUseAutoRange( bool value ) { mUseAutoRange = value; calculateNiceRange(); //this change will be detected in paint and the image cache regenerated } bool TrafficGraph::useAutoRange() const { return mUseAutoRange; } void TrafficGraph::setMinValue( double min ) { mMinValue = min; calculateNiceRange(); //this change will be detected in paint and the image cache regenerated } double TrafficGraph::minValue() const { return mMinValue; } void TrafficGraph::setMaxValue( double max ) { mMaxValue = max; calculateNiceRange(); //this change will be detected in paint and the image cache regenerated } double TrafficGraph::maxValue() const { return mMaxValue; } void TrafficGraph::setHorizontalScale( uint scale ) { if (scale == mHorizontalScale) return; mHorizontalScale = scale; updateDataBuffers(); mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } int TrafficGraph::horizontalScale() const { return mHorizontalScale; } void TrafficGraph::setShowVerticalLines( bool value ) { if(mShowVerticalLines == value) return; mShowVerticalLines = value; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } bool TrafficGraph::showVerticalLines() const { return mShowVerticalLines; } void TrafficGraph::setVerticalLinesColor( const QColor &color ) { if(mVerticalLinesColor == color) return; mVerticalLinesColor = color; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } QColor TrafficGraph::verticalLinesColor() const { return mVerticalLinesColor; } void TrafficGraph::setVerticalLinesDistance( uint distance ) { if(distance == mVerticalLinesDistance) return; mVerticalLinesDistance = distance; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } int TrafficGraph::verticalLinesDistance() const { return mVerticalLinesDistance; } void TrafficGraph::setVerticalLinesScroll( bool value ) { if(value == mVerticalLinesScroll) return; mVerticalLinesScroll = value; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } bool TrafficGraph::verticalLinesScroll() const { return mVerticalLinesScroll; } void TrafficGraph::setShowHorizontalLines( bool value ) { if(value == mShowHorizontalLines) return; mShowHorizontalLines = value; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } bool TrafficGraph::showHorizontalLines() const { return mShowHorizontalLines; } void TrafficGraph::setFontColor( const QColor &color ) { mFontColor = color; } QColor TrafficGraph::fontColor() const { return mFontColor; } void TrafficGraph::setHorizontalLinesColor( const QColor &color ) { if(color == mHorizontalLinesColor) return; mHorizontalLinesColor = color; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } QColor TrafficGraph::horizontalLinesColor() const { return mHorizontalLinesColor; } void TrafficGraph::setHorizontalLinesCount( uint count ) { if(count == mHorizontalLinesCount) return; mHorizontalLinesCount = count; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache calculateNiceRange(); } int TrafficGraph::horizontalLinesCount() const { return mHorizontalLinesCount; } void TrafficGraph::setShowLabels( bool value ) { if(value == mShowLabels) return; mShowLabels = value; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } bool TrafficGraph::showLabels() const { return mShowLabels; } void TrafficGraph::setShowTopBar( bool value ) { if(mShowTopBar == value) return; mShowTopBar = value; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } bool TrafficGraph::showTopBar() const { return mShowTopBar; } void TrafficGraph::setFont( const QFont &font ) { mFont = font; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } QFont TrafficGraph::font() const { return mFont; } QString TrafficGraph::svgBackground() { return mSvgFilename; } void TrafficGraph::setSvgBackground( const QString &filename ) { if(mSvgFilename == filename) return; mSvgFilename = filename; //NOTE: We don't free the old svg renderer. This means that it will leak if we set it to use one svg, then reset it to use another svg. //The svg rendererer object will be created on demand in drawBackground } void TrafficGraph::setBackgroundColor( const QColor &color ) { if(color == mBackgroundColor) return; mBackgroundColor = color; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } QColor TrafficGraph::backgroundColor() const { return mBackgroundColor; } void TrafficGraph::setThinFrame( bool set) { if(mShowThinFrame == set) return; mShowThinFrame = set; mBackgroundImage = QImage(); //we changed a paint setting, so reset the cache } void TrafficGraph::resizeEvent( QResizeEvent* ) { Q_ASSERT( width() > 2 ); // mBackgroundImage = mBackgroundImage.scaled(width(), height()); //set to null. If it's invalid, it will be rerendered. updateDataBuffers(); } void TrafficGraph::updateDataBuffers() { /* This is called when the widget has resized * * Determine new number of samples first. * +0.5 to ensure rounding up * +4 for extra data points so there is * 1) no wasted space and * 2) no loss of precision when drawing the first data point. */ mSamples = static_cast( ( ( width() - 2 ) / mHorizontalScale ) + 4.5 ); } QImage TrafficGraph::getSnapshotImage(uint w, uint height) { uint horizontalStep = (uint)((1.0*w/width())+0.5); //get the closest integer horizontal step uint newWidth = horizontalStep * width(); QImage image = QImage(newWidth, height, QImage::Format_RGB32); QPainter p(&image); drawWidget(&p, newWidth, height, newWidth); return image; } void TrafficGraph::paintEvent( QPaintEvent* ) { uint w = width(); uint h = height(); /* Do not do repaints when the widget is not yet setup properly. */ if ( w <= 2 ) return; QPainter p(this); drawWidget(&p, w, h, mHorizontalScale); } void TrafficGraph::drawWidget(QPainter *p, uint w, uint height, int horizontalScale) { uint h = height; //h will become the height of just the bit we draw the beams in p->setFont( mFont ); uint fontheight = p->fontMetrics().height(); if(mMinValue < mNiceMinValue || mMaxValue > mNiceMaxValue || mMaxValue < (mNiceRange*0.75 + mNiceMinValue) || mNiceRange == 0) calculateNiceRange(); QPen pen; pen.setWidth(1); pen.setCapStyle(Qt::RoundCap); p->setPen(pen); uint top = p->pen().width() / 2; //The y position of the top of the graph. Basically this is one more than the height of the top bar h-= top; //check if there's enough room to actually show a top bar. Must be enough room for a bar at the top, plus horizontal lines each of a size with room for a scale bool showTopBar = mShowTopBar && h > (fontheight/*top bar size*/ +5/*smallest reasonable size for a graph*/ ); if(showTopBar) { top += fontheight; //The top bar has the same height as fontheight. Thus the top of the graph is at fontheight h -= fontheight; } if(mBackgroundImage.isNull() || (uint)mBackgroundImage.height() != height || (uint)mBackgroundImage.width() != w) { //recreate on resize etc mBackgroundImage = QImage(w, height, QImage::Format_RGB32); QPainter pCache(&mBackgroundImage); pCache.setRenderHint(QPainter::Antialiasing, false); pCache.setFont( mFont ); drawBackground(&pCache, w, height); if(mShowThinFrame) { drawThinFrame(&pCache, w, height); //We have a 'frame' in the bottom and right - so subtract them from the view h--; w--; pCache.setClipRect( 0, 0, w, height-1 ); } if(showTopBar) { int seperatorX = w / 2; drawTopBarFrame(&pCache, w, seperatorX, top); } /* Draw scope-like grid vertical lines if it doesn't move. If it does move, draw it in the dynamic part of the code*/ if(!mVerticalLinesScroll && mShowVerticalLines && w > 60) drawVerticalLines(&pCache, top, w, h); if ( mShowHorizontalLines ) drawHorizontalLines(&pCache, top, w, h); } else { if(mShowThinFrame) { //We have a 'frame' in the bottom and right - so subtract them from the view h--; w--; } } p->drawImage(0,0, mBackgroundImage); p->setRenderHint(QPainter::Antialiasing, true); if ( showTopBar ) { int seperatorX = w / 2; int topBarWidth = w - seperatorX -2; drawTopBarContents(p, seperatorX, topBarWidth, top -1); } p->setClipRect( 0, top, w, h); /* Draw scope-like grid vertical lines */ if ( mVerticalLinesScroll && mShowVerticalLines && w > 60 ) drawVerticalLines(p, top, w, h); drawBeams(p, top, w, h, horizontalScale); if( mShowLabels && w > 60 && h > ( fontheight + 1 ) ) //if there's room to draw the labels, then draw them! drawAxisText(p, top, h); } void TrafficGraph::drawBackground(QPainter *p, int w, int h) { p->fillRect(0,0,w, h, mBackgroundColor); if(mSvgFilename.isEmpty()) return; //nothing to draw, return QSvgRenderer *svgRenderer; if(!sSvgRenderer.contains(mSvgFilename)) { KStandardDirs* kstd = KGlobal::dirs(); QString file = kstd->findResource( "data", "ksysguard/" + mSvgFilename); svgRenderer = new QSvgRenderer(file, this); sSvgRenderer.insert(mSvgFilename, svgRenderer); } else svgRenderer = sSvgRenderer[mSvgFilename]; svgRenderer->render(p); } void TrafficGraph::drawThinFrame(QPainter *p, int w, int h) { /* Draw white line along the bottom and the right side of the * widget to create a 3D like look. */ p->setPen( palette().color( QPalette::Light ) ); p->drawLine( 0, h - 1, w - 1, h - 1 ); p->drawLine( w - 1, 0, w - 1, h - 1 ); } void TrafficGraph::calculateNiceRange() { mNiceRange = mMaxValue - mMinValue; /* If the range is too small we will force it to 1.0 since it * looks a lot nicer. */ if ( mNiceRange < 0.000001 ) mNiceRange = 1.0; mNiceMinValue = mMinValue; // if ( mUseAutoRange ) { if ( mMinValue != 0.0 ) { double dim = pow( 10, floor( log10( fabs( mMinValue ) ) ) ) / 2; if ( mMinValue < 0.0 ) mNiceMinValue = dim * floor( mMinValue / dim ); else mNiceMinValue = dim * ceil( mMinValue / dim ); mNiceRange = mMaxValue - mNiceMinValue; if ( mNiceRange < 0.000001 ) mNiceRange = 1.0; } // Massage the range so that the grid shows some nice values. double step = mNiceRange / (mScaleDownBy*(mHorizontalLinesCount+1)); int logdim = (int)floor( log10( step ) ); double dim = pow( 10, logdim ) / 2; int a = (int)ceil( step / dim ); if(logdim >= 0) mPrecision = 0; else if( a % 2 == 0){ mPrecision =-logdim; } else { mPrecision = 1-logdim; } mNiceRange = mScaleDownBy*dim * a * (mHorizontalLinesCount+1); // } mNiceMaxValue = mNiceMinValue + mNiceRange; } void TrafficGraph::drawTopBarFrame(QPainter *p, int fullWidth, int seperatorX, int height) { /* Draw horizontal bar with current sensor values at top of display. */ //remember that it has a height of 'height'. Thus the lowest pixel it can draw on is height-1 since we count from 0 p->setPen( Qt::NoPen); // p->fillRect( 0, 0, fullWidth, height-1, QBrush(QColor(255,255,255,60))); p->setPen( mFontColor ); p->drawText(0, 1, seperatorX, height, Qt::AlignCenter, mTitle ); p->setPen( mHorizontalLinesColor ); p->drawLine( seperatorX - 1, 1, seperatorX - 1, height-1 ); } void TrafficGraph::drawTopBarContents(QPainter *p, int x, int width, int height) { //The height is the height of the contents, so this will be one pixel less than the height of the topbar double bias = -mNiceMinValue; double scaleFac = width / mNiceRange; QList::Iterator col; col = mBeamColors.end(); /** * The top bar shows the current values of all the beam data. * This iterates through each different beam and plots the newest data for each */ if ( !mBeamData.isEmpty() ) { QList newestData = mBeamData.first(); for(int i = newestData.count()-1; i >= 0; --i) { double newest_datapoint = newestData.at(i); int start = x + (int)( bias * scaleFac ); int end = x + (int)( ( bias += newest_datapoint ) * scaleFac ); int start2 = qMin(start,end); end = qMax(start,end); start = start2; /* If the rect is wider than 2 pixels we draw only the last * pixels with the bright color. The rest is painted with * a 50% darker color. */ p->setPen(Qt::NoPen); QLinearGradient linearGrad( QPointF(start,1), QPointF(end, 1)); linearGrad.setColorAt(0, mBeamColorsDark[i]); linearGrad.setColorAt(1, mBeamColors[i]); p->fillRect( start, 1, end - start, height-1, QBrush(linearGrad)); } } } void TrafficGraph::drawVerticalLines(QPainter *p, int top, int w, int h) { p->setPen( mVerticalLinesColor ); for ( int x = mVerticalLinesOffset; x < ( w - 2 ); x += mVerticalLinesDistance ) p->drawLine( w - x, top, w - x, h + top -1 ); } void TrafficGraph::drawBeams(QPainter *p, int top, int w, int h, int horizontalScale) { Q_ASSERT(mNiceRange != 0); if(mNiceRange == 0) mNiceRange = 1; double scaleFac = (h-1) / mNiceRange; int xPos = 0; QLinkedList< QList >::Iterator it = mBeamData.begin(); p->setPen(Qt::NoPen); /* In autoRange mode we determine the range and plot the values in * one go. This is more efficiently than running through the * buffers twice but we do react on recently discarded samples as * well as new samples one plot too late. So the range is not * correct if the recently discarded samples are larger or smaller * than the current extreme values. But we can probably live with * this. * * These values aren't used directly anywhere. Instead we call * calculateNiceRange() which massages these values into a nicer * values. Rounding etc. This means it's safe to change these values * without affecting any other drawings * */ if ( mUseAutoRange ) mMinValue = mMaxValue = 0.0; /* mBezierCurveOffset is how many points we have at the start. * All the bezier curves are in groups of 3, with the first of the next group being the last point * of the previous group-> * * Example, when mBezierCurveOffset == 0, and we have data, then just plot a normal bezier curve * (we will have at least 3 points in this case) * When mBezierCurveOffset == 1, then we want a bezier curve that uses the first data point and * the second data point. Then the next group starts from the second data point. * When mBezierCurveOffset == 2, then we want a bezier curve that uses the first, second and third data * */ for (unsigned int i = 0; it != mBeamData.end() && i < mSamples; ++i) { QPen pen; pen.setWidth(1); pen.setCapStyle(Qt::FlatCap); /** * We will plot 1 bezier curve for every 3 points, with the 4th point being the end * of one bezier curve and the start of the second. * This does means the bezier curves will not join nicely, * but it should be better than nothing. */ QList datapoints = *it; QList prev_datapoints = datapoints; QList prev_prev_datapoints = datapoints; QList prev_prev_prev_datapoints = datapoints; if (i == 0 && mBezierCurveOffset>0) { /** * We are plotting an incomplete bezier curve - we don't have all the data we want. * Try to cope */ xPos += horizontalScale*mBezierCurveOffset; if (mBezierCurveOffset == 1) { prev_datapoints = *it; ++it; //Now we are on the first element of the next group, if it exists if (it != mBeamData.end()) { prev_prev_prev_datapoints = prev_prev_datapoints = *it; } else { prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints; } } else { // mBezierCurveOffset must be 2 now prev_datapoints = *it; Q_ASSERT(it != mBeamData.end()); ++it; prev_prev_datapoints = *it; Q_ASSERT(it != mBeamData.end()); ++it; //Now we are on the first element of the next group, if it exists if (it != mBeamData.end()) { prev_prev_prev_datapoints = *it; } else { prev_prev_prev_datapoints = prev_prev_datapoints; } } } else { /** * We have a group of 3 points at least. That's 1 start point and 2 control points. */ xPos += horizontalScale*3; it++; if (it != mBeamData.end()) { prev_datapoints = *it; it++; if (it != mBeamData.end()) { prev_prev_datapoints = *it; it++; //We are now on the next set of data points if (it != mBeamData.end()) { // We have this datapoint, so use it for our finish point prev_prev_prev_datapoints = *it; } else { // We don't have the next set, so use our last control point as our finish point prev_prev_prev_datapoints = prev_prev_datapoints; } } else { prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints; } } else { prev_prev_prev_datapoints = prev_prev_datapoints = prev_datapoints = datapoints; } } float x0 = w - xPos + 3.0*horizontalScale; float x1 = w - xPos + 2.0*horizontalScale; float x2 = w - xPos + 1.0*horizontalScale; float x3 = w - xPos; float y0 = h -1 + top; float y1 = y0; float y2 = y0; float y3 = y0; int offset = 0; //Our line is 2 pixels thick. This means that when we draw the area, we need to offset double max_y=0; double min_y=0; for (int j = qMin(datapoints.size(), mBeamColors.size())-1; j >=0 ; --j) { if ( mUseAutoRange) { //If we use autorange, then we need to prepare the min and max values for _next_ time we paint //if we are stacking the beams, then we need to add the maximums together double current_maxvalue = qMax(datapoints[j], qMax(prev_datapoints[j], qMax(prev_prev_datapoints[j], prev_prev_prev_datapoints[j]))); double current_minvalue = qMin(datapoints[j], qMin(prev_datapoints[j], qMin(prev_prev_datapoints[j], prev_prev_prev_datapoints[j]))); mMaxValue = qMax(mMaxValue, current_maxvalue); mMinValue = qMin(mMinValue, current_maxvalue); if( mStackBeams ) { max_y += current_maxvalue; min_y += current_minvalue; } } /* * Draw polygon only if enough data points are available. */ if ( j < prev_prev_prev_datapoints.count() && j < prev_prev_datapoints.count() && j < prev_datapoints.count() ) { QPolygon curve( 4 ); /* The height of the whole widget is h+top-> The height of the area we are plotting in is just h. * The y coordinate system starts from the top, so at the bottom the y coordinate is h+top * So to draw a point at value y', we need to put this at h+top-y' */ float delta_y0; delta_y0 = (datapoints[j] - mNiceMinValue)*scaleFac; float delta_y1; delta_y1 = (prev_datapoints[j] - mNiceMinValue)*scaleFac; float delta_y2; delta_y2 = (prev_prev_datapoints[j] - mNiceMinValue)*scaleFac; float delta_y3; delta_y3 = (prev_prev_prev_datapoints[j] - mNiceMinValue)*scaleFac; QPainterPath path; if(mStackBeams && offset) { //we don't want the lines to overdraw each other. This isn't a great solution though :( if(delta_y0 < 3) delta_y0=3; if(delta_y1 < 3) delta_y1=3; if(delta_y2 < 3) delta_y2=3; if(delta_y3 < 3) delta_y3=3; } path.moveTo( x0,y0-delta_y0); path.cubicTo( x1,y1-delta_y1,x2,y2-delta_y2,x3,y3-delta_y3 ); if(mFillBeams) { QPainterPath path2(path); QLinearGradient myGradient(0,(h-1+top),0,(h-1+top)/5); Q_ASSERT(mBeamColorsDark.size() >= j); Q_ASSERT(mBeamColors.size() >= j); QColor c0(mBeamColorsDark[j]); QColor c1(mBeamColors[j]); c0.setAlpha(150); c1.setAlpha(150); myGradient.setColorAt(0, c0); myGradient.setColorAt(1, c1); path2.lineTo( x3,y3-offset); if(mStackBeams) path2.cubicTo( x2,y2-offset,x1,y1-offset,x0,y0-offset); //offset is set to 1 after the first beam is drawn, so we don't trample on top of the 2pt thick line else path2.lineTo(x0,y0-1); p->setBrush(myGradient); p->setPen(Qt::NoPen); p->drawPath( path2 ); } p->setBrush(Qt::NoBrush); Q_ASSERT(mBeamColors.size() >= j); pen.setColor(mBeamColors[j]); p->setPen(pen); p->drawPath( path ); if(mStackBeams) { //We can draw the beams stacked on top of each other. This means that say beam 0 has the value 2 and beam // 1 has the value 3, then we plot beam 0 at 2 and beam 1 at 2+3 = 5. y0-=delta_y0; y1-=delta_y1; y2-=delta_y2; y3-=delta_y3; offset = 1; //see the comment further up for int offset; } } if ( mUseAutoRange && mStackBeams) { mMaxValue = qMax(max_y, mMaxValue); mMinValue = qMin(min_y, mMinValue); } } } } void TrafficGraph::drawAxisText(QPainter *p, int top, int h) { /* Draw horizontal lines and values. Lines are always drawn. * Values are only draw when width is greater than 60 */ QString val; /* top = 0 or font.height depending on whether there's a topbar or not * h = graphing area.height - i.e. the actual space we have to draw inside * * Note we are drawing from 0,0 as the top left corner. So we have to add on top to get to the top of where we are drawing * so top+h is the height of the widget */ p->setPen( mFontColor ); double stepsize = mNiceRange/(mScaleDownBy*(mHorizontalLinesCount+1)); int step = (int)ceil((mHorizontalLinesCount+1) * (p->fontMetrics().height() + p->fontMetrics().leading()/2.0) / h); if(step ==0) step = 1; for ( int y = mHorizontalLinesCount+1; y >= 1; y-= step) { int y_coord = top + (y * (h-1)) / (mHorizontalLinesCount+1); //Make sure it's y*h first to avoid rounding bugs if(y_coord - p->fontMetrics().ascent() < top) continue; //at most, only allow 4 pixels of the text to be covered up by the top bar. Otherwise just don't bother to draw it double value; if((uint)y == mHorizontalLinesCount+1) value = mNiceMinValue; //sometimes using the formulas gives us a value very slightly off else value = mNiceMaxValue/mScaleDownBy - y * stepsize; QString number = KGlobal::locale()->formatNumber( value, mPrecision); val = QString( "%1 %2" ).arg( number, mUnit ); p->drawText( 6, y_coord - 3, val ); } } void TrafficGraph::drawHorizontalLines(QPainter *p, int top, int w, int h) { p->setPen( mHorizontalLinesColor ); for ( uint y = 0; y <= mHorizontalLinesCount+1; y++ ) { //note that the y_coord starts from 0. so we draw from pixel number 0 to h-1. Thus the -1 in the y_coord int y_coord = top + (y * (h-1)) / (mHorizontalLinesCount+1); //Make sure it's y*h first to avoid rounding bugs p->drawLine( 0, y_coord, w - 2, y_coord); } } double TrafficGraph::lastValue( int i) const { if(mBeamData.isEmpty() || mBeamData.first().size() <= i) return 0; return mBeamData.first()[i]; } QString TrafficGraph::lastValueAsString( int i) const { if(mBeamData.isEmpty()) return QString(); double value = mBeamData.first()[i] / mScaleDownBy; //retrieve the newest value for this beam then scale it correct QString number = KGlobal::locale()->formatNumber( value, (value >= 100)?0:2); return QString( "%1 %2").arg(number, mUnit); } } #include "trafficgraph.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/filtereditor.h0000644000175000017500000002027211276037142022510 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETSFILTEREDITOR_H #define KFTPWIDGETSFILTEREDITOR_H #include "widgetlister.h" #include "misc/filter.h" #include #include #include #include #include #include #include #include namespace KFTPWidgets { /** * A visual representation of a condition. * * @author Jernej Kos */ class FilterConditionWidget : public QWidget { Q_OBJECT public: /** * Class constructor. * * @param parent Parent widget */ FilterConditionWidget(QWidget *parent); /** * Associate a condition with this widget. * * @param condition The internal condition representation */ void setCondition(const KFTPCore::Filter::Condition *condition); /** * Return the condition associated with this widget. * * @return A valid condition or 0 if no condition has been associated */ KFTPCore::Filter::Condition *condition() const { return m_condition; } private slots: void slotFieldChanged(int field); void slotTypeChanged(); void slotValueChanged(); private: QComboBox *m_fieldCombo; QStackedWidget *m_typeStack; QStackedWidget *m_valueStack; KFTPCore::Filter::Condition *m_condition; }; /** * A container for condition representation widgets. * * @author Jernej Kos */ class FilterConditionWidgetLister : public WidgetLister { Q_OBJECT public: /** * Class constructor. * * @param parent Parent widget */ FilterConditionWidgetLister(QWidget *parent); /** * Load the conditions from the specified rule. * * @param rule The rule instance */ void loadConditions(KFTPCore::Filter::Rule *rule); protected: QWidget *createWidget(QWidget *parent); protected slots: void slotMore(); void slotFewer(); void slotClear(); private: KFTPCore::Filter::Rule *m_rule; }; /** * A list of conditions together with all/any configuration. * * @author Jernej Kos */ class FilterConditionsList : public QGroupBox { Q_OBJECT public: /** * Class constructor. * * @param parent Parent widget */ FilterConditionsList(QWidget *parent); public slots: /** * Reset the condition list and disable it. */ void reset(); /** * Load the conditions from the specified rule. * * @param rule The rule instance */ void loadRule(KFTPCore::Filter::Rule *rule); private slots: void slotMatchTypeChanged(int type); private: QRadioButton *m_buttonAll; QRadioButton *m_buttonAny; FilterConditionWidgetLister *m_lister; KFTPCore::Filter::Rule *m_rule; }; /** * A visual representation of an action. * * @author Jernej Kos */ class FilterActionWidget : public QWidget { Q_OBJECT public: /** * Class constructor. * * @param parent Parent widget */ FilterActionWidget(QWidget *parent); /** * Associate an action with this widget. * * @param action The internal action representation */ void setAction(const KFTPCore::Filter::Action *action); /** * Return the action associated with this widget. * * @return A valid action or 0 if no action has been associated */ KFTPCore::Filter::Action *action() const { return m_action; } private slots: void slotActionChanged(int field); void slotValueChanged(); private: QComboBox *m_actionCombo; QStackedWidget *m_valueStack; KFTPCore::Filter::Action *m_action; }; /** * A container for action representation widgets. * * @author Jernej Kos */ class FilterActionWidgetLister : public WidgetLister { Q_OBJECT public: /** * Class constructor. * * @param parent Parent widget */ FilterActionWidgetLister(QWidget *parent); /** * Load the actions from the specified rule. * * @param rule The rule instance */ void loadActions(KFTPCore::Filter::Rule *rule); protected: QWidget *createWidget(QWidget *parent); protected slots: void slotMore(); void slotFewer(); void slotClear(); private: KFTPCore::Filter::Rule *m_rule; }; /** * A list of actions. * * @author Jernej Kos */ class FilterActionsList : public QGroupBox { Q_OBJECT public: /** * Class constructor. * * @param parent Parent widget */ FilterActionsList(QWidget *parent); public slots: /** * Reset the action list and disable it. */ void reset(); /** * Load the actions from the specified rule. * * @param rule The rule instance */ void loadRule(KFTPCore::Filter::Rule *rule); private: FilterActionWidgetLister *m_lister; KFTPCore::Filter::Rule *m_rule; }; /** * A widget that displays the list of currently loaded filter rules. * * @author Jernej Kos */ class FilterListWidget : public QGroupBox { Q_OBJECT public: /** * Class constructor. * * @param parent Parent widget */ FilterListWidget(QWidget *parent); /** * Reset the filter editor and reload all the rules. */ void reset(); private slots: void slotItemActivated(QListWidgetItem *item); void slotNewRule(); void slotDeleteRule(); void slotRenameRule(); void slotCopyRule(); void slotUp(); void slotDown(); private: QListWidget *m_listWidget; KPushButton *m_buttonUp; KPushButton *m_buttonDown; QPushButton *m_buttonNew; QPushButton *m_buttonCopy; QPushButton *m_buttonDelete; QPushButton *m_buttonRename; signals: /** * This signal gets emitted when a new rule should be displayed by * other widgets. * * @param rule The rule to display */ void ruleChanged(KFTPCore::Filter::Rule *rule); /** * This signal gets emitted when a rule is removed. */ void ruleRemoved(); }; /** * This widget is a global filter editor and enables the user to add, * remove or modify existing filters. * * @author Jernej Kos */ class FilterEditor : public QWidget { Q_OBJECT public: /** * Class constructor. */ FilterEditor(QWidget *parent); /** * Reset the filter editor and reload all the rules. */ void reset(); private slots: void slotRuleChanged(KFTPCore::Filter::Rule *rule); void slotRuleRemoved(); void slotEnabledChanged(); private: KFTPCore::Filter::Rule *m_rule; QCheckBox *m_enabledCheck; FilterListWidget *m_listWidget; FilterConditionsList *m_conditionsList; FilterActionsList *m_actionsList; }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/kftpserverlineedit.h0000644000175000017500000000451711276037142023731 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPSERVERLINEEDIT_H #define KFTPSERVERLINEEDIT_H #include #include #include namespace KFTPBookmarks { class Site; } /** @author Jernej Kos */ class KFTPServerLineEdit : public QWidget { Q_OBJECT public: KFTPServerLineEdit(QWidget *parent = 0, const char *name = 0, Qt::WFlags f = 0); ~KFTPServerLineEdit(); KFTPBookmarks::Site *getCurrentSite() { return m_currentSite; } void setCurrentSite(KFTPBookmarks::Site *site); void clear(); private: KFTPBookmarks::Site *m_currentSite; KLineEdit *m_lineEdit; private slots: void slotSelectButtonClicked(); signals: void siteChanged(KFTPBookmarks::Site *site); }; #endif kftpgrabber-0.8.99~svn1214766/src/widgets/logview.h0000644000175000017500000000533411276037142021472 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2008 by the KFTPGrabber developers * Copyright (C) 2003-2008 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPLOGVIEW_H #define KFTPLOGVIEW_H #include #include namespace KFTPWidgets { /** * This class provides a simple log widget based on QPlainTextEdit. * * @author Jernej Kos */ class LogView : public QPlainTextEdit { Q_OBJECT public: /** * Valid line format types. */ enum LineType { FtpResponse = 0, FtpCommand, FtpMultiline, FtpStatus, FtpError, Plain }; /** * Class constructor. * * @param parent Parent widget */ LogView(QWidget *parent); /** * Class destructor. */ ~LogView(); /** * Appends some text. * * @param str String to append * @param type Optional line format type */ void append(const QString &str, LineType type = Plain); protected: KAction *m_saveToFileAction; KAction *m_clearLogAction; /** * @overload * Reimplemented from QAbstractScrollArea. */ void contextMenuEvent(QContextMenuEvent *event); private slots: void slotSaveToFile(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/kftpselectserverdialog.cpp0000644000175000017500000000551311276037142025123 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftpbookmarks.h" #include "kftpselectserverdialog.h" #include "kftpbookmarks.h" #include "bookmarks/listview.h" #include #include #include using namespace KFTPGrabberBase; KFTPSelectServerDialog::KFTPSelectServerDialog(QWidget *parent, const char *name) : KDialogBase(parent, name, true, "Select a server", KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok), m_selectedSite(0) { m_tree = new KFTPWidgets::Bookmarks::ListView(KFTPBookmarks::Manager::self(), this); m_tree->setMinimumWidth(270); m_tree->fillBookmarkData(); connect(m_tree, SIGNAL(clicked(Q3ListViewItem*)), this, SLOT(slotTreeClicked())); // Set some stuff setMainWidget(m_tree); enableButtonOk(false); } void KFTPSelectServerDialog::slotTreeClicked() { enableButtonOk(false); if (m_tree->selectedItem()) { if (static_cast(m_tree->selectedItem())->m_type == 1) { // Set the active server m_selectedSite = static_cast(m_tree->selectedItem())->m_site; enableButtonOk(true); return; } } } #include "kftpselectserverdialog.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/kftpselectserverdialog.h0000644000175000017500000000440411276037142024566 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPSELECTSERVERDIALOG_H #define KFTPSELECTSERVERDIALOG_H #include #include #include namespace KFTPBookmarks { class Site; } namespace KFTPWidgets { namespace Bookmarks { class ListView; } } /** @author Jernej Kos */ class KFTPSelectServerDialog : public KDialogBase { Q_OBJECT public: KFTPSelectServerDialog(QWidget *parent = 0, const char *name = 0); KFTPBookmarks::Site *getSelectedSite() { return m_selectedSite; } private: KFTPWidgets::Bookmarks::ListView *m_tree; KFTPBookmarks::Site *m_selectedSite; private slots: void slotTreeClicked(); }; #endif kftpgrabber-0.8.99~svn1214766/src/widgets/systemtray.h0000644000175000017500000000462611276037142022245 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETSSYSTEMTRAY_H #define KFTPWIDGETSSYSTEMTRAY_H #include #include #include class MainWindow; namespace KFTPWidgets { /** * A system tray icon that is used for some actions. * * @author Jernej Kos */ class SystemTray : public KSystemTrayIcon { Q_OBJECT public: /** * Get the global system tray instance. */ static SystemTray *self() { return SystemTray::m_self; } /** * Class constructor. */ SystemTray(MainWindow *parent); /** * Class destructor. */ ~SystemTray(); protected: static SystemTray *m_self; private: KActionMenu *m_bookmarkMenu; private slots: void slotUpdateBookmarks(); void slotQuitSelected(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/listview.h0000644000175000017500000000424711276037142021666 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPLISTVIEW_H #define KFTPLISTVIEW_H #include //Added by qt3to4: #include namespace KFTPWidgets { /** * @author Jernej Kos */ class ListView : public K3ListView { Q_OBJECT public: ListView(QWidget *parent); ~ListView(); void setEmptyListText(const QString &text); virtual void resizeEvent(QResizeEvent *e); protected: virtual void drawContentsOffset(QPainter * p, int ox, int oy, int cx, int cy, int cw, int ch ); private: QString m_emptyListText; }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/kftpserverlineedit.cpp0000644000175000017500000000635111276037142024262 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftpbookmarks.h" #include "kftpserverlineedit.h" #include "kftpselectserverdialog.h" #include #include #include #include //Added by qt3to4: #include KFTPServerLineEdit::KFTPServerLineEdit(QWidget *parent, const char *name, Qt::WFlags f) : QWidget(parent, name, f), m_currentSite(0) { Q3HBoxLayout *layout = new Q3HBoxLayout(this, 0, KDialog::spacingHint()); m_lineEdit = new KLineEdit(this); m_lineEdit->setReadOnly(true); KPushButton *selectButton = new KPushButton(i18n("Select..."), this); selectButton->setFlat(true); connect(selectButton, SIGNAL(clicked()), this, SLOT(slotSelectButtonClicked())); layout->addWidget(m_lineEdit); layout->addWidget(selectButton); } KFTPServerLineEdit::~KFTPServerLineEdit() { } void KFTPServerLineEdit::setCurrentSite(KFTPBookmarks::Site *site) { if (site) { m_currentSite = site; m_lineEdit->setText(m_currentSite->getAttribute("name")); emit siteChanged(m_currentSite); } else { m_currentSite = 0L; clear(); } } void KFTPServerLineEdit::clear() { m_lineEdit->clear(); } void KFTPServerLineEdit::slotSelectButtonClicked() { KFTPSelectServerDialog *dialog = new KFTPSelectServerDialog(this); if (dialog->exec() == QDialog::Accepted) { m_currentSite = dialog->getSelectedSite(); if (m_currentSite) m_lineEdit->setText(m_currentSite->getAttribute("name")); else m_lineEdit->setText(i18n("No name")); emit siteChanged(m_currentSite); } delete dialog; } #include "kftpserverlineedit.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/filtereditor.cpp0000644000175000017500000004641611276037142023053 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "filtereditor.h" #include "listview.h" #include "misc/filterwidgethandler.h" #include #include #include #include #include using namespace KFTPCore::Filter; namespace KFTPWidgets { FilterEditor::FilterEditor(QWidget *parent) : QWidget(parent), m_rule(0) { QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->setSpacing(KDialog::spacingHint()); m_listWidget = new FilterListWidget(this); mainLayout->addWidget(m_listWidget, 1); QVBoxLayout *rightLayout = new QVBoxLayout(); rightLayout->setParent(mainLayout); mainLayout->addItem(rightLayout); mainLayout->setStretchFactor(rightLayout, KDialog::spacingHint()); m_enabledCheck = new QCheckBox(i18n("Filter &enabled"), this); m_enabledCheck->setEnabled(false); rightLayout->addWidget(m_enabledCheck); m_conditionsList = new FilterConditionsList(this); rightLayout->addWidget(m_conditionsList/*, 0, Qt::AlignTop*/); m_actionsList = new FilterActionsList(this); rightLayout->addWidget(m_actionsList/*, 0, Qt::AlignTop*/); rightLayout->addStretch(1); // Connect some signals connect(m_enabledCheck, SIGNAL(clicked()), this, SLOT(slotEnabledChanged())); connect(m_listWidget, SIGNAL(ruleChanged(KFTPCore::Filter::Rule*)), this, SLOT(slotRuleChanged(KFTPCore::Filter::Rule*))); connect(m_listWidget, SIGNAL(ruleRemoved()), this, SLOT(slotRuleRemoved())); connect(m_listWidget, SIGNAL(ruleChanged(KFTPCore::Filter::Rule*)), m_conditionsList, SLOT(loadRule(KFTPCore::Filter::Rule*))); connect(m_listWidget, SIGNAL(ruleRemoved()), m_conditionsList, SLOT(reset())); connect(m_listWidget, SIGNAL(ruleChanged(KFTPCore::Filter::Rule*)), m_actionsList, SLOT(loadRule(KFTPCore::Filter::Rule*))); connect(m_listWidget, SIGNAL(ruleRemoved()), m_actionsList, SLOT(reset())); // Reset the view to load all the current rules m_listWidget->reset(); } void FilterEditor::slotRuleChanged(KFTPCore::Filter::Rule *rule) { m_enabledCheck->setEnabled(true); m_enabledCheck->setChecked(rule->isEnabled()); m_rule = rule; } void FilterEditor::slotRuleRemoved() { m_enabledCheck->setChecked(false); m_enabledCheck->setEnabled(false); } void FilterEditor::slotEnabledChanged() { if (m_rule) m_rule->setEnabled(m_enabledCheck->isChecked()); } void FilterEditor::reset() { m_enabledCheck->setChecked(false); m_enabledCheck->setEnabled(false); m_conditionsList->reset(); m_actionsList->reset(); m_listWidget->reset(); } FilterListWidget::FilterListWidget(QWidget *parent) : QGroupBox(i18n("Filters"), parent) { QVBoxLayout *layout = new QVBoxLayout(this); m_listWidget = new QListWidget(this); layout->addWidget(m_listWidget); KHBox *hb = new KHBox(this); hb->setSpacing(4); layout->addWidget(hb); // Up/down buttons m_buttonUp = new KPushButton(QString::null, hb); m_buttonUp->setIcon(KIcon("go-up")); m_buttonUp->setMinimumSize(m_buttonUp->sizeHint() * 1.2); m_buttonDown = new KPushButton(QString::null, hb); m_buttonDown->setIcon(KIcon("go-down")); m_buttonDown->setMinimumSize(m_buttonDown->sizeHint() * 1.2); m_buttonUp->setToolTip(i18n("Up")); m_buttonDown->setToolTip(i18n("Down")); // New, copy, delete buttons hb = new KHBox(this); hb->setSpacing(4); layout->addWidget(hb); m_buttonNew = new QPushButton(QString::null, hb); m_buttonNew->setIcon(KIcon("list-add")); m_buttonNew->setMinimumSize(m_buttonNew->sizeHint() * 1.2); m_buttonCopy = new QPushButton(QString::null, hb); m_buttonCopy->setIcon(KIcon("edit-copy")); m_buttonCopy->setMinimumSize(m_buttonCopy->sizeHint() * 1.2); m_buttonDelete = new QPushButton(QString::null, hb); m_buttonDelete->setIcon(KIcon("list-remove")); m_buttonDelete->setMinimumSize(m_buttonDelete->sizeHint() * 1.2); m_buttonRename = new QPushButton(QString::null, hb); m_buttonRename->setIcon(KIcon("edit-rename")); m_buttonRename->setMinimumSize(m_buttonRename->sizeHint() * 1.2); m_buttonNew->setToolTip(i18n("New")); m_buttonCopy->setToolTip(i18n("Copy")); m_buttonDelete->setToolTip(i18n("Delete")); m_buttonRename->setToolTip(i18n("Rename")); // Connect the signals connect(m_buttonNew, SIGNAL(clicked()), this, SLOT(slotNewRule())); connect(m_buttonDelete, SIGNAL(clicked()), this, SLOT(slotDeleteRule())); connect(m_buttonRename, SIGNAL(clicked()), this, SLOT(slotRenameRule())); connect(m_buttonCopy, SIGNAL(clicked()), this, SLOT(slotCopyRule())); connect(m_buttonUp, SIGNAL(clicked()), this, SLOT(slotUp())); connect(m_buttonDown, SIGNAL(clicked()), this, SLOT(slotDown())); connect(m_listWidget, SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)), this, SLOT(slotItemActivated(QListWidgetItem*))); m_buttonUp->setEnabled(false); m_buttonDown->setEnabled(false); m_buttonCopy->setEnabled(false); m_buttonDelete->setEnabled(false); m_buttonRename->setEnabled(false); } void FilterListWidget::reset() { m_listWidget->clear(); // Load all existing rules Filters *filters = Filters::self(); Filters::ConstIterator le = filters->constEnd(); for (Filters::ConstIterator i = filters->constBegin(); i != le; ++i) { QListWidgetItem *item = new QListWidgetItem(); item->setText((*i)->name()); item->setData(Qt::UserRole, QVariant::fromValue(*i)); m_listWidget->addItem(item); } // Select the first rule m_listWidget->setCurrentItem(m_listWidget->item(0)); } void FilterListWidget::slotItemActivated(QListWidgetItem *item) { const int row = m_listWidget->row(item); if (row < 0) return; m_buttonUp->setEnabled(row > 0); m_buttonDown->setEnabled(row < m_listWidget->count() - 1); m_buttonRename->setEnabled(true); m_buttonCopy->setEnabled(true); m_buttonDelete->setEnabled(true); // Signal the rule change Rule *rule = item->data(Qt::UserRole).value(); if (rule) emit ruleChanged(rule); } void FilterListWidget::slotNewRule() { Rule *rule = new Rule(i18n("Unnamed Rule")); QListWidgetItem *current = m_listWidget->currentItem(); QListWidgetItem *item = new QListWidgetItem(); item->setText(rule->name()); item->setData(Qt::UserRole, QVariant::fromValue(rule)); if (current) { Rule *currentRule = current->data(Qt::UserRole).value(); Filters::self()->insert(Filters::self()->indexOf(currentRule), rule); m_listWidget->insertItem(m_listWidget->row(current), item); } else { Filters::self()->append(rule); m_listWidget->addItem(item); } // Select the newly inserted item m_listWidget->setCurrentItem(item); } void FilterListWidget::slotDeleteRule() { QListWidgetItem *current = m_listWidget->currentItem(); if (current) { const int row = m_listWidget->row(current); Rule *rule = current->data(Qt::UserRole).value(); emit ruleRemoved(); delete current; Filters::self()->removeAll(rule); delete rule; //m_listWidget->setCurrentRow(row); } if (!m_listWidget->currentItem()) { m_buttonUp->setEnabled(false); m_buttonDown->setEnabled(false); m_buttonRename->setEnabled(false); m_buttonCopy->setEnabled(false); m_buttonDelete->setEnabled(false); } } void FilterListWidget::slotRenameRule() { QListWidgetItem *current = m_listWidget->currentItem(); if (current) { Rule *rule = current->data(Qt::UserRole).value(); QString name = KInputDialog::getText(i18n("Rename Rule"), i18n("Rename rule '%1' to:", rule->name()), rule->name()); if (name.trimmed().isEmpty()) name = i18n("Unnamed Rule"); rule->setName(name); current->setText(name); } } void FilterListWidget::slotCopyRule() { QListWidgetItem *current = m_listWidget->currentItem(); if (current) { Rule *currentRule = current->data(Qt::UserRole).value(); Rule *rule = new Rule(currentRule); QListWidgetItem *item = new QListWidgetItem(); item->setText(rule->name()); item->setData(Qt::UserRole, QVariant::fromValue(rule)); Filters::self()->insert(Filters::self()->indexOf(currentRule) + 1, rule); m_listWidget->insertItem(m_listWidget->row(current) + 1, item); m_listWidget->setCurrentItem(item); } } void FilterListWidget::slotUp() { QListWidgetItem *current = m_listWidget->currentItem(); if (current) { const int row = m_listWidget->row(current); if (!row) return; // Remove the current rule Rule *rule = current->data(Qt::UserRole).value(); const int index = Filters::self()->indexOf(rule); Filters::self()->takeAt(index); m_listWidget->takeItem(row); // Reinsert the item one position higher Filters::self()->insert(index - 1, rule); m_listWidget->insertItem(row - 1, current); m_buttonUp->setEnabled(row - 1 > 0); m_listWidget->setCurrentItem(current); } } void FilterListWidget::slotDown() { QListWidgetItem *current = m_listWidget->currentItem(); if (current) { const int row = m_listWidget->row(current); if (row == m_listWidget->count() - 1) return; // Remove the current rule Rule *rule = current->data(Qt::UserRole).value(); const int index = Filters::self()->indexOf(rule); Filters::self()->takeAt(index); m_listWidget->takeItem(row); // Reinsert the item one position lower Filters::self()->insert(index + 1, rule); m_listWidget->insertItem(row + 1, current); m_buttonDown->setEnabled(row + 1 < m_listWidget->count() - 1); m_listWidget->setCurrentItem(current); } } FilterConditionsList::FilterConditionsList(QWidget *parent) : QGroupBox(i18n("Conditions"), parent) { setEnabled(false); // Create the layout QVBoxLayout *layout = new QVBoxLayout(this); m_buttonAll = new QRadioButton(i18n("Match a&ll of the following"), this); m_buttonAny = new QRadioButton(i18n("Match an&y of the following"), this); layout->addWidget(m_buttonAll); layout->addWidget(m_buttonAny); m_buttonAll->setChecked(true); m_buttonAny->setChecked(false); QButtonGroup *bg = new QButtonGroup(this); bg->addButton(m_buttonAll, (int) ConditionChain::All); bg->addButton(m_buttonAny, (int) ConditionChain::Any); // Connect some signals connect(bg, SIGNAL(buttonClicked(int)), this, SLOT(slotMatchTypeChanged(int))); m_lister = new FilterConditionWidgetLister(this); layout->addWidget(m_lister); } void FilterConditionsList::reset() { m_lister->clear(); setEnabled(false); } void FilterConditionsList::loadRule(Rule *rule) { m_rule = rule; switch (rule->conditions()->type()) { case ConditionChain::All: m_buttonAll->setChecked(true); break; case ConditionChain::Any: m_buttonAny->setChecked(true); break; } m_lister->loadConditions(rule); setEnabled(true); } void FilterConditionsList::slotMatchTypeChanged(int type) { if (m_rule) const_cast(m_rule->conditions())->setType((ConditionChain::Type) type); } FilterConditionWidgetLister::FilterConditionWidgetLister(QWidget *parent) : WidgetLister(parent, 0, 7), m_rule(0) { setMinimumWidth(400); } void FilterConditionWidgetLister::loadConditions(KFTPCore::Filter::Rule *rule) { const ConditionChain *conditions = rule->conditions(); // Clear the current list setNumberShown(qMax(conditions->count(), 0)); ConditionChain::ConstIterator le = conditions->end(); QList::Iterator wi = m_widgetList.begin(); for (ConditionChain::ConstIterator i = conditions->begin(); i != le; ++i, ++wi) static_cast((*wi))->setCondition((*i)); m_rule = rule; } void FilterConditionWidgetLister::slotMore() { WidgetLister::slotMore(); // Actually add the condition and update the latest widget Condition *condition = new Condition(Filename, Condition::Contains, QVariant("")); const_cast(m_rule->conditions())->append(condition); static_cast(m_widgetList.last())->setCondition(condition); } void FilterConditionWidgetLister::slotFewer() { // Actually remove the condition Condition *condition = static_cast(m_widgetList.last())->condition(); const_cast(m_rule->conditions())->removeAll(condition); WidgetLister::slotFewer(); } void FilterConditionWidgetLister::slotClear() { if (m_rule) const_cast(m_rule->conditions())->clear(); WidgetLister::slotClear(); } QWidget *FilterConditionWidgetLister::createWidget(QWidget *parent) { return new FilterConditionWidget(parent); } FilterConditionWidget::FilterConditionWidget(QWidget *parent) : QWidget(parent), m_condition(0) { QHBoxLayout *layout = new QHBoxLayout(this); layout->setSpacing(KDialog::spacingHint()); layout->setMargin(0); m_fieldCombo = new QComboBox(this); m_fieldCombo->addItems(Filters::self()->getFieldNames()); layout->addWidget(m_fieldCombo); m_typeStack = new QStackedWidget(this); m_typeStack->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); layout->addWidget(m_typeStack); m_valueStack = new QStackedWidget(this); m_valueStack->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); layout->addWidget(m_valueStack); layout->setStretchFactor(m_valueStack, 10); // Initialize widgets WidgetHandlerManager::self()->createConditionWidgets(m_typeStack, m_valueStack, this); // Connect signals connect(m_fieldCombo, SIGNAL(activated(int)), this, SLOT(slotFieldChanged(int))); setFocusProxy(m_fieldCombo); } void FilterConditionWidget::setCondition(const Condition *condition) { m_condition = const_cast(condition); m_fieldCombo->setCurrentIndex((int) condition->field()); WidgetHandlerManager::self()->setCondition(m_typeStack, m_valueStack, condition); } void FilterConditionWidget::slotFieldChanged(int field) { WidgetHandlerManager::self()->update((Field) field, m_typeStack, m_valueStack); if (m_condition) { // Update the current condition m_condition->setField((Field) field); slotTypeChanged(); } } void FilterConditionWidget::slotTypeChanged() { if (m_condition) { // Update the current condition m_condition->setType(WidgetHandlerManager::self()->getConditionType(m_condition->field(), m_typeStack)); slotValueChanged(); } } void FilterConditionWidget::slotValueChanged() { if (m_condition) { // Update the current condition m_condition->setValue(WidgetHandlerManager::self()->getConditionValue(m_condition->field(), m_valueStack)); } } FilterActionsList::FilterActionsList(QWidget *parent) : QGroupBox(i18n("Actions"), parent) { setEnabled(false); QVBoxLayout *layout = new QVBoxLayout(this); m_lister = new FilterActionWidgetLister(this); layout->addWidget(m_lister); } void FilterActionsList::reset() { m_lister->clear(); setEnabled(false); } void FilterActionsList::loadRule(Rule *rule) { m_rule = rule; m_lister->loadActions(rule); setEnabled(true); } FilterActionWidgetLister::FilterActionWidgetLister(QWidget *parent) : WidgetLister(parent, 0, 7), m_rule(0) { setMinimumWidth(400); } void FilterActionWidgetLister::loadActions(KFTPCore::Filter::Rule *rule) { const ActionChain *actions = rule->actions(); // Clear the current list setNumberShown(qMax(actions->count(), 0)); ActionChain::ConstIterator le = actions->end(); QList::Iterator wi = m_widgetList.begin(); for (ActionChain::ConstIterator i = actions->begin(); i != le; ++i, ++wi) static_cast((*wi))->setAction((*i)); m_rule = rule; } void FilterActionWidgetLister::slotMore() { WidgetLister::slotMore(); // Actually add the action and update the latest widget Action *action = new Action(Action::None, QVariant()); const_cast(m_rule->actions())->append(action); static_cast(m_widgetList.last())->setAction(action); } void FilterActionWidgetLister::slotFewer() { // Actually remove the action Action *action = static_cast(m_widgetList.last())->action(); const_cast(m_rule->actions())->removeAll(action); WidgetLister::slotFewer(); } void FilterActionWidgetLister::slotClear() { if (m_rule) const_cast(m_rule->actions())->clear(); WidgetLister::slotClear(); } QWidget *FilterActionWidgetLister::createWidget(QWidget *parent) { return new FilterActionWidget(parent); } FilterActionWidget::FilterActionWidget(QWidget *parent) : QWidget(parent), m_action(0) { QHBoxLayout *layout = new QHBoxLayout(this); layout->setSpacing(KDialog::spacingHint()); layout->setMargin(0); m_actionCombo = new QComboBox(this); m_actionCombo->addItems(Filters::self()->getActionNames()); layout->addWidget(m_actionCombo); m_valueStack = new QStackedWidget(this); m_valueStack->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); layout->addWidget(m_valueStack); layout->setStretchFactor(m_valueStack, 10); // Initialize widgets WidgetHandlerManager::self()->createActionWidgets(m_valueStack, this); // Connect signals connect(m_actionCombo, SIGNAL(activated(int)), this, SLOT(slotActionChanged(int))); connect(m_actionCombo, SIGNAL(activated(int)), m_valueStack, SLOT(setCurrentIndex(int))); setFocusProxy(m_actionCombo); } void FilterActionWidget::setAction(const Action *action) { m_action = const_cast(action); m_actionCombo->setCurrentIndex((int) action->type()); WidgetHandlerManager::self()->setAction(m_valueStack, action); } void FilterActionWidget::slotActionChanged(int field) { if (m_action) { m_action->setType((Action::Type) field); slotValueChanged(); } } void FilterActionWidget::slotValueChanged() { if (m_action) m_action->setValue(WidgetHandlerManager::self()->getActionValue(m_valueStack)); } } #include "filtereditor.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/trafficgraph.h0000644000175000017500000001645311276037142022462 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 1999-2002 Chris Schlaeger * Copyright (C) 2006-2007 John Tapsell * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETSTRAFFICGRAPH_H #define KFTPWIDGETSTRAFFICGRAPH_H #include #include #include #include #include class QColor; class QSvgRenderer; namespace KFTPWidgets { class TrafficGraph : public QWidget { Q_OBJECT public: TrafficGraph(QWidget *parent); ~TrafficGraph(); bool addBeam( const QColor &color ); void addSample( const QList &samples ); void reorderBeams( const QList& newOrder ); void removeBeam( uint pos ); void changeRange( int beam, double min, double max ); QList &beamColors(); void setTitle( const QString &title ); QString title() const; void setTranslatedUnit( const QString &unit ); QString translatedUnit() const; void setScaleDownBy( double value ); double scaleDownBy() const; void setUseAutoRange( bool value ); bool useAutoRange() const; void setMinValue( double min ); double minValue() const; void setMaxValue( double max ); double maxValue() const; void setHorizontalScale( uint scale ); int horizontalScale() const; void setShowVerticalLines( bool value ); bool showVerticalLines() const; void setVerticalLinesColor( const QColor &color ); QColor verticalLinesColor() const; void setVerticalLinesDistance( uint distance ); int verticalLinesDistance() const; void setVerticalLinesScroll( bool value ); bool verticalLinesScroll() const; void setShowHorizontalLines( bool value ); bool showHorizontalLines() const; void setHorizontalLinesColor( const QColor &color ); QColor horizontalLinesColor() const; void setFontColor( const QColor &color ); QColor fontColor() const; void setFont( const QFont &font ); QFont font() const; void setHorizontalLinesCount( uint count ); int horizontalLinesCount() const; void setShowLabels( bool value ); bool showLabels() const; void setShowTopBar( bool value ); bool showTopBar() const; void setBackgroundColor( const QColor &color ); QColor backgroundColor() const; void setSvgBackground( const QString &filename ); QString svgBackground(); /** Return the last value that we have for beam i. * Returns 0 if not known */ double lastValue( int i) const; /** Return a translated string like: "34 %" or "100 KB" for beam i */ QString lastValueAsString( int i) const; /** Whether to show a white line on the left and bottom of the widget, for a 3D effect */ void setThinFrame( bool set); void setStackBeams( bool stack) { mStackBeams = stack; mFillBeams = stack; } bool stackBeams() const { return mStackBeams;} QImage getSnapshotImage(uint width, uint height); protected: void updateDataBuffers(); virtual void resizeEvent( QResizeEvent* ); virtual void paintEvent( QPaintEvent* ); void drawWidget(QPainter *p, uint w, uint height, int horizontalScale); void drawBackground(QPainter *p, int w, int h); void drawThinFrame(QPainter *p, int w, int h); void calculateNiceRange(); void drawTopBarFrame(QPainter *p, int fullWidth, int seperatorX, int height); void drawTopBarContents(QPainter *p, int x, int width, int height); void drawVerticalLines(QPainter *p, int top, int w, int h); /** Used from paint(). Draws all the beams on the paint device, given the top, width and height and the range of values to show */ void drawBeams(QPainter *p, int top, int w, int h, int horizontalScale); void drawAxisText(QPainter *p, int top, int h); void drawHorizontalLines(QPainter *p, int top, int w, int h); private: /** We make the svg renderer static so that an svg renderer is shared among all of the images. This is because a svg renderer takes up a lot of memory, so we want to * share them as much as we can */ static QHash sSvgRenderer; QString mSvgFilename; QImage mBackgroundImage; //A cache of the svg double mMinValue; double mMaxValue; double mNiceMinValue; double mNiceMaxValue; double mNiceRange; double mScaleDownBy; bool mUseAutoRange; /** Whether to show a white line on the left and bottom of the widget, for a 3D effect */ bool mShowThinFrame; /** Whether to stack the beams on top of each other */ bool mStackBeams; /** Whether to fill the area underneath the beams */ bool mFillBeams; uint mGraphStyle; bool mShowVerticalLines; int mPrecision; QColor mVerticalLinesColor; uint mVerticalLinesDistance; bool mVerticalLinesScroll; uint mVerticalLinesOffset; uint mHorizontalScale; bool mShowHorizontalLines; QColor mHorizontalLinesColor; uint mHorizontalLinesCount; bool mShowLabels; bool mShowTopBar; uint mBezierCurveOffset; QColor mBackgroundColor; QColor mFontColor; QLinkedList < QList > mBeamData; // Every item in the linked list contains a set of data points to plot. The first item is the newest QList< QColor> mBeamColors; //These colors match up against the QList in mBeamData QList< QColor> mBeamColorsDark; //These colors match up against the QList in mBeamData, and are darker than mBeamColors. Done for gradient effects unsigned int mSamples; //This is what mBeamData.size() should equal when full. When we start off and have no data then mSamples will be higher. If we resize the widget so it's smaller, then for a short while this will be smaller int mNewestIndex; //The index to the newest item added. newestIndex+1 is the second newest, and so on QString mTitle; QString mUnit; QFont mFont; }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/sslerrorsdialog.ui0000644000175000017500000000722111276037142023417 0ustar michaelmichael SslErrorsDialog 0 0 410 285 0 0 0 0 32 32 Qt::Vertical 20 171 <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600; color:#ff0000;">SECURITY WARNING</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; color:#ff0000;"><span style=" font-weight:400; color:#000000;">One or more errors with this connection prevent validating the authenticity of the host you are connecting to. Please review the following list of errors, and click </span><span style=" font-weight:400; font-style:italic; color:#000000;">Ignore</span><span style=" font-weight:400; color:#000000;"> to continue, or </span><span style=" font-weight:400; font-style:italic; color:#000000;">Cancel</span><span style=" font-weight:400; color:#000000;"> to abort the connection.</span></p></body></html> true Errors encountered during SSL negotiation 5 5 5 5 Trust this certificate in further communications with this site kftpgrabber-0.8.99~svn1214766/src/widgets/sslerrorsdialog.h0000644000175000017500000000531611276037142023234 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_SSLERRORSDIALOG_H #define KFTPWIDGETS_SSLERRORSDIALOG_H #include #include #include #include "widgets/ui_sslerrorsdialog.h" namespace KFTPWidgets { /** * A simple dialog that displays errors ocurred during the SSL * negotiation phase. Also offers a link to review the peer * certificate information. * * @author Jernej Kos */ class SslErrorsDialog : public KDialog { Q_OBJECT public: /** * Class constructor. */ SslErrorsDialog(QWidget *parent = 0); /** * Sets the errors that should be displayed by this dialog. The list * should contain variants that can be converted to QSslError * instances. * * @param errors A list of errors ocurred during negotiation */ void setErrors(const QVariantList &errors); protected slots: /** * @overload * Reimplemented from KDialog. */ virtual void slotButtonClicked(int button); private: Ui::SslErrorsDialog ui; QSslCertificate m_certificate; }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/fingerprintverifydialog.h0000644000175000017500000000512411276037142024747 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETS_FINGERPRINTVERIFYDIALOG_H #define KFTPWIDGETS_FINGERPRINTVERIFYDIALOG_H #include #include "widgets/ui_fingerprintverifydialog.h" namespace KFTPWidgets { /** * A simple dialog that displays a fingerprint verification * form. * * @author Jernej Kos */ class FingerprintVerifyDialog : public KDialog { Q_OBJECT public: /** * Class constructor. */ FingerprintVerifyDialog(QWidget *parent = 0); /** * Sets the fingerprint that should be displayed by this dialog. * * @param fingerprint Raw fingerprint digest * @param url Site URL */ void setFingerprint(const QByteArray &fingerprint, const KUrl &url); protected slots: /** * @overload * Reimplemented from KDialog. */ virtual void slotButtonClicked(int button); private: Ui::FingerprintVerifyDialog ui; KUrl m_url; QByteArray m_fingerprint; }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/configfilter.h0000644000175000017500000000447411276037142022475 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETSCONFIGFILTER_H #define KFTPWIDGETSCONFIGFILTER_H #include #include #include // Layouts #include "ui/ui_config_filters.h" namespace KFTPWidgets { class FilterEditor; /** * Filter related configuration dialog. * * @author Jernej Kos */ class ConfigFilter : public QWidget { Q_OBJECT public: ConfigFilter(QWidget *parent); void saveSettings(); void loadSettings(); private: void asciiLoadExtensions(); QStringList asciiToStringList(); FilterEditor *m_filterEditor; Ui::ConfigFilterLayout ui; private slots: void slotAddAscii(); void slotRemoveAscii(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/systemtray.cpp0000644000175000017500000000550011276037142022570 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include #include #include #include "widgets/systemtray.h" #include "mainwindow.h" #include "kftpbookmarks.h" #include "misc/config.h" namespace KFTPWidgets { SystemTray *SystemTray::m_self = 0L; SystemTray::SystemTray(MainWindow *parent) : KSystemTrayIcon(parent) { m_self = this; // Set icon and show it setIcon(KIcon("kftpgrabber")); if (KFTPCore::Config::showSystrayIcon()) show(); // Add some actions m_bookmarkMenu = new KActionMenu(i18n("Bookmarks"), this); slotUpdateBookmarks(); // Let our bookmarks be up to date connect(KFTPBookmarks::Manager::self(), SIGNAL(update()), this, SLOT(slotUpdateBookmarks())); contextMenu()->addAction(m_bookmarkMenu); // Ensure that we actually quit connect(this, SIGNAL(quitSelected()), this, SLOT(slotQuitSelected())); } SystemTray::~SystemTray() { delete m_bookmarkMenu; } void SystemTray::slotQuitSelected() { //m_actions->m_closeApp = true; } void SystemTray::slotUpdateBookmarks() { // Re-create the bookmarks menu m_bookmarkMenu->menu()->clear(); KFTPBookmarks::Manager::self()->populateBookmarksMenu(m_bookmarkMenu); } } #include "systemtray.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/popupmessage.h0000644000175000017500000000666311276037142022534 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * Copyright (C) 2005 Max Howell * Copyright (C) 2005 Seb Ruiz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPWIDGETSPOPUPMESSAGE_H #define KFTPWIDGETSPOPUPMESSAGE_H #include "overlaywidget.h" #include #include #include class QLabel; class KPushButton; class QVBoxLayout; namespace KFTPWidgets { /** * Widget that animates itself into a position relative to an anchor widget. */ class PopupMessage : public OverlayWidget { Q_OBJECT public: /** * Possible animation effects. */ enum MaskEffect { Plain, Slide, Dissolve }; /** * Class constructor. * * @param parent Parent widget * @param anchor Which widget to tie the popup widget to * @param timeout How long to wait before auto closing */ PopupMessage(QWidget *parent, QWidget *anchor, int timeout = 5000); void addWidget(QWidget *widget); void setShowCloseButton(bool show); void setImage(const QString &location); void setImage(const QPixmap &pixmap); void setMaskEffect(MaskEffect type) { m_maskEffect = type; } void setText(const QString &text); void setTimeout(int timeout) { m_timeout = timeout; } //QSize sizeHint() const; public slots: void close(); void display(); protected: void timerEvent(QTimerEvent *event); void countDown(); void dissolveMask(); void plainMask(); void slideMask(); private: QLabel *m_icon; QLabel *m_text; KPushButton *m_close; QVBoxLayout *m_layout; QWidget *m_anchor; QWidget *m_parent; QBitmap m_mask; MaskEffect m_maskEffect; int m_dissolveSize; int m_dissolveDelta; int m_offset; int m_counter; int m_stage; int m_timeout; int m_timerId; }; } #endif kftpgrabber-0.8.99~svn1214766/src/widgets/configfilter.cpp0000644000175000017500000000667311276037142023033 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "configfilter.h" #include "filtereditor.h" #include "misc/config.h" #include #include #include #include #include #include #include #include namespace KFTPWidgets { ConfigFilter::ConfigFilter(QWidget *parent) : QWidget(parent) { // Create the main widget QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setContentsMargins(0, 0, 0, 0); QWidget *widget = new QWidget(this); ui.setupUi(widget); mainLayout->addWidget(widget); m_filterEditor = new FilterEditor(this); ui.tabWidget->insertTab(0, m_filterEditor, i18n("Filters")); ui.tabWidget->setCurrentIndex(0); loadSettings(); // Connect the slots connect(ui.addExtButton, SIGNAL(clicked()), this, SLOT(slotAddAscii())); connect(ui.removeExtButton, SIGNAL(clicked()), this, SLOT(slotRemoveAscii())); } void ConfigFilter::loadSettings() { //m_filterEditor->reset(); asciiLoadExtensions(); } void ConfigFilter::saveSettings() { // Save the settings KFTPCore::Config::setAsciiList(asciiToStringList()); } void ConfigFilter::slotAddAscii() { if (!ui.newExtension->text().trimmed().isEmpty()) { ui.extensionList->addItem(ui.newExtension->text().trimmed()); ui.newExtension->clear(); } } void ConfigFilter::slotRemoveAscii() { delete ui.extensionList->currentItem(); } void ConfigFilter::asciiLoadExtensions() { // Load the ascii extensions ui.extensionList->clear(); ui.extensionList->addItems(KFTPCore::Config::asciiList()); } QStringList ConfigFilter::asciiToStringList() { QStringList extensions; for (int i = 0; i < ui.extensionList->count(); i++) { extensions << ui.extensionList->item(i)->text(); } return extensions; } } #include "configfilter.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/listviewitem.cpp0000644000175000017500000000607711276037142023103 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "listviewitem.h" #include #include #include #include namespace KFTPWidgets { ListViewItem::ListViewItem(Q3ListView *parent) : K3ListViewItem(parent) { } void ListViewItem::setRichText(int col, const QString &text) { setText(col, QString::null); m_richText[col] = text; } void ListViewItem::setup() { Q3ListViewItem::setup(); int maxHeight = height(); for (int i = 0; i < listView()->header()->count() - 1; i++) { if (text(i).isNull()) { Q3SimpleRichText rt(m_richText[i], QFont()); maxHeight = rt.height() > maxHeight ? rt.height() : maxHeight; } } setHeight(maxHeight); } void ListViewItem::paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int alignment) { if (text(column).isNull()) { K3ListViewItem::paintCell(p, cg, column, width, alignment); int pad = 0; if (pixmap(column)) { pad = pixmap(column)->width() + 5; } Q3SimpleRichText rt(m_richText[column], p->font()); rt.draw(p, pad, 0, QRect(pad, 0, width, height()), cg); } else if (m_colors.contains(column)) { /*QColorGroup _cg(cg); QColor c = _cg.text(); _cg.setColor(QColorGroup::Text, m_colors[column]);*/ K3ListViewItem::paintCell(p, cg, column, width, alignment); //_cg.setColor(QColorGroup::Text, c); } else { K3ListViewItem::paintCell(p, cg, column, width, alignment); } } } kftpgrabber-0.8.99~svn1214766/src/widgets/kftpfiltereditorlayout.cpp0000644000175000017500000001013511276037142025163 0ustar michaelmichael#include /**************************************************************************** ** Form implementation generated from reading ui file '/home/kostko/development/kftpgrabber/src/widgets/kftpfiltereditorlayout.ui' ** ** Created: Mon Oct 20 16:14:00 2003 ** by: The User Interface Compiler ($Id: kftpfiltereditorlayout.cpp,v 1.1.1.1 2004/02/13 13:33:43 kostko Exp $) ** ** WARNING! All changes made in this file will be lost! ****************************************************************************/ #include "kftpfiltereditorlayout.h" #include #include #include //Added by qt3to4: #include #include #include #include #include #include #include #include #include #include /* * Constructs a KFTPFilterEditorLayout as a child of 'parent', with the * name 'name' and widget flags set to 'f'. */ KFTPFilterEditorLayout::KFTPFilterEditorLayout( QWidget* parent, const char* name, Qt::WFlags fl ) : QWidget( parent, name, fl ) { if ( !name ) setName( "KFTPFilterEditorLayout" ); KFTPFilterEditorLayoutLayout = new Q3GridLayout( this, 1, 1, 11, 6, "KFTPFilterEditorLayoutLayout"); tabWidget2 = new QTabWidget( this, "tabWidget2" ); tab = new QWidget( tabWidget2, "tab" ); tabLayout = new Q3GridLayout( tab, 1, 1, 11, 6, "tabLayout"); layout1 = new Q3VBoxLayout( 0, 0, 6, "layout1"); addPatternButton = new KPushButton( tab, "addPatternButton" ); layout1->addWidget( addPatternButton ); editPatternButton = new KPushButton( tab, "editPatternButton" ); layout1->addWidget( editPatternButton ); removePatternButton = new KPushButton( tab, "removePatternButton" ); layout1->addWidget( removePatternButton ); tabLayout->addLayout( layout1, 0, 1 ); QSpacerItem* spacer = new QSpacerItem( 31, 111, QSizePolicy::Minimum, QSizePolicy::Expanding ); tabLayout->addItem( spacer, 1, 1 ); layout2 = new Q3VBoxLayout( 0, 0, 6, "layout2"); patternList = new K3ListView( tab, "patternList" ); patternList->addColumn( tr2i18n( "Pattern" ) ); patternList->addColumn( tr2i18n( "Color" ) ); layout2->addWidget( patternList ); enabledCheck = new QCheckBox( tab, "enabledCheck" ); layout2->addWidget( enabledCheck ); tabLayout->addMultiCellLayout( layout2, 0, 1, 0, 0 ); tabWidget2->insertTab( tab, QString("") ); tab_2 = new QWidget( tabWidget2, "tab_2" ); textLabel1 = new QLabel( tab_2, "textLabel1" ); textLabel1->setGeometry( QRect( 10, 10, 130, 20 ) ); tabWidget2->insertTab( tab_2, QString("") ); tab_3 = new QWidget( tabWidget2, "tab_3" ); textLabel1_2 = new QLabel( tab_3, "textLabel1_2" ); textLabel1_2->setGeometry( QRect( 10, 10, 130, 20 ) ); tabWidget2->insertTab( tab_3, QString("") ); KFTPFilterEditorLayoutLayout->addWidget( tabWidget2, 0, 0 ); languageChange(); resize( QSize(456, 299).expandedTo(minimumSizeHint()) ); clearWState( WState_Polished ); } /* * Destroys the object and frees any allocated resources */ KFTPFilterEditorLayout::~KFTPFilterEditorLayout() { // no need to delete child widgets, Qt does it all for us } /* * Sets the strings of the subwidgets using the current * language. */ void KFTPFilterEditorLayout::languageChange() { setCaption( tr2i18n( "Form1" ) ); addPatternButton->setText( tr2i18n( "Add pattern" ) ); editPatternButton->setText( tr2i18n( "Edit" ) ); removePatternButton->setText( tr2i18n( "Remove" ) ); patternList->header()->setLabel( 0, tr2i18n( "Pattern" ) ); patternList->header()->setLabel( 1, tr2i18n( "Color" ) ); enabledCheck->setText( tr2i18n( "Enabled" ) ); tabWidget2->changeTab( tab, tr2i18n( "Highlighting" ) ); textLabel1->setText( tr2i18n( "Not yet implemented." ) ); tabWidget2->changeTab( tab_2, tr2i18n( "Skip List" ) ); textLabel1_2->setText( tr2i18n( "Not yet implemented." ) ); tabWidget2->changeTab( tab_3, tr2i18n( "ASCII extensions" ) ); } #include "kftpfiltereditorlayout.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/CMakeLists.txt0000644000175000017500000000164511276037142022406 0ustar michaelmichaelADD_SUBDIRECTORY( queueview ) ADD_SUBDIRECTORY( browser ) ADD_SUBDIRECTORY( bookmarks ) ADD_SUBDIRECTORY( failedtransfers ) INCLUDE_DIRECTORIES( .. ../misc ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(widgets_SRCS logview.cpp #kftpselectserverdialog.cpp #kftpselectserverdialog.h #kftpserverlineedit.cpp #kftpserverlineedit.h listview.cpp systemtray.cpp #searchdialog.cpp zeroconflistview.cpp trafficgraph.cpp listviewitem.cpp configdialog.cpp configfilter.cpp verifier.cpp filtereditor.cpp widgetlister.cpp overlaywidget.cpp popupmessage.cpp sslerrorsdialog.cpp fingerprintverifydialog.cpp ) SET(widgets_UI sslerrorsdialog.ui fingerprintverifydialog.ui ) kde4_add_ui_files(widgets_SRCS ${widgets_UI}) kde4_add_library(widgets STATIC ${widgets_SRCS}) add_dependencies(widgets misc engine ui) kftpgrabber-0.8.99~svn1214766/src/widgets/configdialog.cpp0000644000175000017500000001230511276037142022772 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "configdialog.h" #include "misc/config.h" #include "widgets/systemtray.h" #include #include #include #include #include #include #include #include #include #include #include #include // Config layouts #include "ui/ui_config_general.h" #include "ui/ui_config_transfers.h" #include "ui/ui_config_log.h" #include "ui/ui_config_display.h" #include "configfilter.h" namespace KFTPWidgets { template KPageWidgetItem *_addPage(KConfigDialog *dialog, const QString &itemName, const QString &pixmapName = QString()) { T ui; QWidget *page = new QWidget(); ui.setupUi(page); return dialog->addPage(page, itemName, pixmapName); } ConfigDialog::ConfigDialog(QWidget *parent, const QString &name) : KConfigDialog(parent, name, KFTPCore::Config::self()) { // Add all standard pages _addPage(this, "General", "preferences-other"); _addPage(this, "Transfers", "network-workgroup"); _addPage(this, "Log", "utilities-log-viewer"); _addPage(this, "Display", "preferences-desktop-theme"); // Add the actions page QFrame *aFrame = new QFrame(); QVBoxLayout *actionsLayout = new QVBoxLayout(aFrame); actionsLayout->setContentsMargins(0, 0, 0, 0); actionsLayout->addWidget(KFTPCore::Config::self()->dActions()->getConfigWidget(aFrame)); actionsLayout->addSpacing(KDialog::spacingHint()); actionsLayout->addWidget(KFTPCore::Config::self()->uActions()->getConfigWidget(aFrame)); actionsLayout->addSpacing(KDialog::spacingHint()); actionsLayout->addWidget(KFTPCore::Config::self()->fActions()->getConfigWidget(aFrame)); actionsLayout->addStretch(1); addPage(aFrame, i18n("Actions"), "system-run"); // Add the filter page m_configFilter = new ConfigFilter(this); addPage(m_configFilter, i18n("Filters"), "view-filter"); // Setup some stuff findChild("kcfg_defLocalDir")->setMode(KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly); // Let the config be up-to-date connect(this, SIGNAL(settingsChanged(const QString&)), KFTPCore::Config::self(), SLOT(emitChange())); connect(this, SIGNAL(okClicked()), this, SLOT(slotSettingsChanged())); } void ConfigDialog::prepareDialog() { // Update the actions KFTPCore::Config::self()->dActions()->updateWidget(); KFTPCore::Config::self()->uActions()->updateWidget(); KFTPCore::Config::self()->fActions()->updateWidget(); // Populate charsets KComboBox *encoding = findChild("cfg_defEncoding"); foreach (QString description, KGlobal::charsets()->descriptiveEncodingNames()) { encoding->addItem(description, KGlobal::charsets()->encodingForName(description)); } encoding->setCurrentIndex(encoding->findData(KFTPCore::Config::defEncoding())); m_configFilter->loadSettings(); } void ConfigDialog::slotSettingsChanged() { // Update the actions KFTPCore::Config::self()->dActions()->updateConfig(); KFTPCore::Config::self()->uActions()->updateConfig(); KFTPCore::Config::self()->fActions()->updateConfig(); m_configFilter->saveSettings(); // Save encoding KComboBox *encoding = findChild("cfg_defEncoding"); KFTPCore::Config::setDefEncoding(encoding->itemData(encoding->currentIndex()).toString()); // Show/hide the systray icon if (KFTPCore::Config::showSystrayIcon()) SystemTray::self()->show(); else SystemTray::self()->hide(); } } #include "configdialog.moc" kftpgrabber-0.8.99~svn1214766/src/widgets/widgetlister.cpp0000644000175000017500000001104411276037142023052 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "widgetlister.h" #include #include #include #include namespace KFTPWidgets { WidgetLister::WidgetLister(QWidget *parent, int minWidgets, int maxWidgets) : QWidget(parent) { m_minWidgets = qMax(minWidgets, 0); m_maxWidgets = qMax(maxWidgets, m_minWidgets + 1); // The button box m_layout = new QVBoxLayout(this); m_layout->setMargin(0); m_buttonBox = new KHBox(this); m_buttonBox->setSpacing(KDialog::spacingHint()); m_layout->addWidget(m_buttonBox); m_buttonMore = new KPushButton(KIcon("list-add"), i18n("More"), m_buttonBox); m_buttonBox->setStretchFactor(m_buttonMore, 0); m_buttonFewer = new KPushButton(KIcon("list-remove"), i18n("Fewer"), m_buttonBox); m_buttonBox->setStretchFactor(m_buttonFewer, 0); QWidget *spacer = new QWidget(m_buttonBox); m_buttonBox->setStretchFactor(spacer, 1); m_buttonClear = new KPushButton(KIcon("edit-clear"), i18n("Clear"), m_buttonBox); m_buttonBox->setStretchFactor(m_buttonClear, 0); // Connect signals connect(m_buttonMore, SIGNAL(clicked()), this, SLOT(slotMore())); connect(m_buttonFewer, SIGNAL(clicked()), this, SLOT(slotFewer())); connect(m_buttonClear, SIGNAL(clicked()), this, SLOT(slotClear())); enableControls(); } WidgetLister::~WidgetLister() { qDeleteAll(m_widgetList); } void WidgetLister::slotMore() { addWidget(); enableControls(); } void WidgetLister::slotFewer() { removeWidget(); enableControls(); } void WidgetLister::clear() { setNumberShown(m_minWidgets); // Clear remaining widgets foreach (QWidget *widget, m_widgetList) { clearWidget(widget); } enableControls(); emit clearWidgets(); } void WidgetLister::slotClear() { clear(); } void WidgetLister::addWidget(QWidget *widget) { if (!widget) widget = createWidget(this); m_layout->insertWidget(m_layout->indexOf(m_buttonBox), widget); m_widgetList.append(widget); widget->show(); enableControls(); emit widgetAdded(widget); } void WidgetLister::removeWidget() { QWidget *widget = m_widgetList.takeLast(); delete widget; enableControls(); emit widgetRemoved(); } void WidgetLister::clearWidget(QWidget *widget) { Q_UNUSED(widget) } QWidget *WidgetLister::createWidget(QWidget* parent) { return new QWidget(parent); } void WidgetLister::setNumberShown(int number) { int superfluousWidgets = qMax((int) m_widgetList.count() - number, 0); int missingWidgets = qMax(number - (int) m_widgetList.count(), 0); // Remove superfluous widgets for (; superfluousWidgets; superfluousWidgets--) removeWidget(); // Add missing widgets for (; missingWidgets; missingWidgets--) addWidget(); } void WidgetLister::enableControls() { int count = m_widgetList.count(); bool isMaxWidgets = (count >= m_maxWidgets); bool isMinWidgets = (count <= m_minWidgets); m_buttonMore->setEnabled(!isMaxWidgets); m_buttonFewer->setEnabled(!isMinWidgets); } } kftpgrabber-0.8.99~svn1214766/src/queuegroup.h0000644000175000017500000000603511276037142020550 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUEQUEUEGROUP_H #define KFTPQUEUEQUEUEGROUP_H #include #include namespace KFTPQueue { class QueueObject; class Transfer; /** * This class manages a group of child queue objects so they get * executed in the proper order. * * Note that all child transfers that are grouped together must be * part of the same session, otherwise unexpected behavior may * ocurr. * * @author Jernej Kos */ class QueueGroup : public QObject { Q_OBJECT public: /** * Class constructor. * * @param object The queue object to manage */ QueueGroup(QueueObject *object); /** * Reset the group. */ void reset(); /** * Execute the next transfer in list. * * @return 1 if the transfer has been executed, 0 or -1 otherwise */ int executeNextTransfer(); public slots: /** * Increment the current iterator and call executeNextTransfer method. */ void incrementAndExecute(); private: QueueObject *m_object; QListIterator m_childIterator; QPointer m_lastTransfer; bool m_directories; signals: /** * This signal gets emitted when there is nothing more to do in the * queue. */ void done(); /** * This signal gets emitted when the group processing is interrupted * due to abort. */ void interrupted(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/misc/0000755000175000017500000000000011276037142017125 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/misc/filterwidgethandler.h0000644000175000017500000002261311276037142023331 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCORE_FILTERFILTERWIDGETHANDLER_H #define KFTPCORE_FILTERFILTERWIDGETHANDLER_H #include "filter.h" #include #include namespace KFTPCore { namespace Filter { class WidgetHandlerManagerPrivate; /** * This is an interface that any condition widget handlers must implement * in order to be registred with the manager. The handler handles several * widgets at once so it should not keep any member variables. * * @author Jernej Kos */ class ConditionWidgetHandler { public: /** * Class destructor. */ virtual ~ConditionWidgetHandler() {} /** * This method has to return a new widget used for displaying condition * types. It is usually a combobox with several options. The returned * widget is added to the value widget stack. * * @param parent Widget to be used as parent for the newly created widget * @param receiver Object that receives type change notifications * @return A valid QWidget instance */ virtual QWidget *createTypeWidget(QWidget *parent, const QObject *receiver) const = 0; /** * This method has to create one or several input widgets for different * condition types. Each widget has to be added to the widget stack. An * identifying widget name is recommended for each widget, so you can easily * access it from other methods which get the value stack widget passed as * an argument. * * @param stack Value widget stack * @param receiver Object that receives value change notifications */ virtual void createValueWidgets(QStackedWidget *stack, const QObject *receiver) const = 0; /** * Update the status of all widgets. * * @param field The field to display * @param types Type widget stack to use * @param values Value widget stack to use */ virtual void update(int field, QStackedWidget *types, QStackedWidget *values) const = 0; /** * Extract data from internal condition representation and show it to the * user using the created widgets. * * @param types Type widget stack to use * @param values Value widget stack to use * @param condition The condition representation */ virtual void setCondition(QStackedWidget *types, QStackedWidget *values, const Condition *condition) = 0; /** * This method should return the currently selected condition type. * * @param widget The type widget previously created * @return A valid Condition::Type */ virtual Condition::Type getConditionType(QWidget *widget) const = 0; /** * This method should return the current condition value. * * @param values Value widget stack to use * @return A valid condition value */ virtual QVariant getConditionValue(QStackedWidget *values) const = 0; }; /** * This is an interface that any action widget handlers must implement * in order to be registred with the manager. The handler handles several * widgets at once so it should not keep any member variables. * * @author Jernej Kos */ class ActionWidgetHandler { public: /** * Class destructor. */ virtual ~ActionWidgetHandler() {} /** * This method has to return a new widget used for displaying the action * value. It is usually a line edit or a similar input widget. The returned * widget is added to the value widget stack. * * @param parent Widget to be used as parent for the newly created widget * @param receiver Object that receives type change notifications * @return A valid QWidget instance */ virtual QWidget *createWidget(QWidget *parent, const QObject *receiver) const = 0; /** * Extract data from internal action representation and show it to the * user using the created widgets. * * @param stack Value widget stack to use * @param action The action representation */ virtual void setAction(QStackedWidget *stack, const Action *action) const = 0; /** * This method should return the current action value. * * @param values Value widget stack to use * @return A valid action value */ virtual QVariant getActionValue(QWidget *widget) const = 0; }; /** * This class keeps a list of all registred condition and action widget * handlers. It is a singleton. * * @author Jernej Kos */ class WidgetHandlerManager { friend class WidgetHandlerManagerPrivate; public: /** * Get the global class instance. */ static WidgetHandlerManager *self(); /** * Create widgets for all currently registred condition handlers. * * @param types Type widget stack to use * @param value Value widget stack to use * @param receiver Object that receives change notifications */ void createConditionWidgets(QStackedWidget *types, QStackedWidget *values, const QObject *receiver); /** * Create widgets for all currently registred action handlers. * * @param stack Value widget stack to use * @param receiver Object that receives change notifications */ void createActionWidgets(QStackedWidget *stack, const QObject *receiver); /** * Update the specified condition widget handler. * * @param field New condition field * @param types Type widget stack to use * @param values Value widget stack to use */ void update(Field field, QStackedWidget *types, QStackedWidget *values); /** * Extract data from internal condition representation and show it to the * user using the created widgets. * * @param types Type widget stack to use * @param values Value widget stack to use * @param condition The condition representation */ void setCondition(QStackedWidget *types, QStackedWidget *values, const Condition *condition); /** * Get the currently selected condition type. * * @param field Condition field * @param types Type widget stack to use * @return A valid Condition::Type */ Condition::Type getConditionType(Field field, QStackedWidget *types); /** * Get the current condition value. * * @param field Condition field * @param values Value widget stack to use * @return A valid condition value */ QVariant getConditionValue(Field field, QStackedWidget *values); /** * Extract data from internal action representation and show it to the * user using the created widgets. * * @param stack Value widget stack to use * @param action The action representation */ void setAction(QStackedWidget *stack, const Action *action); /** * Get the current action value. * * @param stack Value widget stack to use * @return A valid action value */ QVariant getActionValue(QStackedWidget *stack); /** * Register a new condition handler with the manager. * * @param field Field that this handler handles * @param handler The actual handler instance */ void registerConditionHandler(Field field, ConditionWidgetHandler *handler); /** * Register a new action handler with the manager. * * @param type Action type that this handler handles * @param handler The actual handler instance */ void registerActionHandler(Action::Type type, ActionWidgetHandler *handler); protected: /** * Class constructor. */ WidgetHandlerManager(); /** * Class destructor. */ ~WidgetHandlerManager(); private: typedef QMap ConditionHandlerMap; ConditionHandlerMap m_conditionHandlers; typedef QMap ActionHandlerMap; ActionHandlerMap m_actionHandlers; }; } } #endif kftpgrabber-0.8.99~svn1214766/src/misc/pluginmanager.h0000644000175000017500000000551611276037142022136 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef PLUGINMANAGER_H #define PLUGINMANAGER_H #include #include class KFTPBookmarkImportPlugin; namespace KFTPCore { class PluginManagerPrivate; /** * This class is responsible for loading all the KFTPGrabber plugins and * their communication with the rest of the application. * * @author Jernej Kos */ class PluginManager : public QObject { friend class PluginManagerPrivate; public: /** * Returns the global plugin manager instance. */ static PluginManager *self(); /** * This method will load all the plugins. */ void loadPlugins(); /** * Load bookmark import plugin. * * @param service The plugin KService::Ptr * @return The loaded plugin or NULL if plugin can't be loaded */ KFTPBookmarkImportPlugin *loadImportPlugin(const KService::Ptr &service); /** * Returns the list of all currently loaded import plugins. * * @return List of all laoded import plugins */ KService::List getImportPlugins(); private: /** * Class constructor. */ PluginManager(); /** * Class destructor. */ ~PluginManager(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/misc/filter.h0000644000175000017500000003204011276037142020562 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCORE_FILTERFILTERS_H #define KFTPCORE_FILTERFILTERS_H #include #include #include #include "engine/directorylisting.h" namespace KFTPCore { namespace Filter { /** * Possible filter fields. */ enum Field { Filename = 0, EntryType = 1, Size = 2 }; /** * A filter condition class of different types. * * @author Jernej Kos */ class Condition { public: /** * Condition type. * * The following types are valid: * - None: this rule never validates * - Contains: field contains a given substring * - ContainsNot: field does not contain a given substring * - Is: field is equal to the given value * - IsNot: field is not equal to the given value * - Matches: field matches a given regular expression * - MatchesNot: field doesn't match a given regular expression * - Greater: field's integer value is greater than the given value * - Smaller: field's integer value is smaller than the given value */ enum Type { None = -1, Contains = 0, ContainsNot = 1, Is = 2, IsNot = 3, Matches = 4, MatchesNot = 5, Greater = 6, Smaller = 7 }; /** * Class constructor. The constructed condition is invalid. */ Condition() {} /** * Class constructor. * * @param field Field to check * @param type Condition type * @param value Value to check against */ Condition(Field field, Type type, const QVariant &value); /** * Returns the field this condition operates on. */ Field field() const { return m_field; } /** * Set condition field. * * @param field A valid condition field */ void setField(Field field) { m_field = field; } /** * Returns the type of this condition. */ Type type() const { return m_type; } /** * Set condition type. * * @param type A valid condition type */ void setType(Type type) { m_type = type; } /** * Returns the value this condition validates the field with. */ QVariant value() const { return m_value; } /** * Set condition validation value. * * @param value A valid validation value */ void setValue(const QVariant &value) { m_value = value; } /** * Does the specified entry match this condition ? * * @param entry Directory entry to compare * @return True if the entry matches this condition, false otherwise */ bool matches(const KFTPEngine::DirectoryEntry &entry) const; private: Field m_field; Type m_type; QVariant m_value; }; /** * This class represents a chain of filter conditions. * * @author Jernej Kos */ class ConditionChain : public QList { public: /** * Chain type. * * The following types are valid: * - All: all conditions must match * - Any: any condition can match */ enum Type { All = 0, Any = 1 }; /** * Class constructor. */ ConditionChain(); /** * Class constructor. */ ConditionChain(Type type); /** * Class destructor. */ ~ConditionChain(); /** * Returns condition chain match type. */ Type type() const { return m_type; } /** * Set condition chain match type. * * @param type A valid type */ void setType(Type type) { m_type = type; } /** * Does the specified entry match this condition chain ? The actual * matching depends on chain type. * * @param entry Directory entry to compare * @return True if the entry matches this chain, false otherwise */ bool matches(const KFTPEngine::DirectoryEntry &entry) const; private: Type m_type; }; /** * This class represents a single action to take. */ class Action { public: /** * Action type. * * These are the valid types: * - Priority: when queuing files, their priority should be changed * - Skip: do not queue such files * - Colorize: change font color in the list view * - Hide: do not display such files in the list view * - Lowercase: lowercase the destination filename when queuing */ enum Type { None = 0, Priority = 1, Skip = 2, Colorize = 3, Hide = 4, Lowercase = 5 }; /** * Class constructor. The resulting action is invalid. */ Action(); /** * Class constructor. * * @param type Action type * @param value Action parameters */ Action(Type type, const QVariant &value); /** * Returns true if the action is valid. */ bool isValid() const { return m_valid; } /** * Get action's type. */ Type type() const { return m_type; } /** * Set the action type. * * @param type A valid action type */ void setType(Type type) { m_type = type; } /** * Get action's parameters. */ QVariant value() const { return m_value; } /** * Set action parameter. * * @param value Parameter value */ void setValue(const QVariant &value) { m_value = value; } private: bool m_valid; Type m_type; QVariant m_value; }; /** * This class represents a chain of filter actions. * * @author Jernej Kos */ class ActionChain : public QList { public: /** * Class constructor. */ ActionChain(); /** * Class destructor. */ ~ActionChain(); /** * Get an action of the specified type. * * @param type Action type to search for * @return A valid Action or null if there is none */ const Action *getAction(Action::Type type) const; }; /** * This class represents a single filter rule consiting of a condition chain * and an action chain. * * @author Jernej Kos */ class Rule { public: /** * Class constructor. */ Rule(); /** * Class copy constructor. Creates a duplicate deep copy of the provided * rule. * * @param rule The rule to copy */ Rule(const Rule *rule); /** * Class constructor. * * @param name Human readable rule name */ Rule(const QString &name); /** * Get rule's name. */ QString name() const { return m_name; } /** * Set rule's name. */ void setName(const QString &name) { m_name = name; } /** * Is this rule enabled or not ? * * @return True if the rule is enabled, false otherwise */ bool isEnabled() const { return m_enabled; } /** * Enable or disable this rule. * * @param value True if the rule is enabled, false otherwise */ void setEnabled(bool value) { m_enabled = value; } /** * Get the condition chain reference. */ const ConditionChain *conditions() const { return &m_conditionChain; } /** * Get the action chain reference. */ const ActionChain *actions() const { return &m_actionChain; } private: QString m_name; bool m_enabled; ConditionChain m_conditionChain; ActionChain m_actionChain; }; /** * This class contains all the currently loaded rules. * * @author Jernej Kos */ class Filters : public QList { public: /** * Get the global rule chain. */ static Filters *self(); /** * Class destructor. */ ~Filters(); /** * Load the rules from a file. */ void load(); /** * Serialize the rules and save them to a file. */ void save(); /** * Destroys the global Filters instance. Do not call self() after calling * this method otherwise the filters will be reinitialized! */ void close(); /** * Is filtering enabled or not ? * * @return True if filtering is enabled, false otherwise */ bool isEnabled() const { return m_enabled; } /** * Enable or disable filtering. * * @param value True if filtering is enabled, false otherwise */ void setEnabled(bool value) { m_enabled = value; } /** * Process the specified entry and return an action chain that matched * first. * * @param entry The entry to process * @return An ActionChain reference (might be empty if nothing matched) */ const ActionChain *process(const KFTPEngine::DirectoryEntry &entry) const; /** * Process the specified entry and return an action to use. This will * go trough all loaded rules and attempt to process each one by one. * The first one that succeeds is returned. * * @param entry The entry to process * @param types Only return the action of this type * @return An Action reference (might be invalid if nothing matched) */ const Action *process(const KFTPEngine::DirectoryEntry &entry, QList types) const; /** * Process the specified entry and return an action to use. This will * go trough all loaded rules and attempt to process each one by one. * The first one that succeeds is returned. * * @param entry The entry to process * @param filter Only return the action of this type * @return An Action reference (might be invalid if nothing matched) */ const Action *process(const KFTPEngine::DirectoryEntry &entry, Action::Type filter) const; /** * This method is provided for convienience. It behaves just like the * above method. * * @param url File's URL * @param size File's size * @param directory True if the entry is a directory * @param filter Only return the action of this type * @return An Action reference (might be invalid if nothing matched) */ const Action *process(const KUrl &url, filesize_t size, bool directory, Action::Type filter) const; /** * Process the specified entry and return an action chain that matched * first. * * @param url File's URL * @param size File's size * @param directory True if the entry is a directory * @return An ActionChain reference (might be invalid if nothing matched) */ const ActionChain *process(const KUrl &url, filesize_t size, bool directory) const; /** * This method is provided for convienience. It behaves just like the * above method. * * Note that 0 will be used for filesize and this may affect the filter * process! * * @param url File's URL * @param filter Only return the action of this type * @return An Action reference (might be invalid if nothing matched) */ const Action *process(const KUrl &url, Action::Type filter) const; /** * Get a human readable list of possible field names. * * @return A QStringList representing the field names */ const QStringList &getFieldNames() { return m_fieldNames; } /** * Get a human readable list of possible action names * * @return A QStringList representing the action names */ const QStringList &getActionNames() { return m_actionNames; } protected: /** * Class constructor. */ Filters(); private: static Filters *m_self; bool m_enabled; ActionChain m_emptyActionChain; QStringList m_fieldNames; QStringList m_actionNames; }; } } Q_DECLARE_METATYPE(KFTPCore::Filter::Rule*) #endif kftpgrabber-0.8.99~svn1214766/src/misc/kftpgrabber.kcfg0000644000175000017500000002366611276037142022267 0ustar michaelmichael qsize.h qpoint.h qdir.h kglobalsettings.h configbase.h QSize(800, 500) QPoint(0, 0) 10 0 60 0 true false true true false QDir::homePath() false false true true false true iso 8859-1 4;4;4;4;4;4;4;4;4; 4;4;4;4;4;4;4;4;4; 4;4;4;4;4;4;4;4;4; .txt,.bat,.php,.asp,.htm,.html,.css,.cpp,.h,.hpp,.js,.inc,.nfo,.pl,.sh,.xml,.sql false QColor(67, 170, 23) QColor(0, 0, 255) QColor(148, 188, 22) QColor(255, 0, 0) QColor(0, 0, 0) false false 0 0 65536 65536 0 65536 false true false false 60 30 500 0 true getGlobalMail() 1 1 10 true 60 10 60 10 300 0 0 false 1 1 20 true true false false false false kftpgrabber-0.8.99~svn1214766/src/misc/filter.cpp0000644000175000017500000002654211276037142021127 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "filter.h" #include #include #include #include #include #include namespace KFTPCore { namespace Filter { Condition::Condition(Field field, Type type, const QVariant &value) : m_field(field), m_type(type), m_value(value) { } bool Condition::matches(const KFTPEngine::DirectoryEntry &entry) const { bool result = false; QString check; switch (m_field) { default: case Filename: check = entry.filename(); break; case EntryType: check = entry.type(); break; case Size: check = QString::number(entry.size()); break; } switch (m_type) { case None: result = false; break; case Contains: result = (check.contains(m_value.toString()) > 0); break; case ContainsNot: result = (check.contains(m_value.toString()) == 0); break; case Is: result = (check == m_value.toString()); break; case IsNot: result = (check != m_value.toString()); break; case Matches: { QRegExp r(m_value.toString()); result = (r.indexIn(check) > -1); break; } case MatchesNot: { QRegExp r(m_value.toString()); result = (r.indexIn(check) == -1); break; } case Greater: result = (check.toULongLong() > m_value.toULongLong()); break; case Smaller: result = (check.toULongLong() < m_value.toULongLong()); break; } return result; } ConditionChain::ConditionChain() : QList(), m_type(All) { } ConditionChain::ConditionChain(Type type) : QList(), m_type(type) { } ConditionChain::~ConditionChain() { qDeleteAll(*this); } bool ConditionChain::matches(const KFTPEngine::DirectoryEntry &entry) const { if (isEmpty()) return false; ConditionChain::ConstIterator le = end(); for (ConditionChain::ConstIterator i = begin(); i != le; ++i) { bool match = (*i)->matches(entry); if (match && m_type == Any) return true; else if (!match && m_type == All) return false; } if (m_type == Any) return false; return true; } Action::Action() : m_valid(false) { } Action::Action(Type type, const QVariant &value) : m_valid(true), m_type(type), m_value(value) { } ActionChain::ActionChain() : QList() { } ActionChain::~ActionChain() { qDeleteAll(*this); } const Action *ActionChain::getAction(Action::Type type) const { ActionChain::ConstIterator le = end(); for (ActionChain::ConstIterator i = begin(); i != le; ++i) if ((*i)->type() == type) return (*i); return 0; } Rule::Rule() : m_name(QString::null), m_enabled(false) { } Rule::Rule(const Rule *rule) : m_name(rule->name()), m_enabled(rule->isEnabled()) { // Copy conditions const ConditionChain *conditionList = rule->conditions(); m_conditionChain.setType(conditionList->type()); ConditionChain::ConstIterator cle = conditionList->end(); for (ConditionChain::ConstIterator i = conditionList->begin(); i != cle; ++i) { const Condition *c = (*i); m_conditionChain.append(new Condition(c->field(), c->type(), c->value())); } // Copy actions const ActionChain *actionList = rule->actions(); ActionChain::ConstIterator ale = actionList->end(); for (ActionChain::ConstIterator i = actionList->begin(); i != ale; ++i) { const Action *a = (*i); m_actionChain.append(new Action(a->type(), a->value())); } } Rule::Rule(const QString &name) : m_name(name), m_enabled(true) { // Add a simple condition and a simple action m_conditionChain.append(new Condition(Filename, Condition::Contains, QVariant(""))); m_actionChain.append(new Action(Action::None, QVariant())); } Filters *Filters::m_self = 0; Filters *Filters::self() { if (!m_self) m_self = new Filters(); return m_self; } Filters::Filters() : QList(), m_enabled(true) { // Generate human readable strings m_fieldNames << i18n("Filename"); m_fieldNames << i18n("Entry Type"); m_fieldNames << i18n("Size"); m_actionNames << " "; m_actionNames << i18n("Change priority"); m_actionNames << i18n("Skip when queuing"); m_actionNames << i18n("Colorize in list view"); m_actionNames << i18n("Hide from list view"); m_actionNames << i18n("Lowercase destination"); // Load the filters load(); } Filters::~Filters() { qDeleteAll(*this); } void Filters::close() { m_self = 0; delete this; } void Filters::save() { int num = 0; KSharedConfigPtr config = KGlobal::config(); KConfigGroup group = config->group("Filters"); group.writeEntry("count", count()); // Remove any existing sections for (int i = 0; ; i++) { QString groupName = QString("Filter #%1").arg(i); if (config->hasGroup(groupName)) config->deleteGroup(groupName); else break; } Filters::ConstIterator le = constEnd(); for (Filters::ConstIterator i = constBegin(); i != le; ++i, num++) { const Rule *rule = (*i); group.changeGroup(QString("Filter #%1").arg(num)); group.writeEntry("name", rule->name()); group.writeEntry("enabled", rule->isEnabled()); // Write conditions int cnum = 0; const ConditionChain *conditions = rule->conditions(); group.writeEntry("conditions", conditions->count()); group.writeEntry("conditions-type", (int) conditions->type()); ConditionChain::ConstIterator cle = conditions->end(); for (ConditionChain::ConstIterator j = conditions->begin(); j != cle; ++j, cnum++) { const Condition *c = (*j); QString prefix = QString("condition%1-").arg(cnum); group.writeEntry(prefix + "field", (int) c->field()); group.writeEntry(prefix + "type", (int) c->type()); group.writeEntry(prefix + "value", c->value()); group.writeEntry(prefix + "valueType", (int) c->value().type()); } // Write actions int anum = 0; const ActionChain *actions = rule->actions(); group.writeEntry("actions", actions->count()); ActionChain::ConstIterator ale = actions->end(); for (ActionChain::ConstIterator j = actions->begin(); j != ale; ++j, anum++) { const Action *a = (*j); QString prefix = QString("action%1-").arg(anum); group.writeEntry(prefix + "type", (int) a->type()); group.writeEntry(prefix + "value", a->value()); } } } void Filters::load() { int num = 0; KSharedConfigPtr config = KGlobal::config(); KConfigGroup group = config->group("Filters"); num = group.readEntry("count", 0); for (int i = 0; i < num; i++) { Rule *rule = new Rule(); group.changeGroup(QString("Filter #%1").arg(i)); rule->setName(group.readEntry("name", i18n("Unnamed Rule"))); rule->setEnabled(group.readEntry("enabled", true)); // Read conditions ConditionChain *conditions = const_cast(rule->conditions()); int cnum = group.readEntry("conditions", 0); conditions->setType((ConditionChain::Type) group.readEntry("conditions-type", 0)); for (int j = 0; j < cnum; j++) { QString prefix = QString("condition%1-").arg(j); conditions->append(new Condition((Field) group.readEntry(prefix + "field", 0), (Condition::Type) group.readEntry(prefix + "type", 0), group.readEntry(prefix + "value", QVariant((QVariant::Type) group.readEntry(prefix + "valueType", 0))))); } // Read actions ActionChain *actions = const_cast(rule->actions()); int anum = group.readEntry("actions", 0); for (int j = 0; j < anum; j++) { QString prefix = QString("action%1-").arg(j); actions->append(new Action((Action::Type) group.readEntry(prefix + "type", 0), group.readEntry(prefix + "value", QVariant()))); } append(rule); } } const ActionChain *Filters::process(const KFTPEngine::DirectoryEntry &entry) const { if (m_enabled) { Filters::ConstIterator le = end(); for (Filters::ConstIterator i = begin(); i != le; ++i) { const Rule *rule = (*i); if (rule->isEnabled() && rule->conditions()->matches(entry)) return rule->actions(); } } // Nothing has matched return 0; } const Action *Filters::process(const KFTPEngine::DirectoryEntry &entry, QList types) const { const ActionChain *chain = process(entry); if (!chain || chain->isEmpty()) return 0; // Find an action that matches the filter ActionChain::ConstIterator le = chain->end(); for (ActionChain::ConstIterator i = chain->begin(); i != le; ++i) { if (types.contains((*i)->type())) return (*i); } return 0; } const Action *Filters::process(const KFTPEngine::DirectoryEntry &entry, Action::Type filter) const { const ActionChain *chain = process(entry); if (!chain || chain->isEmpty()) return 0; // Find an action that matches the filter ActionChain::ConstIterator le = chain->end(); for (ActionChain::ConstIterator i = chain->begin(); i != le; ++i) { if ((*i)->type() == filter) return (*i); } return 0; } const Action *Filters::process(const KUrl &url, filesize_t size, bool directory, Action::Type filter) const { KFTPEngine::DirectoryEntry entry; entry.setFilename(url.fileName()); entry.setSize(size); entry.setType(directory ? 'd' : 'f'); return process(entry, filter); } const ActionChain *Filters::process(const KUrl &url, filesize_t size, bool directory) const { KFTPEngine::DirectoryEntry entry; entry.setFilename(url.fileName()); entry.setSize(size); entry.setType(directory ? 'd' : 'f'); return process(entry); } const Action *Filters::process(const KUrl &url, Action::Type filter) const { return process(url, 0, false, filter); } } } kftpgrabber-0.8.99~svn1214766/src/misc/certificatestore.h0000644000175000017500000000604711276037142022644 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCORECERTIFICATESTORE_H #define KFTPCORECERTIFICATESTORE_H #include #include #include #include #include namespace KFTPCore { /** * A global store for trusted SSL certificates and SSH fingerprints. * * @author Jernej Kos */ class CertificateStore { public: /** * Class constructor. */ CertificateStore(); /** * Copy constructor. */ CertificateStore(const CertificateStore &store); /** * Adds a certificate to the certificate store. */ void addCertificate(const QSslCertificate &certificate); /** * Adds a fingerprint to the store. */ void addFingerprint(const KUrl &url, const QByteArray &fingerprint); /** * Returns true if the fingerprint is authentic, false otherwise. */ bool verifyFingerprint(const KUrl &url, const QByteArray &fingerprint) const; /** * Returns a list of trusted certificates currently in the certificate * store. */ QList trustedCertificates() const; /** * Saves the certificate store to disk in PEM format. */ void save(); protected: /** * Normalizes an URL. */ KUrl normalizeUrl(const KUrl &url) const; private: QList m_store; QMap m_fingerprints; }; } #endif kftpgrabber-0.8.99~svn1214766/src/misc/certificatestore.cpp0000644000175000017500000000700411276037142023171 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "certificatestore.h" #include #include #include namespace KFTPCore { CertificateStore::CertificateStore() { // Load certificates m_store = QSslCertificate::fromPath(KStandardDirs::locateLocal("appdata", "certstore")); // Load fingerprints QFile file(KStandardDirs::locateLocal("appdata", "fpstore")); if (file.open(QIODevice::ReadOnly)) { QDataStream stream(&file); stream >> m_fingerprints; file.close(); } } CertificateStore::CertificateStore(const CertificateStore &store) { m_store = store.m_store; } void CertificateStore::addCertificate(const QSslCertificate &certificate) { if (!m_store.contains(certificate)) m_store.append(certificate); } void CertificateStore::addFingerprint(const KUrl &url, const QByteArray &fingerprint) { m_fingerprints[normalizeUrl(url)] = fingerprint; } bool CertificateStore::verifyFingerprint(const KUrl &url, const QByteArray &fingerprint) const { return m_fingerprints[normalizeUrl(url)] == fingerprint; } QList CertificateStore::trustedCertificates() const { return m_store; } KUrl CertificateStore::normalizeUrl(const KUrl &url) const { KUrl normalizedUrl = url; normalizedUrl.setPath("/"); normalizedUrl.setUser(""); normalizedUrl.setPass(""); return normalizedUrl; } void CertificateStore::save() { // Save certificates QFile file(KStandardDirs::locateLocal("appdata", "certstore")); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) return; foreach (QSslCertificate certificate, m_store) { file.write(certificate.toPem()); } file.close(); // Save fingerprints file.setFileName(KStandardDirs::locateLocal("appdata", "fpstore")); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) return; QDataStream stream(&file); stream << m_fingerprints; file.close(); } } kftpgrabber-0.8.99~svn1214766/src/misc/filterwidgethandler.cpp0000644000175000017500000004101711276037142023663 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "filterwidgethandler.h" #include #include #include #include #include #include #include namespace KFTPCore { namespace Filter { namespace { static const struct { const Condition::Type type; const char *name; } TextTypes[] = { { Condition::Contains, I18N_NOOP("contains") }, { Condition::ContainsNot, I18N_NOOP("does not contain") }, { Condition::Is, I18N_NOOP("equals") }, { Condition::IsNot, I18N_NOOP("does not equal") }, { Condition::Matches, I18N_NOOP("matches regexp") }, { Condition::MatchesNot, I18N_NOOP("does not match regexp") } }; static const int TextTypeCount = sizeof(TextTypes) / sizeof(*TextTypes); class TextWidgetHandler : public ConditionWidgetHandler { public: TextWidgetHandler() : ConditionWidgetHandler() { } QWidget *createTypeWidget(QWidget *parent, const QObject *receiver) const { QComboBox *combo = new QComboBox(parent); for (int i = 0; i < TextTypeCount; i++) { combo->insertItem(i, i18n(TextTypes[i].name)); } combo->adjustSize(); // Connect the signal QObject::connect(combo, SIGNAL(activated(int)), receiver, SLOT(slotTypeChanged())); return combo; } Condition::Type getConditionType(QWidget *widget) const { QComboBox *combo = static_cast(widget); return TextTypes[combo->currentIndex()].type; } void createValueWidgets(QStackedWidget *stack, const QObject *receiver) const { KLineEdit *lineEdit = new KLineEdit(stack); lineEdit->setObjectName("textWidgetHandler_LineEdit"); QObject::connect(lineEdit, SIGNAL(textChanged(const QString&)), receiver, SLOT(slotValueChanged())); stack->addWidget(lineEdit); } QVariant getConditionValue(QStackedWidget *values) const { KLineEdit *lineEdit = values->findChild("textWidgetHandler_LineEdit"); return QVariant(lineEdit->text()); } void update(int field, QStackedWidget *types, QStackedWidget *values) const { types->setCurrentIndex(field); values->setCurrentWidget(values->findChild("textWidgetHandler_LineEdit")); } void setCondition(QStackedWidget *types, QStackedWidget *values, const Condition *condition) { // Set condition type const Condition::Type type = condition->type(); int typeIndex = 0; for (; typeIndex < TextTypeCount; typeIndex++) if (type == TextTypes[typeIndex].type) break; QComboBox *combo = static_cast(types->widget(((int) condition->field()))); combo->blockSignals(true); combo->setCurrentIndex(typeIndex); combo->blockSignals(false); types->setCurrentWidget(combo); // Set condition value KLineEdit *lineEdit = values->findChild("textWidgetHandler_LineEdit"); lineEdit->blockSignals(true); lineEdit->setText(condition->value().toString()); lineEdit->blockSignals(false); values->setCurrentWidget(lineEdit); } }; } namespace { static const struct { const Condition::Type type; const char *name; } EntryTypes[] = { { Condition::Is, I18N_NOOP("is") }, { Condition::IsNot, I18N_NOOP("is not") } }; static const int EntryTypeCount = sizeof(EntryTypes) / sizeof(*EntryTypes); class EntryWidgetHandler : public ConditionWidgetHandler { public: EntryWidgetHandler() : ConditionWidgetHandler() { } QWidget *createTypeWidget(QWidget *parent, const QObject *receiver) const { QComboBox *combo = new QComboBox(parent); for (int i = 0; i < EntryTypeCount; i++) { combo->addItem(i18n(EntryTypes[i].name)); } combo->adjustSize(); // Connect the signal QObject::connect(combo, SIGNAL(activated(int)), receiver, SLOT(slotTypeChanged())); return combo; } Condition::Type getConditionType(QWidget *widget) const { QComboBox *combo = static_cast(widget); return EntryTypes[combo->currentIndex()].type; } void createValueWidgets(QStackedWidget *stack, const QObject *receiver) const { QComboBox *combo = new QComboBox(stack); combo->setObjectName("entryWidgetHandler_Combo"); combo->insertItem(0, i18n("File")); combo->insertItem(1, i18n("Directory")); QObject::connect(combo, SIGNAL(activated(int)), receiver, SLOT(slotValueChanged())); stack->addWidget(combo); } QVariant getConditionValue(QStackedWidget *values) const { QComboBox *combo = values->findChild("entryWidgetHandler_Combo"); QVariant value; if (combo->currentIndex() == 0) value = QVariant(QString("f")); else value = QVariant(QString("d")); return value; } void update(int field, QStackedWidget *types, QStackedWidget *values) const { types->setCurrentIndex(field); values->setCurrentWidget(values->findChild("entryWidgetHandler_Combo")); } void setCondition(QStackedWidget *types, QStackedWidget *values, const Condition *condition) { // Set condition type const Condition::Type type = condition->type(); int typeIndex = 0; for (; typeIndex < EntryTypeCount; typeIndex++) if (type == EntryTypes[typeIndex].type) break; QComboBox *combo = static_cast(types->widget(((int) condition->field()))); combo->blockSignals(true); combo->setCurrentIndex(typeIndex); combo->blockSignals(false); types->setCurrentWidget(combo); // Set condition value combo = values->findChild("entryWidgetHandler_Combo"); combo->blockSignals(true); combo->setCurrentIndex(condition->value().toString() == "f" ? 0 : 1); combo->blockSignals(false); values->setCurrentWidget(combo); } }; } namespace { static const struct { const Condition::Type type; const char *name; } SizeTypes[] = { { Condition::Is, I18N_NOOP("equals") }, { Condition::IsNot, I18N_NOOP("does not equal") }, { Condition::Greater, I18N_NOOP("is greater than") }, { Condition::Smaller, I18N_NOOP("is smaller than") } }; static const int SizeTypeCount = sizeof(SizeTypes) / sizeof(*SizeTypes); class SizeWidgetHandler : public ConditionWidgetHandler { public: SizeWidgetHandler() : ConditionWidgetHandler() { } QWidget *createTypeWidget(QWidget *parent, const QObject *receiver) const { QComboBox *combo = new QComboBox(parent); for (int i = 0; i < SizeTypeCount; i++) { combo->insertItem(i, i18n(SizeTypes[i].name)); } combo->adjustSize(); // Connect the signal QObject::connect(combo, SIGNAL(activated(int)), receiver, SLOT(slotTypeChanged())); return combo; } Condition::Type getConditionType(QWidget *widget) const { QComboBox *combo = static_cast(widget); return SizeTypes[combo->currentIndex()].type; } void createValueWidgets(QStackedWidget *stack, const QObject *receiver) const { KIntNumInput *numInput = new KIntNumInput(stack); numInput->setObjectName("sizeWidgetHandler_NumInput"); numInput->setMinimum(0); numInput->setSuffix(" " + i18n("bytes")); QObject::connect(numInput, SIGNAL(valueChanged(int)), receiver, SLOT(slotValueChanged())); stack->addWidget(numInput); } QVariant getConditionValue(QStackedWidget *values) const { KIntNumInput *numInput = values->findChild("sizeWidgetHandler_NumInput"); return QVariant(numInput->value()); } void update(int field, QStackedWidget *types, QStackedWidget *values) const { types->setCurrentIndex(field); values->setCurrentWidget(values->findChild("sizeWidgetHandler_NumInput")); } void setCondition(QStackedWidget *types, QStackedWidget *values, const Condition *condition) { // Set condition type const Condition::Type type = condition->type(); int typeIndex = 0; for (; typeIndex < SizeTypeCount; typeIndex++) if (type == SizeTypes[typeIndex].type) break; QComboBox *combo = static_cast(types->widget(((int) condition->field()))); combo->blockSignals(true); combo->setCurrentIndex(typeIndex); combo->blockSignals(false); types->setCurrentWidget(combo); // Set condition value KIntNumInput *numInput = values->findChild("sizeWidgetHandler_NumInput"); numInput->blockSignals(true); numInput->setValue(condition->value().toInt()); numInput->blockSignals(false); values->setCurrentWidget(numInput); } }; } class EmptyActionWidgetHandler : public ActionWidgetHandler { public: EmptyActionWidgetHandler() : ActionWidgetHandler() { } virtual QWidget *createWidget(QWidget *parent, const QObject *receiver) const { Q_UNUSED(receiver); return new QWidget(parent); } QVariant getActionValue(QWidget *widget) const { Q_UNUSED(widget); return QVariant(QString()); } void setAction(QStackedWidget *stack, const Action *action) const { stack->setCurrentIndex((int) action->type()); } }; class NoneActionWidgetHandler : public EmptyActionWidgetHandler { public: NoneActionWidgetHandler() : EmptyActionWidgetHandler() { } QWidget *createWidget(QWidget *parent, const QObject *receiver) const { Q_UNUSED(receiver); return new QLabel(i18n("Please select an action."), parent); } }; class PriorityActionWidgetHandler : public ActionWidgetHandler { public: PriorityActionWidgetHandler() : ActionWidgetHandler() { } QWidget *createWidget(QWidget *parent, const QObject *receiver) const { KIntNumInput *numInput = new KIntNumInput(parent); numInput->setPrefix(i18n("Priority:") + " "); QObject::connect(numInput, SIGNAL(valueChanged(int)), receiver, SLOT(slotValueChanged())); return numInput; } QVariant getActionValue(QWidget *widget) const { KIntNumInput *numInput = static_cast(widget); return QVariant(numInput->value()); } void setAction(QStackedWidget *stack, const Action *action) const { stack->setCurrentIndex((int) action->type()); KIntNumInput *numInput = static_cast(stack->currentWidget()); numInput->setValue(action->value().toInt()); } }; class ColorizeActionWidgetHandler : public ActionWidgetHandler { public: ColorizeActionWidgetHandler() : ActionWidgetHandler() { } QWidget *createWidget(QWidget *parent, const QObject *receiver) const { KColorButton *colorButton = new KColorButton(parent); QObject::connect(colorButton, SIGNAL(changed(const QColor&)), receiver, SLOT(slotValueChanged())); return colorButton; } QVariant getActionValue(QWidget *widget) const { KColorButton *colorButton = static_cast(widget); return QVariant(colorButton->color()); } void setAction(QStackedWidget *stack, const Action *action) const { stack->setCurrentIndex((int) action->type()); KColorButton *colorButton = static_cast(stack->currentWidget()); colorButton->setColor(action->value().value()); } }; class WidgetHandlerManagerPrivate { public: WidgetHandlerManager instance; }; K_GLOBAL_STATIC(WidgetHandlerManagerPrivate, widgetHandlerManagerPrivate) WidgetHandlerManager *WidgetHandlerManager::self() { return &widgetHandlerManagerPrivate->instance; } WidgetHandlerManager::WidgetHandlerManager() { // Register condition handlers registerConditionHandler(Filename, new TextWidgetHandler()); registerConditionHandler(EntryType, new EntryWidgetHandler()); registerConditionHandler(Size, new SizeWidgetHandler()); // Register action handlers registerActionHandler(Action::None, new NoneActionWidgetHandler()); registerActionHandler(Action::Priority, new PriorityActionWidgetHandler()); registerActionHandler(Action::Skip, new EmptyActionWidgetHandler()); registerActionHandler(Action::Colorize, new ColorizeActionWidgetHandler()); registerActionHandler(Action::Hide, new EmptyActionWidgetHandler()); registerActionHandler(Action::Lowercase, new EmptyActionWidgetHandler()); } WidgetHandlerManager::~WidgetHandlerManager() { } void WidgetHandlerManager::registerConditionHandler(Field field, ConditionWidgetHandler *handler) { m_conditionHandlers[field] = handler; } void WidgetHandlerManager::registerActionHandler(Action::Type type, ActionWidgetHandler *handler) { m_actionHandlers[type] = handler; } void WidgetHandlerManager::createConditionWidgets(QStackedWidget *types, QStackedWidget *values, const QObject *receiver) { ConditionHandlerMap::ConstIterator le = m_conditionHandlers.constEnd(); for (ConditionHandlerMap::ConstIterator i = m_conditionHandlers.constBegin(); i != le; ++i) { Field field = i.key(); const ConditionWidgetHandler *handler = i.value(); types->insertWidget((int) field, handler->createTypeWidget(types, receiver)); handler->createValueWidgets(values, receiver); } } void WidgetHandlerManager::createActionWidgets(QStackedWidget *stack, const QObject *receiver) { ActionHandlerMap::ConstIterator le = m_actionHandlers.constEnd(); for (ActionHandlerMap::ConstIterator i = m_actionHandlers.constBegin(); i != le; ++i) { Action::Type type = i.key(); const ActionWidgetHandler *handler = i.value(); stack->insertWidget((int) type, handler->createWidget(stack, receiver)); } } void WidgetHandlerManager::update(Field field, QStackedWidget *types, QStackedWidget *values) { m_conditionHandlers[field]->update((int) field, types, values); } void WidgetHandlerManager::setCondition(QStackedWidget *types, QStackedWidget *values, const Condition *condition) { m_conditionHandlers[condition->field()]->setCondition(types, values, condition); } Condition::Type WidgetHandlerManager::getConditionType(Field field, QStackedWidget *types) { return m_conditionHandlers[field]->getConditionType(types->widget((int) field)); } QVariant WidgetHandlerManager::getConditionValue(Field field, QStackedWidget *values) { return m_conditionHandlers[field]->getConditionValue(values); } void WidgetHandlerManager::setAction(QStackedWidget *stack, const Action *action) { m_actionHandlers[action->type()]->setAction(stack, action); } QVariant WidgetHandlerManager::getActionValue(QStackedWidget *stack) { QWidget *widget = stack->currentWidget(); return m_actionHandlers[(Action::Type) stack->indexOf(widget)]->getActionValue(widget); } } } kftpgrabber-0.8.99~svn1214766/src/misc/configbase.h0000644000175000017500000001030511276037142021375 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCORECONFIGBASE_H #define KFTPCORECONFIGBASE_H #include #include "certificatestore.h" #include "fileexistsactions.h" namespace KFTPCore { /** * This is a base class for KFTPGrabber's configuration. It is inherited by * auto-generated KConfigXT class KFTPCore::Config that adds all the configuration * options. * * @author Jernej Kos */ class ConfigBase : public KConfigSkeleton { Q_OBJECT public: ConfigBase(const QString &fileName); /** * Does some post initialization stuff that couldn't be done in the constructor due * to use of Config singleton. */ void postInit(); /** * Does some pre write stuff (eg. exporting the actions). */ void saveConfig(); /** * Returns a proper mode for the requested file. If the current mode is set to AUTO * the list of ascii file patterns is consulted. * * @param filename The filename for which the mode should be returned * @return A valid FTP transfer mode */ char ftpMode(const QString &filename); /** * Set the global transfer mode. * * @param mode Transfer mode */ void setGlobalMode(char mode) { m_transMode = mode; } /** * Get the global transfer mode. * * @return The transfer mode currently in use */ char getGlobalMode() const { return m_transMode; } /** * Get the download actions object. * * @return The FileExistsActions object for download actions */ KFTPQueue::FileExistsActions *dActions() { return &m_fileExistsDownActions; } /** * Get the upload actions object. * * @return The FileExistsActions object for upload actions */ KFTPQueue::FileExistsActions *uActions() { return &m_fileExistsUpActions; } /** * Get the fxp actions object. * * @return The FileExistsActions object for fxp actions */ KFTPQueue::FileExistsActions *fActions() { return &m_fileExistsFxpActions; } /** * Returns the global CertificateStore object. */ CertificateStore *certificateStore() { return &m_certificateStore; } public slots: /** * Emits the configChanged() signal. */ void emitChange(); protected: QString getGlobalMail(); private: KFTPQueue::FileExistsActions m_fileExistsDownActions; KFTPQueue::FileExistsActions m_fileExistsUpActions; KFTPQueue::FileExistsActions m_fileExistsFxpActions; CertificateStore m_certificateStore; char m_transMode; signals: void configChanged(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/misc/plugins/0000755000175000017500000000000011276037142020606 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/0000755000175000017500000000000011276037142023646 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/filezilla3/0000755000175000017500000000000011276037142025704 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/filezilla3/kftpimportfz3plugin.cpp0000644000175000017500000001327711276037142032463 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftpimportfz3plugin.h" #include #include #include #include #include K_EXPORT_COMPONENT_FACTORY(kftpimportplugin_filezilla3, KGenericFactory("kftpimportplugin_filezilla3")) KFTPImportFz3Plugin::KFTPImportFz3Plugin(QObject *parent, const QStringList&) : KFTPBookmarkImportPlugin(parent) { KGlobal::locale()->insertCatalog("kftpgrabber"); } QDomDocument KFTPImportFz3Plugin::getImportedXml() { return m_domDocument; } void KFTPImportFz3Plugin::import(const QString &fileName) { m_domDocument.setContent(QString("").arg(i18n("FileZilla 3 import"))); QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { emit progress(100); return; } m_workDocument.setContent(&file); file.close(); // Import categories recursively importCategory(m_domDocument.documentElement(), m_workDocument.documentElement().firstChild()); emit progress(100); } void KFTPImportFz3Plugin::importCategory(QDomNode parent, const QDomNode &node) { QDomNode n = node.firstChild(); while (!n.isNull()) { if (!n.isElement()) { n = n.nextSibling(); continue; } QDomElement e = n.toElement(); if (e.tagName() == "Folder") { QDomElement categoryElement = m_domDocument.createElement("category"); categoryElement.setAttribute("name", e.firstChild().nodeValue().trimmed()); parent.appendChild(categoryElement); importCategory(categoryElement, n); } else if (e.tagName() == "Server") { QString name = e.lastChild().nodeValue().trimmed(); QString host = e.namedItem("Host").toElement().text(); QString port = e.namedItem("Port").toElement().text(); QString localDir = e.namedItem("LocalDir").toElement().text(); QString remoteDir = e.namedItem("RemoteDir").toElement().text(); QString username = e.namedItem("User").toElement().text(); QString password = e.namedItem("Pass").toElement().text(); // Set name QDomElement siteElement = m_domDocument.createElement("server"); siteElement.setAttribute("name", name); parent.appendChild(siteElement); // Set host QDomElement tmpElement = m_domDocument.createElement("host"); QDomText txtNode = m_domDocument.createTextNode(host); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set port tmpElement = m_domDocument.createElement("port"); txtNode = m_domDocument.createTextNode(port); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set remote directory tmpElement = m_domDocument.createElement("defremotepath"); txtNode = m_domDocument.createTextNode(remoteDir); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set local directory tmpElement = m_domDocument.createElement("deflocalpath"); txtNode = m_domDocument.createTextNode(localDir); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set username if (username.isNull()) { username = "anonymous"; tmpElement = m_domDocument.createElement("anonlogin"); txtNode = m_domDocument.createTextNode("1"); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); } tmpElement = m_domDocument.createElement("username"); txtNode = m_domDocument.createTextNode(username); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set password tmpElement = m_domDocument.createElement("password"); txtNode = m_domDocument.createTextNode(KCodecs::base64Encode(password.toAscii(), true).data()); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); } n = n.nextSibling(); } } QString KFTPImportFz3Plugin::getDefaultPath() { return QString(".filezilla/sitemanager.xml"); } #include "kftpimportfz3plugin.moc" kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/filezilla3/kftpimportfz3plugin.h0000644000175000017500000000554511276037142032127 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPIMPORTFZ3PLUGIN_H #define KFTPIMPORTFZ3PLUGIN_H #include #include /** * This plugin enables importing of FileZilla 3 bookmark files into KFTPGrabber. * * @author Jernej Kos */ class KFTPImportFz3Plugin : public KFTPBookmarkImportPlugin { Q_OBJECT public: KFTPImportFz3Plugin(QObject *parent, const QStringList&); /** * This method should return the properly formated XML for KFTPGrabber * bookmarks that is generated from the import. * * @return The @ref QDomDocument representation of XML */ QDomDocument getImportedXml(); /** * This method should start the import procedure. * * @param fileName is the path to the file that will be imported */ void import(const QString &fileName); /** * This method should return the default path where the bookmarks could * be located. The path must be relative to the user's home directory. * * @return The default path where bookmarks are located */ QString getDefaultPath(); private: QDomDocument m_domDocument; QDomDocument m_workDocument; void importCategory(QDomNode parent, const QDomNode &node); }; #endif ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootkftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/filezilla3/kftpimportplugin_filezilla3.desktopkftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/filezilla3/kftpimportplugin_filezilla30000644000175000017500000001042711556266077033403 0ustar michaelmichael[Desktop Entry] Name=FileZilla 3 Import plugin Name[be]=Утулка імпарту FileZilla 3 Name[bg]=Приставка за импортиране на FileZilla 3 Name[cs]=gFileZilla 3 importní modul Name[da]=Import-plugin til FileZilla 3 Name[de]=FileZilla-3-Importmodul Name[el]=Πρόσθετο εισαγωγής FileZilla 3 Name[en_GB]=FileZilla 3 Import plugin Name[es]=Complemento de importación de FileZilla 3 Name[et]=FileZilla 3 impordiplugin Name[fi]=FileZilla 3-tuontiliitännäinen Name[fr]=Module externe d'importation FileZilla 3 Name[ga]=Breiseán Iompórtála FileZilla 3 Name[gl]=Extensión para importar desde FileZilla 3 Name[hne]=फाइल जिल्ला ३ आयात प्लगइन Name[is]=FileZilla 3 Innflutningsíforrit Name[it]=Estensione di importazione FileZilla 3 Name[ja]=FileZilla 3 インポートプラグイン Name[km]=កម្មវិធី​ជំនួយ​នាំចូល FileZilla 3 Name[lt]=FileZilla 3 importavimo įskiepis Name[lv]=FileZilla 3 importēšanas spraudnis Name[nb]=Programtillegg for FileZilla 3 import Name[nds]=Importmoduul för FileZilla 3 Name[nl]=FileZilla 3-importplugin Name[pa]=FileZilla 3 ਇੰਪੋਰਟ ਪਲੱਗਇਨ Name[pl]=Wtyczka do importu z FileZilla 3 Name[pt]='Plugin' de Importação do FileZilla 3 Name[pt_BR]=Plug-in de importação do FileZilla 3 Name[ro]=Modul de import FileZilla 3 Name[ru]=Модуль импорта из FileZilla 3 Name[sv]=FileZilla 3-importinsticksprogram Name[th]=ปลั๊กอินนำเข้าของ FileZilla 3 Name[tr]=Filezilla 3 İçeriye Aktarma Eklentisi Name[uk]=Додаток для імпорту з FileZilla 3 Name[x-test]=xxFileZilla 3 Import pluginxx Name[zh_CN]=FileZilla 3 导入插件 Name[zh_TW]=FileZilla 3 匯入外掛程式 Comment=FileZilla 3 bookmarks import plugin Comment[bg]=Приставка за импортиране на FileZilla 3 отметки в KFTPGrabber Comment[cs]=FileZilla 3 modul importu záložek pro KFTPGrabber Comment[da]=Import-plugin til bogmærker fra FileZilla 3 Comment[de]=FileZilla-3-Lesezeichenimportmodul Comment[el]=Πρόσθετο εισαγωγής σελιδοδεικτών FileZilla 3 Comment[en_GB]=FileZilla 3 bookmarks import plugin Comment[es]=Complemento de importación de marcadores de FileZilla 3 Comment[et]=FileZilla 3 järjehoidjate impordiplugin Comment[fi]=FileZilla 3-kirjanmerkkien tuontiliitännäinen Comment[fr]=Module externe d'importation de signets FileZilla 3 Comment[ga]=Breiseán iompórtála leabharmharcanna FileZilla 3 Comment[gl]=Unha extensión para importar os favoritos de FileZilla 3 Comment[hne]=फाइल जिल्ला ३ निसानी आयात प्लगइन Comment[is]=FileZilla 3 íforrit fyrir innflutning bókamerkja Comment[it]=Estensione di importazione dei segnalibri di FileZilla 3 Comment[ja]=FileZilla 3 ブックマークをインポートするプラグイン Comment[km]=កម្មវិធីជំនួយ​នាំចូល​ចំណាំ​របស់ FileZilla 3 Comment[lt]=FileZilla 3 žymelių importavimo įskiepis Comment[lv]=FileZilla 3 grāmatzīmju KFTPGrabber importēšanas spraudnis Comment[nb]=Programtillegg for FileZilla 3 bokmerkeimport Comment[nds]=Importmoduul för Leesteken vun FileZilla 3 Comment[nl]=FileZilla 3-bladwijzers importplugin Comment[pa]=FileZilla 3 ਬੁੱਕਮਾਰਕ ਇੰਪੋਰਟ ਪਲੱਗਇਨ Comment[pl]=Wtyczka do importu zakładek z FileZilla 3 Comment[pt]='Plugin' de importação de favoritos do FileZilla 3 Comment[pt_BR]=Plug-in de importação de favoritos do FileZilla 3 Comment[ro]=Modul de importat semne de carte din Filezilla 3 Comment[ru]=Модуль импорта закладок из FileZilla 3 Comment[sv]=Insticksprogram för FileZilla 3-bokmärkesimport Comment[th]=ปลั๊กอินนำเข้าที่คั่นหนังสือของ FileZilla 3 Comment[tr]=Filezilla 3 sık kullanılanları içeriye aktarma eklentisi Comment[uk]=Додаток для імпорту закладок з FileZilla 3 Comment[x-test]=xxFileZilla 3 bookmarks import pluginxx Comment[zh_CN]=FileZilla 3 书签导入插件 Comment[zh_TW]=FileZilla 3 書籤匯入外掛程式 X-KDE-ServiceTypes=KFTPGrabber/BookmarkImportPlugin Type=Service X-KDE-Library=kftpimportplugin_filezilla3 kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/filezilla3/CMakeLists.txt0000644000175000017500000000117311276037142030446 0ustar michaelmichaelINCLUDE_DIRECTORIES( ../../../interfaces ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(kftpimportplugin_filezilla3_PART_SRCS kftpimportfz3plugin.cpp ) kde4_add_plugin(kftpimportplugin_filezilla3 ${kftpimportplugin_filezilla3_PART_SRCS}) target_link_libraries(kftpimportplugin_filezilla3 ${KDE4_KPARTS_LIBS} kftpinterfaces) install(TARGETS kftpimportplugin_filezilla3 DESTINATION ${PLUGIN_INSTALL_DIR}) ########### install files ############### install(FILES kftpimportplugin_filezilla3.desktop DESTINATION ${SERVICES_INSTALL_DIR}) kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/kftp/0000755000175000017500000000000011276037142024612 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/kftp/kftpimportkftpplugin.cpp0000644000175000017500000000706711276037142031633 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftpimportkftpplugin.h" #include #include #include #include #include #include K_EXPORT_COMPONENT_FACTORY(kftpimportplugin_kftp, KGenericFactory("kftpimportplugin_kftp")) KFTPImportKftpPlugin::KFTPImportKftpPlugin(QObject *parent, const QStringList&) : KFTPBookmarkImportPlugin(parent) { KGlobal::locale()->insertCatalog("kftpgrabber"); } QDomDocument KFTPImportKftpPlugin::getImportedXml() { return m_domDocument; } void KFTPImportKftpPlugin::import(const QString &fileName) { m_domDocument.setContent(QString("").arg(i18n("KFTPGrabber import"))); // There is actually nothing to import, we just have to read the existing XML and // remove site ids. QFile file(fileName); if (!file.open(QIODevice::ReadOnly)) { emit progress(100); return; } m_workDocument.setContent(&file); file.close(); // Strip all ids stripIds(); // Now append the bookmarks QDomNode n = m_workDocument.documentElement().firstChild(); while (!n.isNull()) { QDomNode import = m_domDocument.importNode(n, true); m_domDocument.documentElement().appendChild(import); n = n.nextSibling(); } emit progress(100); } void KFTPImportKftpPlugin::stripIds(QDomNode node) { if (node.isNull()) node = m_workDocument.documentElement(); QDomNode n = node.firstChild(); while (!n.isNull()) { if (n.toElement().tagName() == "category") { if (!n.toElement().hasAttribute("id")) n.toElement().removeAttribute("id"); stripIds(n); } else if (n.toElement().tagName() == "server") { if (n.toElement().hasAttribute("id")) n.toElement().removeAttribute("id"); } n = n.nextSibling(); } } QString KFTPImportKftpPlugin::getDefaultPath() { return QString(""); } #include "kftpimportkftpplugin.moc" kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/kftp/kftpimportplugin_kftp.desktop0000644000175000017500000001066011556266110032652 0ustar michaelmichael[Desktop Entry] Name=KFTPGrabber XML Import plugin Name[bg]=Приставка за импортиране на XML в KFTPGrabber Name[cs]=KFTPGrabber XML importní modul Name[da]=Import-plugin til KFTPGrabber til XML Name[de]=KFTPGrabber-XML-Importmodul Name[el]=Πρόσθετο εισαγωγής XML του KFTPGrabber Name[en_GB]=KFTPGrabber XML Import plugin Name[es]=Complemento de importación de XML de KFTPGrabber Name[et]=KFTPGrabberi XML-i impordiplugin Name[fi]=KFTPGrabber XML-tuontiliitännäinen Name[fr]=Module externe d'importation XML KFTPGrabber Name[ga]=Breiseán Iompórtála XML KFTPGrabber Name[gl]=Extensión para importar XML de KFTPGrabber Name[is]=KFTPGrabber XML Innflutningsíforrit Name[it]=Estensione di importazione XML per KFTPGrabber Name[ja]=KFTPGrabber XML インポートプラグイン Name[km]=កម្មវិធី​ជំនួយ​នាំចូល​ XML របស់ KFTPGrabber Name[lt]=KFTPGrabber XML importavimo įskiepis Name[lv]=KFTPGrabber XML importēšanas spraudnis Name[nb]=KFTPGrabber programtillegg for XML-import Name[nds]=KFTPGrabber XML-Importmoduul Name[nl]=KFTPGrabber XML Importplugin Name[pa]=KFTPGrabber XML ਇੰਪੋਰਟ ਪਲੱਗਇਨ Name[pt]='Plugin' de importação XML do KFTPGrabber Name[pt_BR]=Plug-in de importação XML do KFTPGrabber Name[ro]=Modul de import XML KFTPGrabber Name[ru]=Модуль KFTPGrabber для импорта из XML Name[sv]=Insticksprogram för XML-import till KFTPgrabber Name[th]=ปลั๊กอินนำเข้าของ KFTPGrabber แบบ XML Name[tr]=KFTPGrabber XML dosyalarını içeriye aktarma eklentisi Name[uk]=Додаток імпорту XML для KFTPGrabber Name[x-test]=xxKFTPGrabber XML Import pluginxx Name[zh_CN]=KFTPGrabber 的 XML 导入插件 Name[zh_TW]=KFTPGrabber XML 匯入外掛程式 Comment=KFTPGrabber XML bookmarks import plugin Comment[bg]=Приставка за импортиране на XML отметки в KFTPGrabber Comment[cs]=XML modul importu záložek pro KFTPGrabber Comment[da]=Import-plugin til KFTPGrabber til XML-bogmærker Comment[de]=KFTPGrabber-XML-Lesezeichenimportmodul Comment[el]=Πρόσθετο εισαγωγής σελιδοδεικτών XML του KFTPGrabber Comment[en_GB]=KFTPGrabber XML bookmarks import plugin Comment[es]=Complemento de importación de marcadores en XML de KFTPGrabber Comment[et]=KFTPGrabberi XML-järjehoidjate impordiplugin Comment[fi]=KFTPGrabber XML-kirjanmerkkien tuontiliitännäinen Comment[fr]=Module externe d'importation de signets XML KFTPGrabber Comment[ga]=Breiseán iompórtála leabharmharcanna XML le haghaidh KFTPGrabber Comment[gl]=Unha extensión para importar os favoritos desde o XML de KFTPGrabber Comment[is]=Íforrit fyrir innflutning XML bókamerkja í KFTPGrabber Comment[it]=Estensione di importazione dei segnalibri XML per KFTPGrabber Comment[ja]=XML ブックマークをインポートする KFTPGrabber プラグイン Comment[km]=កម្មវិធី​ជំនួយ​នាំចូល​ចំណាំ​ XML របស់ KFTPGrabber Comment[lt]=KFTPGrabber XML žymelių importavimo įskiepis Comment[lv]=KFTPGrabber XML grāmatzīmju KFTPGrabber importēšanas spraudnis Comment[ms]=Plugin import tandabuku XML KFTPGrabber Comment[nb]=KFTPGrabber programtillegg for XML bokmerkeimport Comment[nds]=En KFTPGrabber-Moduul för't Importeren vun XML-Leesteken Comment[nl]=KFTPGrabber-plugin voor het importeren van XML-bladwijzers Comment[pa]=KFTPGrabber XML ਬੁੱਕਮਾਰਕ ਇੰਪੋਰਟ ਪਲੱਗਇਨ Comment[pt]='Plugin' de importação de favoritos em XML para o KFTPGrabber Comment[pt_BR]=Plug-in de importação de favoritos em XML para o KFTPGrabber Comment[ro]=Modul de importat semne de carte XML KFTPGrabber Comment[ru]=Модуль KFTPGrabber для импорта закладок из XML Comment[sv]=Insticksprogram för XML-bokmärkesimport till KFTPgrabber Comment[th]=ปลั๊กอินนำเข้าที่คั่นหนังสือของ KFTPGrabber แบบ XML Comment[tr]=KFTPGrabber için XML sık kullanılanları içeriye aktarma eklentisi Comment[uk]=Додаток до KFTPGrabber для імпорту XML-закладок Comment[x-test]=xxKFTPGrabber XML bookmarks import pluginxx Comment[zh_CN]=KFTPGrabber 的 XML 书签导入插件 Comment[zh_TW]=KFTPGrabber XML 書籤匯入外掛程式 X-KDE-ServiceTypes=KFTPGrabber/BookmarkImportPlugin Type=Service X-KDE-Library=kftpimportplugin_kftp kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/kftp/kftpimportkftpplugin.h0000644000175000017500000000564011276037142031273 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPIMPORTKFTPPLUGIN_H #define KFTPIMPORTKFTPPLUGIN_H #include #include /** * This plugin enables importing of KFTPGrabber XML bookmark files into KFTPGrabber, * so the users can import bookmarks that were previously exported. * * @author Jernej Kos */ class KFTPImportKftpPlugin : public KFTPBookmarkImportPlugin { Q_OBJECT public: KFTPImportKftpPlugin(QObject *parent, const QStringList&); /** * This method should return the properly formated XML for KFTPGrabber * bookmarks that is generated from the import. * * @return The @ref QDomDocument representation of XML */ QDomDocument getImportedXml(); /** * This method should start the import procedure. * * @param fileName is the path to the file that will be imported */ void import(const QString &fileName); /** * This method should return the default path where the bookmarks could * be located. The path must be relative to the user's home directory. * * @return The default path where bookmarks are located */ QString getDefaultPath(); private: QDomDocument m_domDocument; QDomDocument m_workDocument; void stripIds(QDomNode node = QDomNode()); }; #endif kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/kftp/CMakeLists.txt0000644000175000017500000000113011276037142027345 0ustar michaelmichaelINCLUDE_DIRECTORIES( ../../../interfaces ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(kftpimportplugin_kftp_PART_SRCS kftpimportkftpplugin.cpp ) kde4_add_plugin(kftpimportplugin_kftp ${kftpimportplugin_kftp_PART_SRCS}) TARGET_LINK_LIBRARIES(kftpimportplugin_kftp ${KDE4_KPARTS_LIBS} kftpinterfaces) install(TARGETS kftpimportplugin_kftp DESTINATION ${PLUGIN_INSTALL_DIR}) ########### install files ############### install(FILES kftpimportplugin_kftp.desktop DESTINATION ${SERVICES_INSTALL_DIR}) kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/gftp/0000755000175000017500000000000011276037142024606 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/gftp/kftpimportgftpplugin.cpp0000644000175000017500000002005411276037142031612 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftpimportgftpplugin.h" #include #include #include #include #include #include K_EXPORT_COMPONENT_FACTORY(kftpimportplugin_gftp, KGenericFactory("kftpimportplugin_gftp")) KFTPImportGftpPlugin::KFTPImportGftpPlugin(QObject *parent, const QStringList&) : KFTPBookmarkImportPlugin(parent) { KGlobal::locale()->insertCatalog("kftpgrabber"); m_domDocument.setContent(QString("").arg(i18n("gFTP import"))); } QDomDocument KFTPImportGftpPlugin::getImportedXml() { return m_domDocument; } void KFTPImportGftpPlugin::import(const QString &fileName) { // First we fetch some global settings KConfig tmpConfig(userPath(".gftp/gftprc"), KConfig::NoGlobals); KConfigGroup group = tmpConfig.group(0); QString email = group.readEntry("email", "anonymous@"); int numRetries = group.readEntry("retries", -1); int sleepTime = group.readEntry("sleep_time", -1); // Open the bookmarks file (it has INI-like file format, so we can use the KConfig // class to do the parsing and converting) KConfig config(fileName, KConfig::SimpleConfig); QStringList groupList = config.groupList(); float size = (float) groupList.count(); if (size == 0) { // There are no bookmarks (or incorrect file), we are done emit progress(100); return; } int counter = 0; QStringList::Iterator end(groupList.end()); for( QStringList::Iterator it(groupList.begin()); it != end; ++it) { // gFTP bookmarks can have subgroups QString groupName = *it; QStringList groupNames = groupName.split("/"); QDomNode groupNode; QDomElement parentElement = m_domDocument.documentElement(); group = config.group(groupName); QString tmp = group.readEntry("hostname"); for (int i = 0; ! tmp.isNull() && i < groupNames.count() - 1; ++i ) { // First see if parenElement has any sub group groupNode = findSubGroup(parentElement, groupNames[i]); if (groupNode.isNull()) { // No, it has no subgroup, let's create one while (i < groupNames.count() -1) { QDomElement tmpElement = m_domDocument.createElement("category"); tmpElement.setAttribute("name", groupNames[i]); parentElement.appendChild(tmpElement); parentElement = tmpElement; ++i; } } else { // Sub group found, lets check next level parentElement = groupNode.toElement(); } } // Now group tree is updated so lets create the site (if it has hostname) if (!tmp.isNull()) { // Set name QDomElement siteElement = m_domDocument.createElement("server"); siteElement.setAttribute("name", groupNames.last()); parentElement.appendChild(siteElement); // Set host tmp = group.readEntry("hostname"); QDomElement tmpElement = m_domDocument.createElement("host"); QDomText txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set port int p = group.readEntry("port", 21); tmpElement = m_domDocument.createElement("port"); txtNode = m_domDocument.createTextNode(QString::number(p)); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set remote directory tmp = group.readEntry("remote directory", "/"); tmpElement = m_domDocument.createElement("defremotepath"); txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set local directory tmp = group.readEntry("local directory", QDir::homePath()); tmpElement = m_domDocument.createElement("deflocalpath"); txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set username tmp = group.readEntry("username", "anonymous"); tmpElement = m_domDocument.createElement("username"); txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); if (tmp == "anonymous") { tmpElement = m_domDocument.createElement("anonlogin"); txtNode = m_domDocument.createTextNode("1"); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); } // Set password tmp = group.readEntry("password", ""); tmpElement = m_domDocument.createElement("password"); if (tmp == "@EMAIL@" || tmp.isNull() || tmp.isEmpty()) tmp = email; else tmp = decodePassword(tmp); // We have to encode the password tmp = KCodecs::base64Encode(tmp.toAscii(), true).data(); txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set retries if (numRetries >= 0) { tmpElement = m_domDocument.createElement("retrytime"); txtNode = m_domDocument.createTextNode(QString::number(sleepTime)); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); tmpElement = m_domDocument.createElement("retrycount"); txtNode = m_domDocument.createTextNode(QString::number(numRetries)); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); } } emit progress(int(float(counter) / size * 100)); ++counter; } emit progress(100); } QString KFTPImportGftpPlugin::decodePassword(const QString &password) { // Leave unencoded passwords as they are if (password[0] != '$') return password; QString work = password; work.remove(0, 1); QString result; for (int i = 0; i < work.length() - 1; i += 2) { char c = work.at(i).toLatin1(); char n = work.at(i+1).toLatin1(); result.append( ((c & 0x3c) << 2) | ((n & 0x3c) >> 2) ); } return result; } QDomNode KFTPImportGftpPlugin::findSubGroup(QDomElement parent, const QString& name) { QDomNodeList nodeList = parent.childNodes(); for (int i = 0; i < nodeList.count(); ++i) { if(nodeList.item(i).toElement().attribute("name") == name) return nodeList.item(i); } return QDomNode(); } QString KFTPImportGftpPlugin::getDefaultPath() { return QString(".gftp/bookmarks"); } kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/gftp/kftpimportplugin_gftp.desktop0000644000175000017500000001011111556266102032632 0ustar michaelmichael[Desktop Entry] Name=gFTP Import plugin Name[bg]=Приставка за импортиране на gFTP Name[cs]=gFTP importní modul Name[da]=Import-plugin til gFTP Name[de]=gFTP-Importmodul Name[el]=Πρόσθετο εισαγωγής gFTP Name[en_GB]=gFTP Import plugin Name[es]=Complemento de importación de gFTP Name[et]=gFTP impordiplugin Name[fi]=gFTP-tuontiliitännäinen Name[fr]=Module externe d'importation gFTP Name[ga]=Breiseán Iompórtála gFTP Name[gl]=Extensión para importar desde gFTP Name[hne]=जीएफटीपी ३ आयात प्लगइन Name[is]=gFTP Innflutningsíforrit Name[it]=Estensione di importazione gFTP Name[ja]=gFTP インポートプラグイン Name[km]=កម្មវិធី​នាំចូល​ gFTP Name[lt]=gFTP importavimo įskiepis Name[lv]=gFTP importēšanas spraudnis Name[nb]=Programtillegg for gFTP-import Name[nds]=Importmoduul för gFTP Name[nl]=gFTP-importplugin Name[pa]=gFTP ਇੰਪੋਰਟ ਪਲੱਗਇਨ Name[pl]=Wtyczka do importu z gFTP Name[pt]='Plugin' de importação do gFTP Name[pt_BR]=Plug-in de importação do gFTP Name[ro]=Modul de import gFTP Name[ru]=Модуль импорта из gFTP Name[sv]=gFTP-importinsticksprogram Name[th]=ปลั๊กอินนำเข้าของ gFTP Name[tr]=gFTP uygulamasından içeriye aktarma eklentisi Name[uk]=Додаток імпорту з gFTP Name[x-test]=xxgFTP Import pluginxx Name[zh_CN]=gFTP 导入插件 Name[zh_TW]=gFTP 匯入外掛程式 Comment=gFTP bookmarks import plugin for KFTPGrabber Comment[bg]=Приставка за импортиране на gFTP отметки в KFTPGrabber Comment[cs]=gFTP modul importu záložek pro KFTPGrabber Comment[da]=Import-plugin til KFTPGrabber til bogmærker fra gFTP Comment[de]=gFTP-Lesezeichenimportmodul Comment[el]=Πρόσθετο εισαγωγής σελιδοδεικτών του gFTP για το KFTPGrabber Comment[en_GB]=gFTP bookmarks import plugin for KFTPGrabber Comment[es]=Complemento de importación de marcadores de gFTP para KFTPGrabber Comment[et]=KFTPGrabberi gFTP järjehoidjate impordiplugin Comment[fi]=gFTP-kirjanmerkkien tuontiliitännäinen KFTPGrabber-ohjelmalle Comment[fr]=Module externe d'importation de signets gFTP pour KFTPGrabber Comment[ga]=Breiseán iompórtála leabharmharcanna gFTP le haghaidh KFTPGrabber Comment[gl]=Unha extensión para importar os favoritos de gFTP en KFTPGrabber Comment[is]=Íforrit fyrir innflutning gFTP bókamerkja í KFTPGrabber Comment[it]=Estensione di importazione dei segnalibri di gFTP per KFTPGrabber Comment[ja]=gFTP のブックマークをインポートする KFTPGrabber プラグイン Comment[km]=កម្មវិធី​ជំនួយ​នាំចូល​ចំណាំ​របស់ gFTP សម្រាប់ KFTPGrabber Comment[lt]=gFTP žymelių importavimo į KFTPGrabber įskiepis Comment[lv]=gFTP grāmatzīmju KFTPGrabber importēšanas spraudnis Comment[nb]=Programtillegg for KFTPGrabber for FTP bokmerke-import Comment[nds]=En KFTPGrabber-Moduul för't Importeren vun gFTP-Leesteken Comment[nl]=KFTPGrabber-plugin voor het importeren van gFTP-bladwijzers Comment[pl]=Wtyczka do importowania zakładek z gFTP Comment[pt]='Plugin' de importação de favoritos do gFTP para o KFTPGrabber Comment[pt_BR]=Plug-in de importação de favoritos do gFTP para o KFTPGrabber Comment[ro]=Modul de importat semne de carte gFTP pentru KFTPGrabber Comment[ru]=Модуль импорта закладок из gFTP для KFTPGrabber Comment[sv]=Insticksprogram för gFTP-bokmärkesimport till KFTPgrabber Comment[th]=ปลั๊กอินนำเข้าที่คั่นหนังสือของ GFTP Comment[tr]=KFTPGrabber için gFTP sık kullanılanlarını içeriye aktarma eklentisi Comment[uk]=Додаток до KFTPGrabber для імпорту закладок з gFTP Comment[x-test]=xxgFTP bookmarks import plugin for KFTPGrabberxx Comment[zh_CN]=KFTPGrabber 的 gFTP 书签导入插件 Comment[zh_TW]=KFTPGrabber 的 gFTP 書籤匯入外掛程式 X-KDE-ServiceTypes=KFTPGrabber/BookmarkImportPlugin Type=Service X-KDE-Library=kftpimportplugin_gftp kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/gftp/CMakeLists.txt0000644000175000017500000000113111276037142027342 0ustar michaelmichaelINCLUDE_DIRECTORIES( ../../../interfaces ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(kftpimportplugin_gftp_PART_SRCS kftpimportgftpplugin.cpp ) kde4_add_plugin(kftpimportplugin_gftp ${kftpimportplugin_gftp_PART_SRCS}) target_link_libraries(kftpimportplugin_gftp kftpinterfaces ${KDE4_KPARTS_LIBS}) install(TARGETS kftpimportplugin_gftp DESTINATION ${PLUGIN_INSTALL_DIR}) ########### install files ############### install(FILES kftpimportplugin_gftp.desktop DESTINATION ${SERVICES_INSTALL_DIR}) kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/gftp/kftpimportgftpplugin.h0000644000175000017500000000566711276037142031274 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPIMPORTGFTPPLUGIN_H #define KFTPIMPORTGFTPPLUGIN_H #include #include /** This plugin can import GFTP bookmarks into KFTPGrabber. This plugin has been ported from "KBear by Bj�n Sahlstr� ". @author Jernej Kos */ class KFTPImportGftpPlugin : public KFTPBookmarkImportPlugin { public: KFTPImportGftpPlugin(QObject *parent, const QStringList&); /** * This method should return the properly formated XML for KFTPGrabber * bookmarks that is generated from the import. * * @return The @ref QDomDocument representation of XML */ QDomDocument getImportedXml(); /** * This method should start the import procedure. * * @param fileName is the path to the file that will be imported */ void import(const QString &fileName); /** * This method should return the default path where the bookmarks could * be located. The path must be relative to the user's home directory. * * @return The default path where bookmarks are located */ QString getDefaultPath(); private: QDomDocument m_domDocument; QDomNode findSubGroup(QDomElement parent, const QString& name); QString decodePassword(const QString &password); }; #endif kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/CMakeLists.txt0000644000175000017500000000016011276037142026403 0ustar michaelmichaelADD_SUBDIRECTORY( gftp ) ADD_SUBDIRECTORY( ncftp ) ADD_SUBDIRECTORY( kftp ) ADD_SUBDIRECTORY( filezilla3 ) kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/ncftp/0000755000175000017500000000000011276037142024760 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/ncftp/kftpimportplugin_ncftp.desktop0000644000175000017500000001025011556266113033164 0ustar michaelmichael[Desktop Entry] Name=NcFTP Import plugin Name[bg]=Приставка за импортиране на NcFTP Name[cs]=NcFTP importní modul Name[da]=Import-plugin til NcFTP Name[de]=NcFTP-Importmodul Name[el]=Πρόσθετο εισαγωγής NcFTP Name[en_GB]=NcFTP Import plugin Name[es]=Complemento de importación de NcFTP Name[et]=NcFTP impordiplugi Name[fi]=NcFTP-tuontiliitännäinen Name[fr]=Module externe d'importation NcFTP Name[ga]=Breiseán Iompórtála NcFTP Name[gl]=Extensión de importación de NcFTP Name[hne]=एनसीएफटीपी ३ आयात प्लगइन Name[is]=NcFTP Innflutningsíforrit Name[it]=Estensione di importazione NcFTP Name[ja]=NcFTP インポートプラグイン Name[km]=កម្មវិធី​ជំនួយ​នាំចូល​ NcFTP Name[lt]=NcFTP importavimo įskiepis Name[lv]=NcFTP importēšanas spraudnis Name[ms]=Plugin Import NcFTP Name[nb]=Programtillegg for NcFTP-import Name[nds]=Importmoduul för NcFTP Name[nl]=NcFTP-importplugin Name[pa]=NcFTP ਇੰਪੋਰਟ ਪਲੱਗਇਨ Name[pt]='Plugin' de importação do NcFTP Name[pt_BR]=Plug-in de importação do NcFTP Name[ro]=Modul de import NcFTP Name[ru]=Модуль импорта из NcFTP Name[sv]=NcFTP-importinsticksprogram Name[th]=ปลั๊กอินนำเข้าของ NcFTP Name[tr]=NcFTP uygulamasından içeriye aktarma eklentisi Name[uk]=Додаток імпорту NcFTP Name[x-test]=xxNcFTP Import pluginxx Name[zh_CN]=NcFTP 导入插件 Name[zh_TW]=NcFTP 匯入外掛程式 Comment=NcFTP bookmarks import plugin for KFTPGrabber Comment[bg]=Приставка за импортиране на NcFTP отметки в KFTPGrabber Comment[cs]=NcFTP modul importu záložek pro KFTPGrabber Comment[da]=Import-plugin til KFTPGrabber til bogmærker fra NcFTP Comment[de]=NcFTP-Lesezeichenimportmodul Comment[el]=Πρόσθετο εισαγωγής σελιδοδεικτών NcFTP για το KFTPGrabber Comment[en_GB]=NcFTP bookmarks import plugin for KFTPGrabber Comment[es]=Complemento de importación de marcadores de NcFTP de KFTPGrabber Comment[et]=KFTPGrabberi NcFTP järjehoidjate impordiplugin Comment[fi]=NcFTP-kirjanmerkkien tuontiliitännäinen KFTPGrabber-ohjelmalle Comment[fr]=Module externe d'importation de signets NcFTP pour KFTPGrabber Comment[ga]=Breiseán iompórtála leabharmharcanna NcFTP le haghaidh KFTPGrabber Comment[gl]=Unha extensión de importación dos favoritos de NcFTP para KFTPGrabber Comment[is]=Íforrit fyrir innflutning NcFTP bókamerkja í KFTPGrabber Comment[it]=Estensione di importazione dei segnalibri di NcFTP per KFTPGrabber Comment[ja]=NcFTP ブックマークをインポートする KFTPGrabber プラグイン Comment[km]=កម្មវិធី​ជំនួយ​នាំចូល​ចំណាំ​របស់ NcFTP សម្រាប់ KFTPGrabber Comment[lt]=NcFTP žymelių importavimo į KFTPGrabber įskiepis Comment[lv]=NcFTP grāmatzīmju KFTPGrabber importēšanas spraudnis Comment[ms]=Plugin import tandabuku NcFTP untuk KFTPGrabber Comment[nb]=KFTPGrabber programtillegg for NcFTP bookmerlkeimport Comment[nds]=En KFTPGrabber-Moduul för't Importeren vun NcFTP-Leesteken Comment[nl]=Een KFTPGrabber-plugin voor het importeren van NcFTP-bladwijzers Comment[pt]='Plugin' de importação de favoritos do NcFTP para o KFTPGrabber Comment[pt_BR]=Plug-in de importação de favoritos do NcFTP para o KFTPGrabber Comment[ro]=Modul de importat semne de carte NcFTP pentru KFTPGrabber Comment[ru]=Модуль импорта закладок из NcFTP для KFTPGrabber Comment[sv]=Insticksprogram för NcFTP-bokmärkesimport till KFTPgrabber Comment[th]=ปลั๊กอินนำเข้าที่คั่นหนังสือของ NcFTP Comment[tr]=KFTPGrabber için NcFTP uygulamasının sık kullanılanlarını içeriye aktarma eklentisi Comment[uk]=Додаток до KFTPGrabber для імпорту закладок з NcFTP Comment[x-test]=xxNcFTP bookmarks import plugin for KFTPGrabberxx Comment[zh_CN]=KFTPGrabber 的 NcFTP 书签导入插件 Comment[zh_TW]=KFTPGrabber NcFTP 書籤匯入外掛程式 X-KDE-ServiceTypes=KFTPGrabber/BookmarkImportPlugin Type=Service X-KDE-Library=kftpimportplugin_ncftp kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/ncftp/kftpimportncftpplugin.h0000644000175000017500000000551311276037142031606 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPIMPORTNCFTPPLUGIN_H #define KFTPIMPORTNCFTPPLUGIN_H #include #include /** This plugin can import NcFTP bookmarks into KFTPGrabber. @author Jernej Kos */ class KFTPImportNcftpPlugin : public KFTPBookmarkImportPlugin { Q_OBJECT public: KFTPImportNcftpPlugin(QObject *parent, const QStringList&); /** * This method should return the properly formated XML for KFTPGrabber * bookmarks that is generated from the import. * * @return The @ref QDomDocument representation of XML */ QDomDocument getImportedXml(); /** * This method should start the import procedure. * * @param fileName is the path to the file that will be imported */ void import(const QString &fileName); /** * This method should return the default path where the bookmarks could * be located. The path must be relative to the user's home directory. * * @return The default path where bookmarks are located */ QString getDefaultPath(); private: QDomDocument m_domDocument; QString subSection(const QString &text, int section, const QString &def = QString::null); }; #endif kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/ncftp/CMakeLists.txt0000644000175000017500000000113711276037142027522 0ustar michaelmichaelINCLUDE_DIRECTORIES( ../../../interfaces ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(kftpimportplugin_ncftp_PART_SRCS kftpimportncftpplugin.cpp ) kde4_add_plugin(kftpimportplugin_ncftp ${kftpimportplugin_ncftp_PART_SRCS}) target_link_libraries(kftpimportplugin_ncftp ${KDE4_KPARTS_LIBS} kftpinterfaces) install(TARGETS kftpimportplugin_ncftp DESTINATION ${PLUGIN_INSTALL_DIR}) ########### install files ############### install(FILES kftpimportplugin_ncftp.desktop DESTINATION ${SERVICES_INSTALL_DIR}) kftpgrabber-0.8.99~svn1214766/src/misc/plugins/bookmarkimport/ncftp/kftpimportncftpplugin.cpp0000644000175000017500000001276511276037142032150 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftpimportncftpplugin.h" #include #include #include #include #include #include K_EXPORT_COMPONENT_FACTORY(kftpimportplugin_ncftp, KGenericFactory("kftpimportplugin_ncftp")) KFTPImportNcftpPlugin::KFTPImportNcftpPlugin(QObject *parent, const QStringList&) : KFTPBookmarkImportPlugin(parent) { KGlobal::locale()->insertCatalog("kftpgrabber"); m_domDocument.setContent(QString("").arg(i18n("NcFtp import"))); } QDomDocument KFTPImportNcftpPlugin::getImportedXml() { return m_domDocument; } void KFTPImportNcftpPlugin::import(const QString &fileName) { /* ARNES FTP serve,ftp.arnes.si,username,*encoded*cGFzc3dvcmQA,,/remote,I,21,4294967295,1,1,-1,1,193.2.1.79,Komentar,,,,,S,-1,/local Redhat,ftp.redhat.com,,,,,I,21,1102099812,-1,-1,-1,1,66.187.224.30,,,,,,S,-1, */ QFile f(fileName); if (!f.open(QIODevice::ReadOnly)) { emit progress(100); return; } QTextStream stream(&f); QString line; int lineNum = 0; while (!stream.atEnd()) { line = stream.readLine(); if (++lineNum <= 2) continue; // Add the imported bookmark QDomElement parentElement = m_domDocument.documentElement(); // Set name QDomElement siteElement = m_domDocument.createElement("server"); siteElement.setAttribute("name", subSection(line, 0)); parentElement.appendChild(siteElement); // Set host QString tmp = subSection(line, 1); QDomElement tmpElement = m_domDocument.createElement("host"); QDomText txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set port tmp = subSection(line, 7, "21"); tmpElement = m_domDocument.createElement("port"); txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set remote directory tmp = subSection(line, 5, "/"); tmpElement = m_domDocument.createElement("defremotepath"); txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set local directory tmp = subSection(line, 21, QDir::homePath()); tmpElement = m_domDocument.createElement("deflocalpath"); txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set username tmp = subSection(line, 2, "anonymous"); tmpElement = m_domDocument.createElement("username"); txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); if (tmp == "anonymous") { tmpElement = m_domDocument.createElement("anonlogin"); txtNode = m_domDocument.createTextNode("1"); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); } // Set password tmp = subSection(line, 3, ""); tmp.replace("*encoded*", ""); tmpElement = m_domDocument.createElement("password"); txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); // Set description tmp = subSection(line, 14, ""); if (!tmp.isEmpty()) { tmpElement = m_domDocument.createElement("description"); txtNode = m_domDocument.createTextNode(tmp); tmpElement.appendChild(txtNode); siteElement.appendChild(tmpElement); } } emit progress(100); } QString KFTPImportNcftpPlugin::subSection(const QString &text, int section, const QString &def) { QString tmp = text.section(',', section, section); return tmp.isEmpty() ? def : tmp; } QString KFTPImportNcftpPlugin::getDefaultPath() { return QString(".ncftp/bookmarks"); } #include "kftpimportncftpplugin.moc" kftpgrabber-0.8.99~svn1214766/src/misc/plugins/CMakeLists.txt0000644000175000017500000000047611276037142023355 0ustar michaelmichaelADD_SUBDIRECTORY( bookmarkimport ) #INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE3_INCLUDE_DIR} ${QT_INCLUDE_DIR} ) ########### install files ############### #original Makefile.am contents follow: #INCLUDES = $(all_includes) #METASOURCES = AUTO #SUBDIRS = bookmarkimport kftpgrabber-0.8.99~svn1214766/src/misc/zeroconf.h0000644000175000017500000000475611276037142021137 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef ZEROCONF_H #define ZEROCONF_H #include #include #include namespace KFTPCore { class ZeroConfPrivate; /** * This class provides an interface to KDNSSD. * * @author Jernej Kos */ class ZeroConf : public QObject { Q_OBJECT friend class ZeroConfPrivate; public: /** * Returns the global zero conf class instance. */ static ZeroConf *self(); /** * Returns discovered services. */ QList getServiceList() const; private: /** * Class constructor. */ ZeroConf(); /** * Class destructor. */ ~ZeroConf(); /** * DNSSD service browser instance. */ DNSSD::ServiceBrowser *m_browser; private slots: void slotServiceChanged(); signals: void servicesUpdated(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/misc/wallet.cpp0000644000175000017500000001132411276037142021122 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2007 by the KFTPGrabber developers * Copyright (C) 2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include #include #include "wallet.h" namespace KFTPCore { class WalletPrivate { public: Wallet instance; }; K_GLOBAL_STATIC(WalletPrivate, walletPrivate) Wallet *Wallet::self() { return &walletPrivate->instance; } Wallet::Wallet() : QObject() { m_wallet = 0L; m_walletRefCount = 0; } Wallet::~Wallet() { slotWalletClosed(); } void Wallet::slotWalletClosed() { m_walletRefCount--; if (m_walletRefCount == 0) { delete m_wallet; m_wallet = 0L; } } QList Wallet::getSiteList() { QList sites; if (!KWallet::Wallet::folderDoesNotExist(KWallet::Wallet::NetworkWallet(), KWallet::Wallet::PasswordFolder())) { if (!m_wallet) { m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0, KWallet::Wallet::Synchronous); if (m_wallet) { m_walletRefCount++; connect(m_wallet, SIGNAL(walletClosed()), this, SLOT(slotWalletClosed())); } } if (!m_wallet) return sites; // Get the site list from our wallet m_wallet->setFolder(KWallet::Wallet::PasswordFolder()); QStringList list = m_wallet->entryList(); QStringList::iterator i; for (i = list.begin(); i != list.end(); ++i) { QMap map; if ((*i).startsWith("ftp-") && m_wallet->readMap(*i, map) == 0) { QString name = *i; name.replace("ftp-", "ftp://"); KUrl siteUrl(name); siteUrl.setUser(map["login"]); siteUrl.setPass(map["password"]); if (siteUrl.port() == 0) siteUrl.setPort(21); if (sites.contains(siteUrl) == 0) sites.append(siteUrl); } } } return sites; } QString Wallet::getPassword(const QString &whatFor) { if (!KWallet::Wallet::folderDoesNotExist(KWallet::Wallet::NetworkWallet(), "KFTPGrabber")) { // We have our own folder if (!m_wallet) { m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0, KWallet::Wallet::Synchronous); if (m_wallet) { m_walletRefCount++; connect(m_wallet, SIGNAL(walletClosed()), this, SLOT(slotWalletClosed())); } } // Try to read the password from the wallet QString pass; if (m_wallet && m_wallet->setFolder("KFTPGrabber") && m_wallet->readPassword(whatFor, pass) == 0) { return pass; } } return QString::null; } void Wallet::setPassword(const QString &whatFor, const QString &password) { if (KWallet::Wallet::isEnabled()) { if (!m_wallet) { m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), 0, KWallet::Wallet::Synchronous); if (m_wallet) { m_walletRefCount++; connect(m_wallet, SIGNAL(walletClosed()), this, SLOT(slotWalletClosed())); } } if (m_wallet) { // Create our folder if (!m_wallet->hasFolder("KFTPGrabber")) { m_wallet->createFolder("KFTPGrabber"); } m_wallet->setFolder("KFTPGrabber"); m_wallet->writePassword(whatFor, password); } } } } #include "wallet.moc" kftpgrabber-0.8.99~svn1214766/src/misc/config.kcfgc0000644000175000017500000000020511276037142021366 0ustar michaelmichaelFile=kftpgrabber.kcfg ClassName=Config Inherits=ConfigBase NameSpace=KFTPCore Singleton=true Mutators=true IncludeFiles=configbase.h kftpgrabber-0.8.99~svn1214766/src/misc/zeroconf.cpp0000644000175000017500000000447111276037142021464 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "zeroconf.h" #include namespace KFTPCore { class ZeroConfPrivate { public: ZeroConf instance; }; K_GLOBAL_STATIC(ZeroConfPrivate, zeroConfPrivate) ZeroConf *ZeroConf::self() { return &zeroConfPrivate->instance; } ZeroConf::ZeroConf() : QObject() { m_browser = new DNSSD::ServiceBrowser("_ftp._tcp", true); connect(m_browser, SIGNAL(finished()), this, SLOT(slotServiceChanged())); m_browser->startBrowse(); } ZeroConf::~ZeroConf() { } QList ZeroConf::getServiceList() const { return m_browser->services(); } void ZeroConf::slotServiceChanged() { emit servicesUpdated(); } } #include "zeroconf.moc" kftpgrabber-0.8.99~svn1214766/src/misc/interfaces/0000755000175000017500000000000011276037142021250 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/misc/interfaces/kftpbookmarkimportplugin.h0000644000175000017500000000566611276037142026602 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPBOOKMARKIMPORTPLUGIN_H #define KFTPBOOKMARKIMPORTPLUGIN_H #include #include /** * This class is the base class for all bookmark import plugins. * * @author Jernej Kos */ class KFTPINTERFACES_EXPORT KFTPBookmarkImportPlugin : public KParts::Plugin { Q_OBJECT public: KFTPBookmarkImportPlugin(QObject *parent); virtual ~KFTPBookmarkImportPlugin(); /** * This method should return the properly formated XML for KFTPGrabber * bookmarks that is generated from the import. * * @return The @ref QDomDocument representation of XML */ virtual QDomDocument getImportedXml() = 0; /** * This method should start the import procedure. * * @param fileName is the path to the file that will be imported */ virtual void import(const QString &fileName) = 0; /** * This method should return the default path where the bookmarks could * be located. The path must be relative to the user's home directory. * * @return The default path where bookmarks are located */ virtual QString getDefaultPath() = 0; protected: QString userPath(const QString &path); signals: /** * Progress of bookmark importing (in percent). */ void progress(int percent); }; #endif kftpgrabber-0.8.99~svn1214766/src/misc/interfaces/kftpbookmarkimportplugin.cpp0000644000175000017500000000376611276037142027134 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2004 by the KFTPGrabber developers * Copyright (C) 2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftpbookmarkimportplugin.h" #include KFTPBookmarkImportPlugin::KFTPBookmarkImportPlugin(QObject *parent) : KParts::Plugin(parent) { } KFTPBookmarkImportPlugin::~KFTPBookmarkImportPlugin() { } QString KFTPBookmarkImportPlugin::userPath(const QString &path) { return QDir::homePath() + "/" + path; } #include "kftpbookmarkimportplugin.moc" kftpgrabber-0.8.99~svn1214766/src/misc/interfaces/kftpinterfaces_export.h0000644000175000017500000000260111276037142026031 0ustar michaelmichael/* This file is part of the KDE project Copyright (C) 2007 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KFTPINTERFACES_EXPORT_H #define KFTPINTERFACES_EXPORT_H /* needed for KDE_EXPORT and KDE_IMPORT macros */ #include #ifndef KFTPINTERFACES_EXPORT # if defined(MAKE_LIBKFTPINTERFACES_LIB) /* We are building this library */ # define KFTPINTERFACES_EXPORT KDE_EXPORT # else /* We are using this library */ # define KFTPINTERFACES_EXPORT KDE_IMPORT # endif #endif # ifndef KFTPINTERFACES_EXPORT_DEPRECATED # define KFTPINTERFACES_EXPORT_DEPRECATED KDE_DEPRECATED KFTPINTERFACES_EXPORT # endif #endif kftpgrabber-0.8.99~svn1214766/src/misc/interfaces/CMakeLists.txt0000644000175000017500000000131711276037142024012 0ustar michaelmichaelINCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/kftpgrabber/src/ftp ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(kftpinterfaces_LIB_SRCS kftpbookmarkimportplugin.cpp ) kde4_add_library(kftpinterfaces SHARED ${kftpinterfaces_LIB_SRCS}) target_link_libraries(kftpinterfaces ${KDE4_KPARTS_LIBS} ${QT_QTCORE_LIBRARY}) set_target_properties(kftpinterfaces PROPERTIES VERSION ${GENERIC_LIB_VERSION} SOVERSION ${GENERIC_LIB_SOVERSION}) install(TARGETS kftpinterfaces ${INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install(FILES kftpbookmarkimportplugin.desktop DESTINATION ${SERVICES_INSTALL_DIR}) kftpgrabber-0.8.99~svn1214766/src/misc/interfaces/kftpbookmarkimportplugin.desktop0000644000175000017500000000473611556266066030033 0ustar michaelmichael[Desktop Entry] Type=Service X-KDE-ServiceType=KFTPGrabber/BookmarkImportPlugin Comment=A KFTPGrabber plugin for importing bookmarks Comment[bg]=Приставка за импортиране на отметки в KFTPGrabber Comment[cs]=Modul KFTPGrabbera pro import záložek Comment[da]=Et KFTGrabber-plugin til import af bogmærker Comment[de]=KFTPGrabber-Lesezeichenimportmodul Comment[el]=Ένα πρόσθετο του KFTPGrabber για την εισαγωγή σελιδοδεικτών Comment[en_GB]=A KFTPGrabber plugin for importing bookmarks Comment[es]=Un complemento de KFTPGrabber para importar marcadores Comment[et]=KFTPGrabberi järjehoidjate impordiplugin Comment[fi]=KFTPGrabber-liitännäinen kirjanmerkkien tuontiin Comment[fr]=Un module externe KFTPGrabber pour l'importation de signets Comment[ga]=Breiseán KFTPGrabber le haghaidh iompórtála leabharmharcanna Comment[gl]=Unha extensión de FTPGrabber para importar favoritos Comment[is]=KFTPGrabber íforrit fyrir innflutning bókamerkja Comment[it]=Un'estensione per importare i segnalibri per KFTPGrabber Comment[ja]=ブックマークをインポートする KFTPGrabber プラグイン Comment[km]=កម្មវិធី​ជំនួយ KFTPGrabber ដើម្បី​នាំចូល​ចំណាំ Comment[lt]=KFTPGrabber įskiepis žymelių importavimui Comment[lv]=KFTPGrabber grāmatzīmju importēšanas spraudnis Comment[nb]=Et programtillegg for KFTPGrabber, som importerer bopkmerker Comment[nds]=En KFTP-Moduul för't Importeren vun Leesteken Comment[nl]=een KFTPGrabber-plugin voor het importeren van bladwijzers Comment[pl]=Wtyczka KFTPGrabbera do importowania zakładek Comment[pt]=Um 'plugin' do KFTPGrabber para importar listas de favoritos Comment[pt_BR]=Um plug-in do KFTPGrabber para importação de favoritos Comment[ro]=Un modul KFTPGrabber pentru importul semnelor de carte Comment[ru]=Модуль KFTPGrabber для импорта закладок Comment[sv]=Ett insticksprogram för bokmärkesimport till KFTPgrabber Comment[th]=ปลั๊กอินสำหรับนำเข้าที่คั่นหนังสือของ KFTPGrabber Comment[tr]=Sık kullanılanları içeriye aktarmak için KFTPGrabber eklentisi Comment[uk]=Додаток до KFTPGrabber для імпорту закладок Comment[x-test]=xxA KFTPGrabber plugin for importing bookmarksxx Comment[zh_CN]=一个用于导入书签的 KFTPGrabber 插件 Comment[zh_TW]=用於匯入書籤的 KFTPGrabber 外掛程式 kftpgrabber-0.8.99~svn1214766/src/misc/wallet.h0000644000175000017500000000544711276037142020600 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCOREWALLET_H #define KFTPCOREWALLET_H #include #include namespace KFTPCore { class WalletPrivate; /** * Enables communication with KDE's wallet system (KWallet). * * @author Jernej Kos getSiteList(); /** * Returns a password stored in the wallet. * * @param whatFor Password key name */ QString getPassword(const QString &whatFor); /** * Stores a password to the wallet. * * @param whatFor Password key name * @param password Value */ void setPassword(const QString &whatFor, const QString &password); private: /** * Class constructor. */ Wallet(); /** * Class destructor. */ ~Wallet(); private: KWallet::Wallet *m_wallet; uint m_walletRefCount; private slots: void slotWalletClosed(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/0000755000175000017500000000000011276037142022161 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/misc/customcommands/entry.h0000644000175000017500000001370711276037142023503 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCORE_CUSTOMCOMMANDSENTRY_H #define KFTPCORE_CUSTOMCOMMANDSENTRY_H #include #include #include namespace KFTPSession { class Session; } namespace KFTPCore { namespace CustomCommands { /** * This class represents a single custom command entry. A tree of * such objects is constructed from an XML file. * * @author Jernej Kos */ class Entry : public QObject { Q_OBJECT public: /** * Possible parameter types. */ enum ParameterType { String, Password, Integer }; /** * Possible display types. */ enum DisplayType { None, Window, MessageBox }; /** * A single command parameter. */ class Parameter { public: /** * Class constructor. */ Parameter(); /** * Class constructor. * * @param type Parameter type * @param name Parameter name */ Parameter(ParameterType type, const QString &name); /** * Returns the parameter type. */ ParameterType type() const { return m_type; } /** * Returns the parameter name. */ QString name() const { return m_name; } private: ParameterType m_type; QString m_name; }; /** * Class constructor. * * @param name Short entry name */ Entry(QObject *parent, const QString &name); /** * Returns entry's name. */ QString name() const { return m_name; } /** * Returns entry's description. */ QString description() const { return m_description; } /** * Returns entry's icon name. */ QString icon() const { return m_icon; } /** * Sets entry's description. * * @param description A longer entry description; can be rich text */ void setDescription(const QString &description) { m_description = description; } /** * Set entry's icon. * * @param icon An icon name */ void setIcon(const QString &icon) { m_icon = icon; } /** * Sets the raw command to be sent. * * @param command A valid FTP command with optional parameter placeholders */ void setCommand(const QString &command) { m_command = command; } /** * Appends a command parameter. * * @param type Parameter type * @param name Human readable parameter name */ void appendParameter(ParameterType type, const QString &name); /** * Sets response display type. * * @param type Display type */ void setDisplayType(DisplayType type) { m_displayType = type; } /** * Sets the response handler to use. * * @param handler Handler name * @param args Optional argument node */ void setResponseHandler(const QString &handler, QDomNode args); /** * Executes this entry. This will actually generate and show a proper * user input dialog, execute the command with the provided parameters, * pass the raw response to a selected handler and properly display * the result. * * @param session A remote session where command should be executed */ void execute(KFTPSession::Session *session); private slots: void handleResponse(const QString &response); private: QString m_name; QString m_description; QString m_icon; QString m_command; QString m_handler; DisplayType m_displayType; QList m_params; QDomNode m_handlerArguments; KFTPSession::Session *m_lastSession; }; /** * This class is a wrapper action, so a proper entry gets pulled and * executed. * * @author Jernej Kos */ class EntryAction : public KAction { public: /** * Class constructor. * * @param entry Associated entry * @param session Associated session */ EntryAction(Entry *entry, KFTPSession::Session *session); /** * Returns the associated entry instance. */ Entry *entryInfo() const { return m_entryInfo; } /** * Returns the associated session instance. */ KFTPSession::Session *session() const { return m_session; } private: Entry *m_entryInfo; KFTPSession::Session *m_session; }; } } #endif kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/handlers.cpp0000644000175000017500000000522611276037142024472 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "handlers.h" #include #include namespace KFTPCore { namespace CustomCommands { namespace Handlers { Handler::Handler(const QString &name) : m_name(name) { } RawHandler::RawHandler() : Handler("Raw") { } SubstituteHandler::SubstituteHandler() : Handler("Substitue") { } QString SubstituteHandler::handleResponse(const QString &raw, QDomNode arguments) const { QString text = arguments.namedItem("text").toElement().text(); if (text.contains("%1")) return text.arg(raw); return text; } RegexpHandler::RegexpHandler() : Handler("Regexp") { } QString RegexpHandler::handleResponse(const QString &raw, QDomNode arguments) const { QString result; QRegExp e(arguments.namedItem("match").toElement().text()); if (e.exactMatch(raw.trimmed())) { result = arguments.namedItem("display").toElement().text(); for (int i = 1; i <= e.numCaptures(); i++) { result.replace(QString("\\%1").arg(i), e.cap(i)); } } return result; } } } } kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/commands.xml0000644000175000017500000000743711276037142024517 0ustar michaelmichael Shows current user aliases. SITE ALIAS Shows group information. SITE GRP %1 Group name Shows your current idle time. SITE IDLE Shows the users that are currently online. SITE WHO Shows the welcome screen. SITE WELCOME Sets your maximum idle time (in seconds). SITE IDLE %1 Idle time Idle time successfully changed. Changes your account password. SITE PASSWD %1 Password Password successfully changed. Removes a user from the server's user database. SITE DELUSER %1 Username User successfully removed. Changes a user's password. SITE CHPASS %1 %2 Username New password Password successfully changed. Terminates all connections for the specified user. SITE KICK %1 Username User has been kicked. kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/parameterentrydialog.h0000644000175000017500000000476011276037142026563 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCORE_CUSTOMCOMMANDSPARAMETERENTRYDIALOG_H #define KFTPCORE_CUSTOMCOMMANDSPARAMETERENTRYDIALOG_H #include #include #include "entry.h" namespace KFTPCore { namespace CustomCommands { /** * A dialog for parameter entry. * * @author Jernej Kos */ class ParameterEntryDialog : public KDialog { Q_OBJECT public: /** * Class constructor. * * @param entry An entry instance * @param params Parameter list */ ParameterEntryDialog(Entry *entry, QList params); /** * Properly replaces the parameter placeholders with actual user * entered values. * * @param command A command string with placeholders */ QString formatCommand(const QString &command); private: QList m_params; }; } } #endif kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/responsedialog.cpp0000644000175000017500000000411211276037142025701 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "responsedialog.h" #include namespace KFTPCore { namespace CustomCommands { ResponseDialog::ResponseDialog(const QString &caption, const QString &response) : KDialog(0) { setCaption(caption); setModal(true); setButtons(Ok); KTextEdit *contents = new KTextEdit(this); setMainWidget(contents); contents->setReadOnly(true); contents->append(response); setMinimumSize(500, 300); } } } kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/responsedialog.h0000644000175000017500000000427211276037142025355 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCORE_CUSTOMCOMMANDSRESPONSEDIALOG_H #define KFTPCORE_CUSTOMCOMMANDSRESPONSEDIALOG_H #include namespace KFTPCore { namespace CustomCommands { /** * A dialog for displaying operation results. * * @author Jernej Kos */ class ResponseDialog : public KDialog { public: /** * Class constructor. * * @param caption Dialog caption * @param response Response text (can be rich-text) */ ResponseDialog(const QString &caption, const QString &response); }; } } #endif kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/entry.cpp0000644000175000017500000001055311276037142024032 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "entry.h" #include "kftpsession.h" #include "manager.h" #include "parameterentrydialog.h" #include "responsedialog.h" #include #include namespace KFTPCore { namespace CustomCommands { Entry::Entry(QObject *parent, const QString &name) : QObject(parent), m_name(name) { } void Entry::appendParameter(ParameterType type, const QString &name) { m_params.append(Parameter(type, name)); } void Entry::setResponseHandler(const QString &handler, QDomNode args) { m_handler = handler; m_handlerArguments = args; } void Entry::execute(KFTPSession::Session *session) { // Create a dialog for parameter input QString command = m_command; if (m_params.count() > 0) { ParameterEntryDialog *dialog = new ParameterEntryDialog(this, m_params); if (dialog->exec() != QDialog::Accepted) { delete dialog; return; } command = dialog->formatCommand(command); delete dialog; } // Execute the command with proper parameters m_lastSession = session; connect(session->getClient()->eventHandler(), SIGNAL(gotRawResponse(const QString&)), this, SLOT(handleResponse(const QString&))); session->getClient()->raw(command); } void Entry::handleResponse(const QString &response) { if (!m_lastSession) return; m_lastSession->getClient()->eventHandler()->QObject::disconnect(this); m_lastSession = 0; // Invoke the proper handler QString expectedReturn = m_handlerArguments.namedItem("expected").toElement().attribute("code"); if (!response.startsWith(expectedReturn)) { KMessageBox::error(0, i18n("Requested operation has failed - response from server was:

%1
",response)); return; } Handlers::Handler *handler = Manager::self()->handler(m_handler); if (!handler) { KMessageBox::error(0, i18n("The handler named %1 cannot be found for response parsing.",m_handler)); return; } QString parsed = handler->handleResponse(response, m_handlerArguments); // Find the proper way to display the parsed response switch (m_displayType) { case None: return; case Window: { ResponseDialog *dialog = new ResponseDialog(m_name, parsed); dialog->exec(); delete dialog; break; } case MessageBox: { KMessageBox::information(0, parsed); break; } } } Entry::Parameter::Parameter() : m_type(String), m_name("") { } Entry::Parameter::Parameter(ParameterType type, const QString &name) : m_type(type), m_name(name) { } EntryAction::EntryAction(Entry *entry, KFTPSession::Session *session) : KAction(KIcon(entry->icon()), entry->name(), 0), m_entryInfo(entry), m_session(session) { } } } #include "entry.moc" kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/manager.h0000644000175000017500000000650411276037142023751 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCORE_CUSTOMCOMMANDSMANAGER_H #define KFTPCORE_CUSTOMCOMMANDSMANAGER_H #include #include #include #include #include #include "handlers.h" namespace KFTPSession { class Session; } namespace KFTPCore { namespace CustomCommands { class ManagerPrivate; /** * This class represents the entry manager. It parses the XML file and * creates the necessary entries. This class is a singleton. * * @author Jernej Kos */ class Manager : public QObject { Q_OBJECT friend class ManagerPrivate; public: /** * Returns a Manager instance. */ static Manager *self(); /** * Returns an appropriate handler. * * @param name Handler string identifier */ Handlers::Handler *handler(const QString &name) const; /** * Returns a KActionMenu that can be used for displaying categories of * entries to the user. */ KActionMenu *categories(const QString &name, KFTPSession::Session *session) const; public slots: /** * Loads a valid commands XML file. */ void load(); protected: static Manager *m_self; /** * Class constructor. */ Manager(); /** * Class destructor. */ ~Manager(); /** * Recursive entry parser. */ void parseEntries(KActionMenu *parentMenu, const QDomNode &parentNode, KFTPSession::Session *session) const; protected slots: /** * This slot gets called when an EntryAction is activated. */ void slotActionActivated(); private: KActionMenu *m_categories; QDomDocument m_document; QMap m_handlers; }; } } #endif kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/manager.cpp0000644000175000017500000001442011276037142024300 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "manager.h" #include "entry.h" #include #include #include #include #include #include namespace KFTPCore { namespace CustomCommands { class ManagerPrivate { public: Manager instance; }; K_GLOBAL_STATIC(ManagerPrivate, managerPrivate) Manager *Manager::self() { return &managerPrivate->instance; } Manager::Manager() : QObject() { // Populate the handlers list m_handlers["Raw"] = new Handlers::RawHandler(); m_handlers["Substitute"] = new Handlers::SubstituteHandler(); m_handlers["Regexp"] = new Handlers::RegexpHandler(); } Manager::~Manager() { // Destroy the handlers delete static_cast(m_handlers["Raw"]); delete static_cast(m_handlers["Substitute"]); delete static_cast(m_handlers["Regexp"]); m_handlers.clear(); } void Manager::load() { QString filename = KStandardDirs::locateLocal("appdata", "commands.xml"); if (!QFile::exists(filename)) { // Copy the default command set over QFile source(KStandardDirs::locate("appdata", "commands.xml")); QFile destination(filename); source.open(QIODevice::ReadOnly); destination.open(QIODevice::WriteOnly | QIODevice::Truncate); destination.write(source.readAll()); source.close(); destination.close(); } QFile file(filename); if (!file.open(QIODevice::ReadOnly)) return; m_document.setContent(&file); file.close(); } void Manager::parseEntries(KActionMenu *parentMenu, const QDomNode &parentNode, KFTPSession::Session *session) const { QDomNode n = parentNode.firstChild(); while (!n.isNull()) { if (n.isElement()) { QDomElement e = n.toElement(); QString tagName = e.tagName(); QString name = e.attribute("name"); if (tagName == "category") { KActionMenu *menu = new KActionMenu(KIcon("folder"), name, parentMenu); parentMenu->addAction(menu); // Recurse into this category parseEntries(menu, n, session); } else if (tagName == "entry") { Entry *entry = new Entry((Manager*) this, name); entry->setDescription(n.namedItem("description").toElement().text()); entry->setIcon(e.attribute("icon")); entry->setCommand(n.namedItem("command").toElement().text()); QDomNode p = n.namedItem("params").firstChild(); while (!p.isNull()) { QDomElement pElement = p.toElement(); if (pElement.tagName() == "param") { QString typeString = pElement.attribute("type"); Entry::ParameterType type = Entry::String; if (typeString == "String") type = Entry::String; else if (typeString == "Password") type = Entry::Password; else if (typeString == "Integer") type = Entry::Integer; entry->appendParameter(type, pElement.text()); } p = p.nextSibling(); } QDomElement rElement = n.namedItem("response").toElement(); entry->setResponseHandler(rElement.attribute("handler"), rElement); QString displayString = rElement.attribute("display"); Entry::DisplayType displayType = Entry::None; if (displayString == "None") displayType = Entry::None; else if (displayString == "Window") displayType = Entry::Window; else if (displayString == "MessageBox") displayType = Entry::MessageBox; entry->setDisplayType(displayType); // Create a new action EntryAction *action = new EntryAction(entry, session); connect(action, SIGNAL(activated()), this, SLOT(slotActionActivated())); parentMenu->addAction(action); } else if (tagName == "separator") { parentMenu->menu()->addSeparator(); } else { KMessageBox::error(0, i18n("Unknown tag while parsing custom site commands.")); } } n = n.nextSibling(); } } Handlers::Handler *Manager::handler(const QString &name) const { if (m_handlers.contains(name)) return m_handlers[name]; return 0; } KActionMenu *Manager::categories(const QString &name, KFTPSession::Session *session) const { KActionMenu *actionMenu = new KActionMenu(name, 0); parseEntries(actionMenu, m_document.documentElement(), session); return actionMenu; } void Manager::slotActionActivated() { EntryAction *action = (EntryAction*) QObject::sender(); action->entryInfo()->execute(action->session()); } } } #include "manager.moc" kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/CMakeLists.txt0000644000175000017500000000070611276037142024724 0ustar michaelmichaelINCLUDE_DIRECTORIES( ../.. ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(customcommands_SRCS handlers.cpp entry.cpp manager.cpp parameterentrydialog.cpp responsedialog.cpp ) kde4_add_library(customcommands STATIC ${customcommands_SRCS}) ########### install files ############### install(FILES commands.xml DESTINATION ${DATA_INSTALL_DIR}/kftpgrabber) kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/handlers.h0000644000175000017500000000761311276037142024141 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPCORE_CUSTOMCOMMANDS_HANDLERSHANDLERS_H #define KFTPCORE_CUSTOMCOMMANDS_HANDLERSHANDLERS_H #include #include namespace KFTPCore { namespace CustomCommands { namespace Handlers { /** * The handler class is an abstract class which every actual handler * must implement. * * @author Jernej Kos */ class Handler { public: /** * Class constructor. * * @param name Handler name */ Handler(const QString &name); /** * Class destructor. */ virtual ~Handler() {} /** * Returns the handler's name. */ QString name() const { return m_name; } /** * This method should be implemented by actual handlers to handler the * server response. * * @param raw Raw FTP response * @param arguments Any argument nodes supplied in the XML file * @return This method should return a formatted string */ virtual QString handleResponse(const QString &raw, QDomNode arguments) const = 0; private: QString m_name; }; /** * The Raw handler accepts no arguments and simply passes on raw data. * * @author Jernej Kos */ class RawHandler : public Handler { public: /** * Class constructor. */ RawHandler(); /** * @overload * Reimplemented from Handler. */ QString handleResponse(const QString &raw, QDomNode) const { return raw; } }; /** * The Substitue handler always returns a predefined value when the * operation is completed successfully. %1 can be used in place of the * raw data received from the server. * * @author Jernej Kos */ class SubstituteHandler : public Handler { public: /** * Class constructor. */ SubstituteHandler(); /** * @overload * Reimplemented from Handler. */ QString handleResponse(const QString &raw, QDomNode arguments) const; }; /** * The Regexp handler enables custom response parsing using regular * expressions. * * @author Jernej Kos */ class RegexpHandler : public Handler { public: /** * Class constructor. */ RegexpHandler(); /** * @overload * Reimplemented from Handler. */ QString handleResponse(const QString &raw, QDomNode arguments) const; }; } } } #endif kftpgrabber-0.8.99~svn1214766/src/misc/customcommands/parameterentrydialog.cpp0000644000175000017500000001137211276037142027113 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "parameterentrydialog.h" #include "entry.h" #include #include #include #include #include #include #include #include namespace KFTPCore { namespace CustomCommands { ParameterEntryDialog::ParameterEntryDialog(Entry *entry, QList params) : KDialog(0), m_params(params) { setCaption(entry->name()); setModal(true); setButtons(Ok | Cancel); QFrame *mainWidget = new QFrame(this); QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget); setMainWidget(mainWidget); QHBoxLayout *headerLayout = new QHBoxLayout(mainWidget); QLabel *icon = new QLabel(mainWidget); icon->setPixmap(DesktopIcon(entry->icon(), 32)); headerLayout->addWidget(icon); QVBoxLayout *headerTextLayout = new QVBoxLayout(mainWidget); headerTextLayout->addWidget(new QLabel(QString("%1").arg(entry->name()), mainWidget)); headerTextLayout->addWidget(new QLabel(entry->description(), mainWidget)); headerLayout->addLayout(headerTextLayout, 1); mainLayout->addLayout(headerLayout); mainLayout->addSpacing(5); QFrame *frame = new QFrame(mainWidget); frame->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); QVBoxLayout *frameLayout = new QVBoxLayout(frame); frameLayout->setMargin(10); mainLayout->addWidget(frame); int num = 0; QList::ConstIterator lend = params.constEnd(); for (QList::ConstIterator i = params.constBegin(); i != lend; ++i) { QHBoxLayout *layout = new QHBoxLayout(frame); QWidget *entryWidget = 0; QString name = QString("param_%1").arg(num++); switch ((*i).type()) { case Entry::String: entryWidget = new KLineEdit(frame); break; case Entry::Password: { entryWidget = new KLineEdit(frame); static_cast(entryWidget)->setPasswordMode(true); break; } case Entry::Integer: entryWidget = new KIntNumInput(frame); break; } entryWidget->setObjectName(name); // The first widget should have focus if (num == 1) entryWidget->setFocus(); layout->addWidget(new QLabel((*i).name() + ":", frame)); layout->addStretch(1); layout->addWidget(entryWidget); frameLayout->addLayout(layout); frameLayout->addSpacing(5); } setMaximumWidth(350); resize(350, minimumHeight()); } QString ParameterEntryDialog::formatCommand(const QString &command) { QString tmp = command; int num = 0; QList::ConstIterator lend = m_params.constEnd(); for (QList::ConstIterator i = m_params.constBegin(); i != lend; ++i) { QObject *entryWidget = findChild(QString("param_%1").arg(num++)); switch ((*i).type()) { case Entry::String: tmp = tmp.arg(static_cast(entryWidget)->text()); break; case Entry::Password: tmp = tmp.arg(static_cast(entryWidget)->text()); break; case Entry::Integer: tmp = tmp.arg(static_cast(entryWidget)->value()); break; } } return tmp; } } } #include "parameterentrydialog.moc" kftpgrabber-0.8.99~svn1214766/src/misc/pluginmanager.cpp0000644000175000017500000000473411276037142022472 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "pluginmanager.h" #include "kftpbookmarkimportplugin.h" #include #include using namespace KParts; namespace KFTPCore { class PluginManagerPrivate { public: PluginManager instance; }; K_GLOBAL_STATIC(PluginManagerPrivate, pluginManagerPrivate) PluginManager *PluginManager::self() { return &pluginManagerPrivate->instance; } PluginManager::PluginManager() : QObject() { } PluginManager::~PluginManager() { } void PluginManager::loadPlugins() { } KService::List PluginManager::getImportPlugins() { return KServiceTypeTrader::self()->query("KFTPGrabber/BookmarkImportPlugin"); } KFTPBookmarkImportPlugin *PluginManager::loadImportPlugin(const KService::Ptr &service) { return ComponentFactory::createPartInstanceFromService(service, 0, this); } } kftpgrabber-0.8.99~svn1214766/src/misc/CMakeLists.txt0000644000175000017500000000075511276037142021674 0ustar michaelmichaelADD_SUBDIRECTORY( interfaces ) ADD_SUBDIRECTORY( plugins ) ADD_SUBDIRECTORY( customcommands ) INCLUDE_DIRECTORIES( .. interfaces ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(misc_SRCS wallet.cpp pluginmanager.cpp zeroconf.cpp configbase.cpp filter.cpp filterwidgethandler.cpp certificatestore.cpp ) kde4_add_kcfg_files(misc_SRCS config.kcfgc) kde4_add_library(misc STATIC ${misc_SRCS}) kftpgrabber-0.8.99~svn1214766/src/misc/configbase.cpp0000644000175000017500000000715111276037142021735 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "configbase.h" #include "config.h" #include "filter.h" #include #include #include #include #include namespace KFTPCore { ConfigBase::ConfigBase(const QString &fileName) : KConfigSkeleton(fileName) { m_fileExistsDownActions.setTypeText(i18n("Download")); m_fileExistsUpActions.setTypeText(i18n("Upload")); m_fileExistsFxpActions.setTypeText(i18n("FXP")); m_transMode = 'I'; } void ConfigBase::postInit() { // Restore the actions QString tmp = Config::downloadActions(); tmp >> m_fileExistsDownActions; tmp = Config::uploadActions(); tmp >> m_fileExistsUpActions; tmp = Config::fxpActions(); tmp >> m_fileExistsFxpActions; } void ConfigBase::saveConfig() { // Save actions before writing QString tmp; tmp << m_fileExistsDownActions; Config::setDownloadActions(tmp); tmp << m_fileExistsUpActions; Config::setUploadActions(tmp); tmp << m_fileExistsFxpActions; Config::setFxpActions(tmp); // Save filters Filter::Filters::self()->save(); // Write the config writeConfig(); } void ConfigBase::emitChange() { emit configChanged(); } char ConfigBase::ftpMode(const QString &filename) { // Get FTP mode (binary/ascii) switch (m_transMode) { case 'A': return 'A'; break; case 'I': return 'I'; break; case 'X': default: { char mode = 'I'; QRegExp e; e.setPatternSyntax(QRegExp::Wildcard); QStringList list = Config::asciiList(); QStringList::iterator end(list.end()); for (QStringList::iterator i(list.begin()); i != end; ++i) { e.setPattern((*i)); if (e.exactMatch(filename)) { mode = 'A'; break; } } return mode; } } } QString ConfigBase::getGlobalMail() { KEMailSettings kes; kes.setProfile(kes.defaultProfileName()); return kes.getSetting(KEMailSettings::EmailAddress); } } #include "configbase.moc" kftpgrabber-0.8.99~svn1214766/src/fileexistsactions.cpp0000644000175000017500000001122711276037142022441 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "fileexistsactions.h" #include #include #include #include #include #include namespace KFTPQueue { QString &operator<<(QString &s, const FileExistsActions &a) { s.truncate(0); ActionMap::ConstIterator end( a.m_actions.end() ); for (ActionMap::ConstIterator i(a.m_actions.begin()); i != end; ++i) { s.append(QString("%1;").arg(i.value())); } return s; } QString &operator>>(QString &s, FileExistsActions &a) { for (unsigned int i = 0; i < 9; i++) { a.m_actions[i+1] = static_cast(s.section(';', i, i).toInt()); } return s; } QWidget *FileExistsActions::getConfigWidget(QWidget *parent) { QGroupBox *gb = new QGroupBox(i18n("On File Exists Actions (%1)", m_type), parent); QGridLayout *gl = new QGridLayout(gb); const int m = KDialog::marginHint(); gl->setSpacing(KDialog::spacingHint()); gl->setContentsMargins(m, m, m, m); QLabel *l = new QLabel(i18n("Size/Timestamp"), gb); gl->addWidget(l, 1, 0); l = new QLabel(i18n("Same"), gb); gl->addWidget(l, 1, 1); l = new QLabel(i18n("Older"), gb); gl->addWidget(l, 1, 2); l = new QLabel(i18n("Newer"), gb); gl->addWidget(l, 1, 3); l = new QLabel(i18n("Same"), gb); gl->addWidget(l, 2, 0); l = new QLabel(i18n("Smaller"), gb); gl->addWidget(l, 3, 0); l = new QLabel(i18n("Bigger"), gb); gl->addWidget(l, 4, 0); for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { KComboBox *cb = new KComboBox(gb); m_combos[row][col] = cb; cb->addItem(i18n("Skip")); cb->addItem(i18n("Overwrite")); cb->addItem(i18n("Resume")); cb->addItem(i18n("Rename")); cb->addItem(i18n("Ask")); cb->setCurrentIndex(m_actions[row * 3 + col + 1]); gl->addWidget(cb, row+2, col+1); } } return gb; } void FileExistsActions::updateWidget() { for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { m_combos[row][col]->setCurrentIndex(m_actions[row * 3 + col + 1]); } } } void FileExistsActions::updateConfig() { for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { m_actions[row * 3 + col + 1] = static_cast(m_combos[row][col]->currentIndex()); } } } FEAction FileExistsActions::getActionForSituation(filesize_t src_fileSize, time_t src_fileTimestamp, filesize_t dst_fileSize, time_t dst_fileTimestamp) { // There are 9 different scenarios int situation = -1; if (dst_fileTimestamp == src_fileTimestamp) { // SAME TIMESTAMP situation = 1; } else if (dst_fileTimestamp < src_fileTimestamp) { // OLDER situation = 2; } else { // NEWER situation = 3; } if (dst_fileSize < src_fileSize) { // SMALLER FILE situation += 3; } else if (dst_fileSize > src_fileSize) { // BIGGER FILE situation += 6; } // Situation calculated, now get the action return m_actions[situation]; } } kftpgrabber-0.8.99~svn1214766/src/hi16-app-kftpgrabber.png0000644000175000017500000000152411276037142022516 0ustar michaelmichaelPNG  IHDRaIDATxuYhQLI$ Ѷ6.A/"Ҋ*R7Q|( .AA\PZtLic$Lf2,N ˽{/j0m[=J6Y\\l*`bGs]jŒ˚Z{7oj[`>EQ&z*@EAD|aNw_23:݄a&t*%C:o!1 D¾AR/|ܝ_z|2qpR"gPZ[!ʮZ"&;ƣkDO(7("ܩ&Ȕz(LxޙY5A'h aQQWdha^Q"ig]>iM FFpx\Q.X?>@"]0Ϝ ;& Y2 gCfbX5T(!;MRpˣC[6)sf|Á@B,䴈Q.QgOHfd%XӝH,+*jy_s.klhf?ج/48PXnw-y:aPd!s\.$]㑷6>Rim]z쩎1Ĵ"P9O s`4 =޶`8[otM}IJTIGM}daBDhbd$T B~)Pudž{bF 7!硡eIENDB`kftpgrabber-0.8.99~svn1214766/src/kftptransfer.h0000644000175000017500000002326211276037142021061 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUEKFTPTRANSFER_H #define KFTPQUEUEKFTPTRANSFER_H #include "queueobject.h" #include #include #include #include namespace KFTPSession { class Session; class Connection; } namespace KFTPQueue { enum TransferType { Download = 0, Upload = 1, FXP = 2 }; class TransferFile; /** * This class represents a failed transfer. Such a transfer is removed * from queue so the error message can later be examined and the transfer * restarted. * * @author Jernej Kos */ class FailedTransfer : public QObject { Q_OBJECT public: /** * Constructs a new failed transfer object. The actual transfer * will be reparented (the FailedTransfer object will become its * parent). */ FailedTransfer(QObject *parent, TransferFile *transfer, const QString &error); ~FailedTransfer(); /** * Returns the error message. * * @return The error message. */ QString getError() const { return m_error; } /** * Add this transfer back to the queue. The FailedTransfer object * will be destroyed afterwards! * * @return Pointer to the TransferFile object that was just restored. */ TransferFile *restore(); /** * Returns the actual transfer object that failed. This transfer is * marked as failed so execute() method can't be called! * * @return A KFTPQueue::TransferFile object. */ TransferFile *getTransfer() const { return m_transfer; } /** * Use this method to declare a transfer as failed. The transfer will * be aborted, removed from queue and added to the failed transfer * list. * * @param transfer Pointer to the transfer object that failed. * @param error The error that ocurred. */ static void fail(TransferFile *transfer, const QString &error); private: QPointer m_transfer; QString m_error; }; /** * This class is the base class for all transfers used in KFTPGrabber. It * provides some basic methods that are extended by KFTPQueue::TransferFile and * KFTPQueue::TransferDir for specific file or dir operations. * * @author Jernej Kos */ class Transfer : public QueueObject { friend class FailedTransfer; friend class TransferDir; friend class Manager; friend class KFTPSession::Session; friend class KFTPSession::Connection; Q_OBJECT public: Transfer(QObject *parent, Type type); ~Transfer(); /** * Returns the source KUrl of this transfer. * * @return Source url */ KUrl getSourceUrl() const { return m_sourceUrl; } /** * Returns the destination KUrl of this transfer. * * @return Destination url */ KUrl getDestUrl() const { return m_destUrl; } /** * Set the source KUrl of this transfer. * * @param url Source url wannabe */ void setSourceUrl(const KUrl &url) { m_sourceUrl = url; } /** * Set the destination url of this transfer. * * @param url Destination url wannabe */ void setDestUrl(const KUrl &url) { m_destUrl = url; } /** * Return the KFTPQueue::TransferType -- that is if this transfer is an Upload, Download * or FXP transfer. * * @return Upload, Download or FXP */ TransferType getTransferType() const { return m_transferType; } /** * Set current KFTPQueue::TransferType -- that is Upload, Download or FXP * * @param type Upload, Download or FXP */ void setTransferType(TransferType type) { m_transferType = type; } /** * Get the source session for this transfer. * * @return A valid KFTPSession::Session instance or 0 if not started */ KFTPSession::Session *getSourceSession() const { return m_srcSession; } /** * Get the destination session for this transfer. * * @return A valid KFTPSession::Session instance or 0 if not started */ KFTPSession::Session *getDestinationSession() const { return m_dstSession; } /** * Returns the connection opposite of one that is passed. So if you * pass the source connection, the destination one is returned and * vice-versa. * * @param conn The connection * @return The opposite Connection */ KFTPSession::Connection *getOppositeConnection(KFTPSession::Connection *conn); /** * Returns the remote connection. If both connections are remote, this * method returns the source connection. * * @return The remote connection */ KFTPSession::Connection *remoteConnection(); /** * Is this transfer a child of another transfer ? * * @return true if this transfer is a child of another KFTPQueue::Transfer */ bool hasParentTransfer() const { return parent()->inherits("KFTPQueue::Transfer"); } /** * Should a transfered file be automagicly opened after transfer ? This only applies for * download transfers. * * @param value The setting */ void setOpenAfterTransfer(bool value) { m_openAfterTransfer = value; } /** * Is this transfer marked for deletion ? * * @return true if this transfer is marked for deletion */ bool isDeleteMarked() const { return m_deleteMe; } /** * Get the transfer's parent transfer. * * @return Transfer's parent or NULL if isChild() returns false */ Transfer *parentTransfer(); /** * Lock this transfer for further changes. */ void lock(); /** * Unlock a previously locked transfer. */ void unlock(); /** * Abort current transfer. */ virtual void abort(); /** * Just emits the objectUpdated() signal. */ void emitUpdate() { emit objectUpdated(); } /** * Assign sessions to this transfer in advance (= before starting the * actual transfer). Both sessions must have free connections. If you * pass NULL to both parameters sessions will be looked up and might * be spawned. * * Note that the sessions MUST be the right ones based on the transfer's * URL, otherwise unexpected results will ocurr! * * @param source The source session * @param destination The destination session * @return True if the sessions are ready for immediate use */ virtual bool assignSessions(KFTPSession::Session *source = 0, KFTPSession::Session *destination = 0); /** * This method returns true if both connections have been properly * initialized. */ bool connectionsReady(); protected: bool m_deleteMe; bool m_openAfterTransfer; TransferType m_transferType; /* Source/destination URL */ KUrl m_sourceUrl; KUrl m_destUrl; /* Transfer sessions */ KFTPSession::Session *m_srcSession; KFTPSession::Session *m_dstSession; /* Source/destination connections */ KFTPSession::Connection *m_srcConnection; KFTPSession::Connection *m_dstConnection; int m_retryCount; void showTransCompleteBalloon(); void resetTransfer(); void update(); bool canMove(); /** * This method gets called just before the transfer is removed. * * @param abortSession If true any session that this transfer is using is aborted */ void faceDestruction(bool abortSession = true); /** * Initialize the specified session for use with this transfer. * * @param session The session to use * @return A valid Connection or NULL if one wasn't available */ KFTPSession::Connection *initializeSession(KFTPSession::Session *session); /** * Deinitialize currently acquired connections. Do not call this method * unless you know what you are doing. */ void deinitializeConnections(); private slots: void slotConnectionAvailable(); void slotConnectionConnected(); signals: void transferStart(long id); void transferComplete(long id); void transferAbort(long id); }; } Q_DECLARE_METATYPE(KFTPQueue::FailedTransfer*) #endif kftpgrabber-0.8.99~svn1214766/src/site.h0000644000175000017500000000500011276037142017302 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUESITE_H #define KFTPQUEUESITE_H #include "queueobject.h" #include namespace KFTPQueue { /** * This class represents a site. * * @author Jernej Kos */ class Site : public QueueObject { Q_OBJECT public: /** * Class constructor. * * @param parent The parent object * @param url The site's URL */ Site(QueueObject *parent, KUrl url); /** * Return the site's URL * * @return The URL for this site */ KUrl getUrl() const { return m_siteUrl; } /** * Process all child transfers, one by one (just like in TransferDir). */ void execute(); /** * Abort transfer processing. */ void abort(); private: KUrl m_siteUrl; QueueGroup *m_group; private slots: void slotGroupInterrupted(); signals: void siteAborted(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/kftpsession.h0000644000175000017500000004302311276037142020715 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPSESSION_H #define KFTPSESSION_H #include #include #include #include #include #include #include "kftpqueue.h" #include "widgets/logview.h" #include "engine/thread.h" namespace KFTPWidgets { namespace Browser { class Actions; class View; } } namespace KFTPBookmarks { class Site; } namespace KFTPSession { class Session; enum Side { LeftSide, RightSide, IgnoreSide }; #define oppositeSide(x) (x == KFTPSession::LeftSide ? KFTPSession::RightSide : KFTPSession::LeftSide) /** * The Connection class represents a session's connection to a ftp server. There * can be many connections in the same session (to the same server), thus providing * support for multiple threads at once. * * Individual transfers must acquire connections before they can use them. When a * connection is acquired it cannot be used by another transfer or another remote * operation. * * @author Jernej Kos */ class Connection : public QObject { Q_OBJECT public: /** * Class constructor. * * @param session The parent session * @param primary Set to true if this is session's primary connection */ Connection(Session *session, bool primary = false); /** * Class destructor. */ ~Connection(); /** * Returns the client thread for this connection. * * @return A KFTPClientThr object representing a client. */ KFTPEngine::Thread *getClient() const { return m_client; } /** * Returns the URL this connection is connected to. * * @return A KUrl this connection is connected to. */ KUrl getUrl() { return m_client->socket()->getCurrentUrl(); } /** * Returns the current transfer if this connection is locked by one. If * it isn't locked NULL will be returned. */ KFTPQueue::Transfer *getTransfer() const { return m_transfer; } /** * Lock this connection for a specific transfer. While the connection is * locked no other transfer may use it. The connection will be automaticly * unlocked when the transfer completes. * * @param transfer The transfer which is locking this connection. */ void acquire(KFTPQueue::Transfer *transfer); /** * Release existing connection lock. Only the transfer who locked the connection * should do this! */ void release(); /** * Abort any actions going via this connection. It will call abort on the * underlying client and emit the aborting signal. */ void abort(); /** * Connect to the previously connected URL. If this connection is already * established this method does nothing. */ void reconnect(); /** * Can this connection be used to perform an operation ? * * @return Returns true if the current connection is busy, false otherwise. */ bool isBusy() const; /** * Is the current connection actually connected to a server ? * * @return Returns true if a connection to a server is established. */ bool isConnected(); /** * Is the current connection the primary session connection ? * * @return Returns true if the current connection is primary, false otherwise */ bool isPrimary() const { return m_primary; } /** * Scans a directory - usually called from KFTPSession for remote scans. * * @param parent The transfer that requested the scan */ void scanDirectory(KFTPQueue::Transfer *parent); private: void addScannedDirectory(KFTPEngine::DirectoryTree *tree, KFTPQueue::Transfer *parent); private: bool m_primary; bool m_busy; bool m_aborting; bool m_scanning; QPointer m_transfer; KFTPEngine::Thread *m_client; private slots: void slotTransferCompleted(); void slotEngineEvent(KFTPEngine::Event *event); signals: /** * This signal gets emitted when the connection is acquired for exclusive * use by a transfer. */ void connectionAcquired(); /** * This signal gets emitted when connection is returned to the pool and is * no longer locked. */ void connectionRemoved(); /** * This signal gets emitted when the connection is lost. * * @param connection This connection instance */ void connectionLost(KFTPSession::Connection *connection); /** * This signal gets emitted when connection with the remote server is * established. */ void connectionEstablished(); /** * This signal gets emitted when this connection is in the process of * aborting any currently running operations. */ void aborting(); }; /** * A Session instance connects all the relevant elements together. Via the * manager this abstraction allows many independent sessions inside one * applications. * * Each session can either be local or remote. A remote session can have * multiple connections open (each connection is represented by a Connection * instance). * * @author Jernej Kos */ class Session : public QObject { Q_OBJECT friend class KFTPWidgets::Browser::Actions; friend class Manager; friend class Connection; public: /** * Class constructor. * * @param side The side the session should be located on */ Session(Side side); /** * Class destructor. */ ~Session(); /** * Has the session registration procedure already been completed ? * * @return True if the registration procedure has been completed, false otherwise */ bool isRegistred() const { return m_registred; } /** * Is this a remote session ? * * @return Returns true if this is a remote session. */ bool isRemote() const { return m_remote; } /** * Is this session currently active (=visible to the user) ? * * @return Returns true if this session is currently active. */ bool isActive() const { return m_active; } /** * Is this session currently connected to a server ? This actually checks if * the primary connection is connected to a server. * * @return Returns true if this session is connected to a server. */ bool isConnected(); /** * Get the site in bookmarks this session is asociated with or NULL if there * is no such site. * * @return Returns the asociated bookmarks site. */ KFTPBookmarks::Site *getSite() const { return m_site; } /** * Returns the session opposite this one. */ Session *oppositeSession() const; /** * Get the session's client thread. This actually returns the client thread * of the primary session's connection. * * @return A KFTPEngine::Thread object representing a client. */ KFTPEngine::Thread *getClient(); /** * Get this session's log widget. * * @return Returns the session's log widget. */ KFTPWidgets::LogView *getLog() const { return m_log; } /** * Get this session's file view. * * @return Returns the session's file view. */ KFTPWidgets::Browser::View *getFileView() const { return m_fileView; } /** * Get the side on which this session is located. * * @return Returns the session's side. */ Side getSide() const { return m_side; } /** * Set bookmark site asociation. * * @param site A valid site to which this session is asociated. */ void setSite(KFTPBookmarks::Site *site) { m_site = site; } /** * Are there any free connections (or if some new can be created) to lock ? * * @return Returns true if there is a connection that can be locked. */ bool isFreeConnection(); /** * Assigns a free connection if there is one. A connection can be created if * the limit hasn't yet been reached. If there are no free connections this * method returns NULL. * * @return A free Connection or NULL if there is none. */ Connection *assignConnection(); /** * Disconnects all connections for this session. */ void disconnectAllConnections(); /** * Get the list of current connections for this session. * * @return A list of current connections. */ QList *getConnectionList() { return &m_connections; } /** * Reconnect to a new URL. The current connections will be droped and reconnected * to the new URL. * * @param url The URL to connect to. */ void reconnect(const KUrl &url); /** * Abort this session. This will actually call abort on all connections for * this session. */ void abort(); /** * Initiate a directory scan, adding all new files and directories under the * transfer specified as parent. This method will change the current transfer's * status to Locked and will return imediately. The actual scan will take * place in a separate thread. * * @param parent The transfer which requested the scan * @param connection An optional connection to use */ void scanDirectory(KFTPQueue::Transfer *parent, Connection *connection = 0); /** * Returns the URL of the primary connection. */ KUrl getUrl() { return getClient()->socket()->getCurrentUrl(); } private: Side m_side; bool m_remote; bool m_active; bool m_aborting; bool m_registred; // Session description KFTPBookmarks::Site *m_site; KFTPWidgets::LogView *m_log; KFTPWidgets::Browser::View *m_fileView; KUrl m_lastUrl; KUrl m_reconnectUrl; // Connection list QList m_connections; int getMaxThreadCount(); private slots: void slotClientEngineEvent(KFTPEngine::Event *event); void slotStartReconnect(); signals: void dirScanDone(); void aborting(); void freeConnectionAvailable(); }; typedef QList SessionList; /** * The Manager class provides access to sessions, their registration and deletion. * * @author Jernej Kos */ class Manager : public QObject { Q_OBJECT public: /** * Get a global manager instance. */ static Manager *self(); /** * Class constructor. * * @param parent Parent object * @param stat A widget that contains log tabs * @param left A widget that contains sessions on the left side * @param right A widget that contains sessions on the right side */ Manager(QObject *parent, QTabWidget *stat, KTabWidget *left, KTabWidget *right); /** * Spawn a new local (=unconnected) session. This method may reuse an old local session. * * @param side The side on which the session should be created. * @param forceNew Should a new session be created if a similar session already exists. * @return Allways returns a valid session. */ Session *spawnLocalSession(Side side, bool forceNew = false); /** * Spawn a new remote session. This method may reuse an old remote session. It may also * spawn a new local session if the URL appears local. * * @param side The side on which the session should be created. * @param remoteUrl URL to which the session should connect upon creation. * @param site The bookmarked site the session is connecting to. * @param mustUnlock Must the returned session be unlocked ? * @return Allways returns a valid session. */ Session *spawnRemoteSession(Side side, const KUrl &remoteUrl, KFTPBookmarks::Site *site = 0, bool mustUnlock = false); /** * Register a new session with the session manager. Every session calls this method in * its constructor to init the session - this method shouldn't be called otherwise. * * @param session A new session. */ void registerSession(Session *session); /** * Destroy the session. All connections and transfers related to this session are * aborted and disconnected first. * * @param session The session that is going to be destroyed. */ void unregisterSession(Session *session); /** * Disconnects all sessions and their connections. */ void disconnectAllSessions(); /** * Find a session related to a client thread. * * @param client The client thread related to a session. * @return Returns a valid session if one is found, NULL otherwise. */ Session *find(KFTPEngine::Thread *client); /** * Find a session related to a file view widget. * * @param fileView The file view widget related to a session. * @return Returns a valid session if one is found, NULL otherwise. */ Session *find(KFTPWidgets::Browser::View *fileView); /** * Find a session related to a log widget. * * @param log The log widget related to a session. * @return Returns a valid session if one is found, NULL otherwise. */ Session *find(KFTPWidgets::LogView *log); /** * Find a session by the url it is connected to. * * @param url The URL a session is connected to. * @param mustUnlock Must the session be unlocked ? * @return Returns a valid session if one is found, NULL otherwise. */ Session *find(const KUrl &url, bool mustUnlock = false); /** * Finds a session by its state (remote/local). * * @param local Must a session be local ? * @return Returns a valid session if one is found, NULL otherwise. */ Session *find(bool local); /** * Finds a session that was last connected to a specific URL that is placed * on a specific side. * * @param url The URL to which the session was connected to. * @param side The side where the session must be. * @return Returns a valid session if one is found, NULL otherwise. */ Session *findLast(const KUrl &url, Side side); /** * Get the list of all sessions in existance. * * @return The session list. */ SessionList *getSessionList() { return &m_sessionList; } /** * Emits the update signal. */ void doEmitUpdate(); /** * Returns the tab widget that holds the log widgets. * * @return Returns a QTabWidget that holds the log widgets. */ QTabWidget *getStatTabs() const { return m_statTabs; } /** * Returns the tab widget that holds the sessions on a specific side. * * @param side The side of the tab widget. * @return Returns a KTabWidget that holds the sessions. */ KTabWidget *getTabs(Side side); /** * Make a session active (=visible to the user). * * @param session Session to be made active. */ void setActive(Session *session); /** * Get the active session on a specific side. * * @param side The side where the session is active. * @return Returns a valid session. */ Session *getActive(Side side); /** * Get the currently active view. * * @return The active view instance */ KFTPWidgets::Browser::View *getActiveView(); /** * Get the currently active session. */ Session *getActiveSession(); protected: static Manager *m_self; /** * Event filter handler. */ bool eventFilter(QObject *object, QEvent *event); /** * Change the currently active session to the browser view inheriting * the passed object. * * @param object The object that has browser view as some parent */ void switchFocusToObject(const QObject *object); private: SessionList m_sessionList; // These variables should be assigned right after construction QTabWidget *m_statTabs; KTabWidget *m_leftTabs; KTabWidget *m_rightTabs; // Currently active sessions Session *m_active; Session *m_leftActive; Session *m_rightActive; private slots: void slotActiveChanged(QWidget *page); void slotSwitchFocus(); public slots: void slotSessionCloseRequest(QWidget *page); signals: void update(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/mainwindow.h0000644000175000017500000000705711276037142020530 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * Copyright (C) 2004 Markus Brueffer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef MAINWINDOW_H_ #define MAINWINDOW_H_ #include #include #include #include namespace KFTPWidgets { namespace Bookmarks { class Sidebar; } class ConfigDialog; class TrafficGraph; class QueueView; } /** * @short Application Main Window * @author Jernej Kos */ class MainWindow : public KXmlGuiWindow { Q_OBJECT public: /** * Class constructor. */ MainWindow(); /** * Class destructor. */ ~MainWindow(); protected: /** * Setup main window actions. */ void setupActions(); /** * Initialize the traffic graph widget. */ void initTrafficGraph(); /** * Initialize the status bar. */ void initStatusBar(); /** * Create the main user interface. */ void initMainView(); /** * Initialize sidebars. */ void initSidebars(); /** * This method gets called when the user attempts to close the * application. */ bool queryClose(); private: QTimer *m_graphTimer; KFTPWidgets::TrafficGraph *m_trafficGraph; KFTPWidgets::QueueView *m_queueView; KFTPWidgets::ConfigDialog *m_configDialog; public slots: void initBookmarkMenu(); private slots: /** * Does a delayed loading of stuff that can take some time to load. */ void slotLoader(); void appShutdown(); void showBookmarkEditor(); void slotUpdateStatusBar(); void slotUpdateTrafficGraph(); void slotConfigChanged(); void slotFileQuit(); void slotQuickConnect(); void slotNewSessionLeft(); void slotNewSessionRight(); void slotSettingsSave(); void slotSettingsConfig(); void slotModeAscii(); void slotModeBinary(); void slotModeAuto(); }; #endif kftpgrabber-0.8.99~svn1214766/src/statistics.h0000644000175000017500000000616411276037142020544 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUESTATISTICS_H #define KFTPQUEUESTATISTICS_H #include #include #include #include namespace KFTPQueue { class StatisticsPrivate; /** * This class represents a statistics for a single site. * * @author Jernej Kos */ class StatisticsSite { public: StatisticsSite(); /** * Set the site's last FXP speed. * * @param speed Site's last FXP speed */ void setLastFxpSpeed(double speed) { m_lastFxpSpeed = speed; } /** * Get the site's last FXP speed. * * @return Site's last FXP speed */ double lastFxpSpeed() const { return m_lastFxpSpeed; } private: double m_lastFxpSpeed; }; /** * This class provides different kind of per-site statistics. * * @author Jernej Kos */ class Statistics : public QObject { Q_OBJECT friend class StatisticsPrivate; public: /** * Returns the global statistics class instance. */ static Statistics *self(); /** * Returns a site that corresponds to the given URL. If the site doesn't * exist it is created. * * @param url The site's URL * @return A valid StatisticsSite pointer */ StatisticsSite *getSite(const KUrl &url); protected: /** * Class constructor. */ Statistics(); /** * Class destructor. */ ~Statistics(); private: QMap m_sites; }; } #endif kftpgrabber-0.8.99~svn1214766/src/kftpbookmarks.cpp0000644000175000017500000010646011276037142021562 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftpbookmarks.h" #include "kftpqueue.h" #include "kftpsession.h" #include "misc/config.h" #include "misc/wallet.h" #include "misc/zeroconf.h" #include "engine/thread.h" #include "engine/settings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KFTPCore; Q_DECLARE_METATYPE(QSslCertificate) Q_DECLARE_METATYPE(QSslKey) namespace KFTPBookmarks { Site::Site(Manager *manager, QDomNode node) { // Use the specified node as data source refresh(manager, node); } Site::~Site() { } void Site::refresh(Manager *manager, QDomNode node) { m_manager = manager; m_element = node.toElement(); if (m_element.tagName() == "category") { m_type = ST_CATEGORY; if (getAttribute("id").isEmpty()) setAttribute("id", QString("cat-%1").arg(KRandom::randomString(7)), false); } else if (m_element.tagName() == "server") { m_type = ST_SITE; if (getAttribute("id").isEmpty()) setAttribute("id", QString("site-%1").arg(KRandom::randomString(7)), false); } else if (m_element.tagName() == "sites") { m_type = ST_ROOT; return; } // Set the id m_id = getAttribute("id"); } Site *Site::duplicate() { if (m_type == ST_ROOT || m_type == ST_CATEGORY) return 0; Site *site = new Site(m_manager, m_element.cloneNode()); site->setAttribute("name", i18n("Copy of") + " " + getAttribute("name"), false); site->setAttribute("id", QString::null, false); site->refresh(m_manager, site->m_element); m_element.parentNode().appendChild(site->m_element); m_manager->cacheSite(site); emit m_manager->siteAdded(site); return site; } void Site::reparentSite(Site *site) { if (site->isRoot()) return; // Move site's parent emit m_manager->siteRemoved(site); m_element.appendChild(site->m_element); emit m_manager->siteAdded(site); } Site *Site::addSite(const QString &name) { QDomElement node = m_element.ownerDocument().createElement("server"); // Create a new site Site *site = new Site(m_manager, node); site->setAttribute("name", name, false); m_element.appendChild(site->m_element); m_manager->cacheSite(site); emit m_manager->siteAdded(site); site->setProperty("protocol", ProtoFtp); site->setProperty("port", 21); return site; } void Site::addCategory(const QString &name) { QDomElement cat = m_element.ownerDocument().createElement("category"); // Create a new category Site *site = new Site(m_manager, cat); site->setAttribute("name", name, false); m_element.appendChild(cat); m_manager->cacheSite(site); emit m_manager->siteAdded(site); } KUrl Site::getUrl() { KUrl url; // Properly translate the protocol value switch (protocol()) { case ProtoFtp: url.setProtocol("ftp"); break; case ProtoSftp: url.setProtocol("sftp"); break; } url.setHost(getProperty("host")); url.setPort(getIntProperty("port")); url.setUser(getProperty("username")); url.setPass(getProperty("password")); return url; } Site *Site::getParentSite() { QDomNode parentNode = m_element.parentNode(); if (parentNode.isNull()) return 0; else return m_manager->siteForNode(parentNode); } Site *Site::child(int index) { if (m_type == ST_CATEGORY || m_type == ST_ROOT) { QDomNode childNode = m_element.childNodes().at(index); if (!childNode.isNull()) return m_manager->siteForNode(childNode); } return 0; } int Site::index() const { if (m_type == ST_ROOT) return 0; QDomNodeList children = m_element.parentNode().childNodes(); for (int i = 0; i < children.size(); i++) { if (children.at(i) == m_element) return i; } Q_ASSERT(false); return -1; } uint Site::childCount() const { return (m_type == ST_CATEGORY || m_type == ST_ROOT) ? m_element.childNodes().size() : 0; } QString Site::getProperty(const QString &name) const { if (m_type != ST_SITE) return QString::null; QDomNodeList nodes = m_element.elementsByTagName(name); if (nodes.length() > 0) { QString property = nodes.item(0).toElement().text(); property.trimmed(); // Transparently decode passwords if (name == "password") property = KCodecs::base64Decode(property.toAscii()).data(); return property; } else { return QString::null; } } int Site::getIntProperty(const QString &name) const { return getProperty(name).toInt(); } void Site::setProperty(const QString &name, const QString &value) { if (m_type != ST_SITE) return; // First delete the old property if it exists QDomNodeList nodes = m_element.elementsByTagName(name); if (nodes.length() > 0) m_element.removeChild(nodes.item(0)); // Transparently encode passwords if (name == "password") const_cast(value) = KCodecs::base64Encode(value.toAscii(), true).data(); // Now add a new one QDomElement property = m_element.ownerDocument().createElement(name); m_element.appendChild(property); QDomText text = m_element.ownerDocument().createTextNode(value); property.appendChild(text); emit m_manager->siteChanged(this); } void Site::setProperty(const QString &name, int value) { setProperty(name, QString::number(value)); } void Site::setAttribute(const QString &name, const QString &value, bool notify) { m_element.setAttribute(name, value); if (notify) emit m_manager->siteChanged(this); } QString Site::getAttribute(const QString &name) const { return m_element.attribute(name); } //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// class ManagerPrivate { public: Manager instance; }; K_GLOBAL_STATIC(ManagerPrivate, managerPrivate) Manager *Manager::self() { return &managerPrivate->instance; } Manager::Manager() : QObject(), m_rootSite(0) { // Init the DOM document m_document = QDomDocument("KFTPgrabber"); } Manager::Manager(const Manager *bookmarks) : QObject(), m_rootSite(0) { // Init the DOM document m_document = QDomDocument("KFTPgrabber"); // Copy the bookmarks QDomNode tmp = m_document.importNode(bookmarks->m_document.documentElement(), true); m_document.appendChild(tmp); } Manager::~Manager() { qDeleteAll(m_siteCache); delete m_rootSite; } void Manager::setBookmarks(KFTPBookmarks::Manager *bookmarks) { // Init the DOM document m_document = QDomDocument("KFTPgrabber"); QDomNode tmp = m_document.importNode(bookmarks->m_document.documentElement(), true); m_document.appendChild(tmp); // Refresh all sites in the cache to use the new nodes foreach (Site *site, m_siteCache) { QDomNode node = findSiteElementById(site->id()); if (!node.isNull()) site->refresh(this, node); } // Refresh all sites in the foreign cache to use the new nodes foreach (Site *site, bookmarks->m_siteCache) { QDomNode node = findSiteElementById(site->id()); if (!node.isNull()) site->refresh(this, node); } // Clear foreign cache to prevent site pointer deletion bookmarks->m_siteCache.clear(); emit update(); } void Manager::importSites(QDomNode node) { QDomNode import = m_document.importNode(node, true); m_document.documentElement().appendChild(import); // Run sanity checks to generate missing ids Manager::validate(); } void Manager::load(const QString &filename) { m_filename = filename; QFile file(filename); if (!file.open(QIODevice::ReadOnly)) { // Create a new empty XML m_document.setContent(QString("").arg(KFTP_BOOKMARKS_VERSION)); return; } // Check if the file is encrpyted QByteArray content = file.readAll(); if (Config::encryptBookmarks()) { // File is encrypted bool saveToWallet = false; QString password = Wallet::self()->getPassword("bookmarkDecryptPwd"); if (password.isNull()) { // Ask the user for a password KPasswordDialog dialog(0, KPasswordDialog::ShowKeepPassword); dialog.setPrompt(i18n("This bookmark file is encrypted. Please enter key for decryption.")); if (!dialog.exec()) password = ""; else password = dialog.password(); } KMessageBox::error(0, "ENCRYPTED BOOKMARK FILE NOT YET REIMPLEMENTED! ALL BOOKMARKS WILL BE LOST UNLESS YOU KILL THE APPLICATION NOW!"); content = ""; // TODO use QCA #if 0 // Try to decrypt DESEncryptor des; des.setKey(p_pass); des.decrypt(content); if (des.output().left(6) != "walletConnection()->setPassword("bookmarkDecryptPwd", QString::null); if (KMessageBox::warningContinueCancel( KFTPAPI::getInstance()->mainWindow(), i18n("Bookmark file decryption has failed with provided key. Do you want to overwrite bookmarks with an empty file?

Warning: If you overwrite, all current bookmarks will be lost.
"), i18n("Decryption Failed"), KGuiItem(i18n("&Overwrite Bookmarks")) ) != KMessageBox::Continue) { // Request the password again goto passwordEntry; } // Create new empty XML m_document.setContent(QString("").arg(KFTP_BOOKMARKS_VERSION)); file.close(); return; } // Save the password for later encryption m_decryptKey = p_pass; content = des.output().ascii(); if (saveToWallet) { // Save the password to KWallet KFTPAPI::getInstance()->walletConnection()->setPassword("bookmarkDecryptPwd", p_pass); } #endif } m_document.setContent(QString::fromLocal8Bit(content)); file.close(); // Check for XML document version updates versionUpdate(); // Document validation Manager::validate(); // We have just loaded the bookmarks, so update all the menus emit update(); } void Manager::save() { // Save the new XML file if (m_filename.isEmpty()) return; QFile file(m_filename); if (!file.open(QIODevice::WriteOnly)) return; // Should we encrypt the data ? QString content = m_document.toString(); if (Config::encryptBookmarks()) { KMessageBox::error(0, "ENCRYPTED BOOKMARK FILE NOT YET REIMPLEMENTED! ALL BOOKMARKS WILL BE LOST UNLESS YOU KILL THE APPLICATION NOW!"); #if 0 DESEncryptor des; if (m_decryptKey.isEmpty()) { // Ask the user for the password KPasswordDialog::getPassword(m_decryptKey, i18n("Enter key for bookmark file encryption.")); } des.setKey(m_decryptKey); des.encrypt(content); content = des.output(); #endif } // Write the XML data to the stream QTextStream fileStream(&file); fileStream << content; file.flush(); file.close(); } void Manager::validate(QDomNode node) { if (node.isNull()) node = m_document.documentElement(); QDomNode n = node.firstChild(); while (!n.isNull()) { if (n.toElement().tagName() == "category") { if (!n.toElement().hasAttribute("id")) n.toElement().setAttribute("id", QString("cat-%1").arg(KRandom::randomString(7))); Manager::validate(n); } else if (n.toElement().tagName() == "server") { if (!n.toElement().hasAttribute("id")) n.toElement().setAttribute("id", QString("site-%1").arg(KRandom::randomString(7))); } n = n.nextSibling(); } } void Manager::versionUpdate() { int version = m_document.documentElement().attribute("version").toInt(); if (version < KFTP_BOOKMARKS_VERSION) { // Conversion from an old bookmark file - save backup QFile file(KStandardDirs::locateLocal("appdata", "bookmarks.bak")); if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { file.write(m_document.toByteArray()); file.close(); } // NOTE: There are no breaks here, since every update method updates to a specific // version. So in order to convert to the most current from the oldest version, all // methods need to be called! switch (version) { case 0: case 1: versionFrom1Update(); case 2: versionFrom2Update(); } // Fix the version m_document.documentElement().setAttribute("version", KFTP_BOOKMARKS_VERSION); QString message = i18n("Bookmarks have been successfully converted from a previous version format.

In case an unexpected problem has occurred during this conversion process, a backup version of your old-format bookmarks has been saved to the following location:
%1.", file.fileName()); if (version <= 2) { message += "

" + i18n("Please note that since encoding names have changed in KDE4 all charset settings might be incorrect and you will have to change them to proper values."); } KMessageBox::information(0, "" + message + "", i18n("Bookmarks Converted")); } } void Manager::versionFrom1Update(QDomNode parent) { // The original format had no site ids, so we have to generate them. Also the old // format used something wierd called "options", we have to convert them as well. // The username/password fields now have differend names. if (parent.isNull()) parent = m_document.documentElement(); QDomNode n = parent.firstChild(); while (!n.isNull()) { if (n.toElement().tagName() == "category") { // Update the category id and all children n.toElement().setAttribute("id", QString("cat-%1").arg(KRandom::randomString(7))); versionFrom1Update(n); } else if (n.toElement().tagName() == "server") { // Update the server id n.toElement().setAttribute("id", QString("site-%1").arg(KRandom::randomString(7))); // Convert the "options" QDomNodeList nodes = n.toElement().elementsByTagName("option"); if (nodes.length() > 0) { for (int i = 0; i < nodes.count(); i++) { QDomNode node = nodes.item(i); // Add a new standard property QDomElement property = m_document.createElement(node.toElement().attribute("name")); n.appendChild(property); QDomText text = m_document.createTextNode(node.toElement().attribute("value")); property.appendChild(text); // And remove the option :> node.parentNode().removeChild(node); i--; } } // Rename the username/password fields nodes = n.toElement().elementsByTagName("downuser"); if (nodes.length() > 0) { for (int i = 0; i < nodes.count(); i++) { QDomNode node = nodes.item(i); node.toElement().setTagName("username"); } } nodes = n.toElement().elementsByTagName("downpass"); if (nodes.length() > 0) { for (int i = 0; i < nodes.count(); i++) { QDomNode node = nodes.item(i); node.toElement().setTagName("password"); } } } n = n.nextSibling(); } } void renameField(QDomNode n, const QString &name, const QString &newName) { QDomNodeList nodes = n.toElement().elementsByTagName(name); if (nodes.length() > 0) { for (int i = 0; i < nodes.count(); i++) { QDomNode node = nodes.item(i); node.toElement().setTagName(newName); } } } void removeField(QDomNode n, const QString &name) { QDomNodeList nodes = n.toElement().elementsByTagName(name); if (nodes.length() > 0) { for (int i = 0; i < nodes.count(); i++) { QDomNode node = nodes.item(i); node.parentNode().removeChild(node); } } } QString retrieveField(QDomNode n, const QString &name) { QDomNodeList nodes = n.toElement().elementsByTagName(name); if (nodes.length() > 0) { QString property = nodes.item(0).toElement().text(); return property.trimmed(); } return QString::null; } void changeField(QDomNode n, const QString &name, const QString &value) { // First delete the old property if it exists QDomNodeList nodes = n.toElement().elementsByTagName(name); if (nodes.length() > 0) n.toElement().removeChild(nodes.item(0)); // Transparently encode passwords if (name == "password") const_cast(value) = KCodecs::base64Encode(value.toAscii(), true).data(); // Now add a new one QDomElement property = n.toElement().ownerDocument().createElement(name); n.toElement().appendChild(property); QDomText text = n.toElement().ownerDocument().createTextNode(value); property.appendChild(text); } void Manager::versionFrom2Update(QDomNode parent) { // Version 2 format had some nasty properties that have to be renamed and // converted. if (parent.isNull()) parent = m_document.documentElement(); QDomNode n = parent.firstChild(); while (!n.isNull()) { if (n.toElement().tagName() == "category") { versionFrom2Update(n); } else if (n.toElement().tagName() == "server") { // Convert the protocol field QString protocol = retrieveField(n, "protocol"); int convertedProtocol = Site::ProtoFtp; if (protocol == "ftp") convertedProtocol = Site::ProtoFtp; else if (protocol == "sftp") convertedProtocol = Site::ProtoSftp; changeField(n, "protocol", QString::number(convertedProtocol)); // Rename/remove SSL fields int negotiationMode = Site::SslNone; if (retrieveField(n, "use_tls").toInt()) negotiationMode = Site::SslAuthTLS; if (retrieveField(n, "use_implicit").toInt()) negotiationMode = Site::SslImplicit; QString useCert = retrieveField(n, "use_cert"); if (useCert == "false") changeField(n, "use_cert", "0"); else if (useCert == "true") changeField(n, "use_cert", "1"); changeField(n, "sslNegotiationMode", QString::number(negotiationMode)); renameField(n, "use_cert", "sslCertificateEnabled"); renameField(n, "tls_cert_path", "sslCertificatePath"); renameField(n, "tls_data_mode", "sslProtMode"); removeField(n, "use_tls"); removeField(n, "use_implicit"); removeField(n, "tls_mode"); // Rename retry fields renameField(n, "doRetry", "retryEnabled"); renameField(n, "retrytime", "retryDelay"); renameField(n, "retrycount", "retryCount"); // Rename keepalive fields renameField(n, "doKeepalive", "keepaliveEnabled"); renameField(n, "keepaliveTimeout", "keepaliveFrequency"); // Rename path fields renameField(n, "deflocalpath", "pathLocal"); renameField(n, "defremotepath", "pathRemote"); // Rename anonymous field renameField(n, "anonlogin", "anonymous"); // Remove distributed FTPd field (it is autodetected anyway) removeField(n, "dist_ftpd"); // Fix disable threads field QString disableThreads = retrieveField(n, "disableThreads"); if (disableThreads == "true") changeField(n, "disableThreads", "1"); else if (disableThreads == "false") changeField(n, "disableThreads", "0"); } n = n.nextSibling(); } } Site *Manager::siteForNode(QDomNode node) { QString id = node.toElement().attribute("id"); Site *site = m_siteCache.value(id); if (!site) { site = new Site(this, node); m_siteCache.insert(site->id(), site); } return site; } void Manager::cacheSite(Site *site) { m_siteCache.insert(site->id(), site); } Site *Manager::rootSite() { if (!m_rootSite) m_rootSite = new Site(this, m_document.documentElement()); return m_rootSite; } Site *Manager::findSite(const KUrl &url) { // Find the node, then see if it is already present in the cache QDomNode siteElement = findSiteElementByUrl(url); if (!siteElement.isNull()) { // Try to get a cached version Site *site = m_siteCache.value(siteElement.toElement().attribute("id")); if (!site) { site = new Site(this, siteElement); m_siteCache.insert(siteElement.toElement().attribute("id"), site); } return site; } else { return NULL; } } Site *Manager::findSite(const QString &id) { if (id.isNull()) return NULL; // Try the cache first Site *site = m_siteCache.value(id); if (!site) { // The site was not found, search in the DOM tree and add it to the // cache if found. QDomNode siteElement = findSiteElementById(id); if (siteElement.isNull()) return NULL; site = new Site(this, siteElement); m_siteCache.insert(id, site); } return site; } QDomNode Manager::findSiteElementByUrl(const KUrl &url, QDomNode parent) { if (parent.isNull()) parent = m_document.documentElement(); QDomNode n = parent.firstChild(); while (!n.isNull()) { if (n.toElement().tagName() == "category") { // Check the category QDomNode site = findSiteElementByUrl(url, n); if (!site.isNull()) return site; } else if (n.toElement().tagName() == "server") { // Check if the server matches Site *tmp = new Site(this, n); if (tmp->getProperty("host") == url.host() && tmp->getIntProperty("port") == url.port() && tmp->getProperty("username") == url.user() && tmp->getProperty("password") == url.pass()) { delete tmp; return n; } delete tmp; } n = n.nextSibling(); } return QDomNode(); } QDomNode Manager::findSiteElementById(const QString &id, QDomNode parent) { if (parent.isNull()) parent = m_document.documentElement(); QDomNode n = parent.firstChild(); while (!n.isNull()) { if (n.toElement().tagName() == "category") { // Check the category QDomNode site = findSiteElementById(id, n); if (!site.isNull()) return site; } else if (n.toElement().tagName() == "server") { // Check if the server matches if (n.toElement().attribute("id") == id) return n; } n = n.nextSibling(); } return QDomNode(); } QDomNode Manager::findCategoryElementById(const QString &id, QDomNode parent) { if (id == "root") return m_document.documentElement(); if (parent.isNull()) parent = m_document.documentElement(); QDomNode n = parent.firstChild(); while (!n.isNull()) { if (n.toElement().tagName() == "category") { if (n.toElement().attribute("id") == id) return n; // Check the category QDomNode site = findCategoryElementById(id, n); if (!site.isNull()) return site; } n = n.nextSibling(); } return QDomNode(); } Site *Manager::findCategory(const QString &id) { // Try the cache first Site *site = m_siteCache.value(id); if (!site) { // The site was not found, search in the DOM tree and add it to the // cache if found. QDomNode siteElement = findCategoryElementById(id); if (siteElement.isNull()) return NULL; site = new Site(this, siteElement); m_siteCache.insert(id, site); } return site; } void Manager::removeSite(Site *site) { emit siteRemoved(site); // Remove the node from the DOM tree site->m_element.parentNode().removeChild(site->m_element); // Remove the site from cache and it will be automaticly deleted m_siteCache.remove(site->id()); emit update(); } void Manager::setupClient(Site *site, KFTPEngine::Thread *client, KFTPEngine::Thread *primary) { KFTPEngine::Settings *settings = client->settings(); settings->initConfig(); if (site) { if (site->getIntProperty("retryEnabled")) { settings->setConfig("retry", true); settings->setConfig("max_retries", site->getIntProperty("retryCount")); settings->setConfig("retry_delay", site->getIntProperty("retryDelay")); } else { settings->setConfig("retry", false); } settings->setConfig("keepalive.enabled", site->getIntProperty("keepaliveEnabled")); settings->setConfig("keepalive.timeout", site->getIntProperty("keepaliveFrequency")); settings->setConfig("encoding", site->getProperty("encoding")); if (site->protocol() == Site::ProtoFtp) { settings->setConfig("feat.pasv", site->getIntProperty("disablePASV") != 1); settings->setConfig("feat.epsv", site->getIntProperty("disableEPSV") != 1); settings->setConfig("pasv.use_site_ip", site->getIntProperty("pasvSiteIp")); settings->setConfig("active.no_force_ip", site->getIntProperty("disableForceIp")); settings->setConfig("stat_listings", site->getIntProperty("statListings")); if (site->getIntProperty("sslNegotiationMode") != Site::SslNone) { settings->setConfig("ssl.use_tls", true); if (site->getIntProperty("sslNegotiationMode") == Site::SslImplicit) settings->setConfig("ssl.use_implicit", true); settings->setConfig("ssl.prot_mode", site->getIntProperty("sslProtMode")); if (primary) { // A primary client has been given, so this is a secondary connection settings->setConfig("ssl.ignore_errors", true); settings->setConfig("ssl.certificate", primary->settings()->getConfig("ssl.certificate")); settings->setConfig("ssl.private_key", primary->settings()->getConfig("ssl.private_key")); } else if (site->getIntProperty("sslCertificateEnabled")) { // Ask the user for the decryption password QString password; KPasswordDialog dialog; dialog.setPrompt(i18n("Please provide your SSL private key decryption password.")); if (dialog.exec()) password = dialog.password(); // Load certificate and private key QFile file(site->getProperty("sslKeyfilePath")); if (!file.open(QIODevice::ReadOnly)) { KMessageBox::error(0, i18n("Unable to open local private key file.")); } else { QSslCertificate certificate = QSslCertificate::fromPath(site->getProperty("sslCertificatePath")).first(); QSslKey key(&file, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, password.toAscii()); if (!certificate.isValid() || key.isNull()) { KMessageBox::error(0, i18n("Local SSL certificate and/or private key is not valid.")); } else { QVariant certificateVariant; certificateVariant.setValue(certificate); QVariant keyVariant; keyVariant.setValue(key); settings->setConfig("ssl.certificate", certificateVariant); settings->setConfig("ssl.private_key", keyVariant); } } } } } else if (site->protocol() == Site::ProtoSftp) { if (primary) { // A primary client has been given, so this is a secondary connection settings->setConfig("auth.ignore_fingerprint", true); settings->setConfig("auth.privkey_password", primary->settings()->getConfig("auth.privkey_password")); } // Should we use public key authentication ? if (site->getIntProperty("sshPubkeyAuth")) { QString pubkeyPath = site->getProperty("sshPublicKey"); QString privkeyPath = site->getProperty("sshPrivateKey"); if (!QFileInfo(pubkeyPath).exists() || !QFileInfo(privkeyPath).exists()) { if (!primary) KMessageBox::error(0, i18n("SSH public or private key file does not exist - pubkey authentication disabled.")); } else { settings->setConfig("auth.pubkey", true); settings->setConfig("auth.pubkey_path", pubkeyPath); settings->setConfig("auth.privkey_path", privkeyPath); } } } } } QList Manager::populateBookmarksMenu(KActionMenu *parentMenu, KFTPSession::Session *session) { QList list; QQueue > categoryQueue, siteQueue; categoryQueue.enqueue(qMakePair(m_document.documentElement(), parentMenu)); // Create all the categories while (!categoryQueue.isEmpty()) { QPair category = categoryQueue.dequeue(); QDomNode n = category.first.firstChild(); while (!n.isNull()) { QDomElement e = n.toElement(); if (e.tagName() == "category") { KActionMenu *menu; if (category.second) { menu = new KActionMenu(KIcon("folder-bookmarks"), e.attribute("name"), category.second); category.second->addAction(menu); } else { menu = new KActionMenu(KIcon("folder-bookmarks"), e.attribute("name"), this); list.append(menu); } categoryQueue.enqueue(qMakePair(e, menu)); } else if (e.tagName() == "server") { siteQueue.enqueue(qMakePair(e, category.second)); } n = n.nextSibling(); } } // Now insert all sites while (!siteQueue.isEmpty()) { QPair site = siteQueue.dequeue(); BookmarkActionData actionData; actionData.siteId = site.first.attribute("id"); actionData.session = session; QVariant dataVariant; dataVariant.setValue(actionData); KAction *action = site.second ? new KAction(site.second) : new KAction(this); action->setText(site.first.attribute("name")); action->setIcon(KIcon("bookmarks")); action->setData(dataVariant); connect(action, SIGNAL(triggered()), this, SLOT(slotBookmarkExecuted())); if (site.second) site.second->addAction(action); else list.append(action); } return list; } void Manager::populateZeroconfMenu(KActionMenu *parentMenu) { // Clear the menu parentMenu->menu()->clear(); QList list = ZeroConf::self()->getServiceList(); if (!list.empty()) { foreach (DNSSD::RemoteService::Ptr p, list) { KUrl url; url.setHost(p->hostName()); url.setPort(p->port()); KAction *action = new KAction(this); action->setText(p->serviceName()); action->setIcon(KIcon("network-workgroup")); action->setData(url); connect(action, SIGNAL(triggered), this, SLOT(slotZeroconfExecuted())); parentMenu->addAction(action); } } else { KAction *disabledAction = new KAction(this); disabledAction->setText(i18n("")); disabledAction->setEnabled(false); parentMenu->addAction(disabledAction); } } void Manager::populateWalletMenu(KActionMenu *parentMenu) { // Clear the menu parentMenu->menu()->clear(); // Populate QList list = Wallet::self()->getSiteList(); if (!list.empty()) { foreach (KUrl url, list) { QString desc; if (url.port() != 21) desc = QString("%1@%2:%3").arg(url.user()).arg(url.host()).arg(url.port()); else desc = QString("%1@%2").arg(url.user()).arg(url.host()); KAction *action = new KAction(this); action->setText(desc); action->setIcon(KIcon("folder-remote")); action->setData(url); connect(action, SIGNAL(triggered()), this, SLOT(slotWalletExecuted())); parentMenu->addAction(action); } } else { KAction *disabledAction = new KAction(this); disabledAction->setText(i18n("")); disabledAction->setEnabled(false); parentMenu->addAction(disabledAction); } } void Manager::slotBookmarkExecuted() { // Get the sender KAction *action = (KAction*) QObject::sender(); BookmarkActionData data = action->data().value(); Site *site = findSite(data.siteId); connectWithSite(site, data.session); } void Manager::connectWithSite(Site *site, KFTPSession::Session *session) { // Get the node data from bookmarks KUrl siteUrl = site->getUrl(); // Handle empty usernames and passwords for non-anonymous sites if (!siteUrl.hasUser() || (!siteUrl.hasPass() && siteUrl.user() != "anonymous" && (site->protocol() != Site::ProtoSftp || !site->getIntProperty("sshPubkeyAuth")) ) ) { KPasswordDialog *dlg = new KPasswordDialog(0, KPasswordDialog::ShowUsernameLine | KPasswordDialog::ShowKeepPassword); dlg->setPrompt(i18n("Please provide your username and password for connecting to this site.")); dlg->addCommentLine(i18n("Site:"), QString("%1:%2").arg(siteUrl.host()).arg(siteUrl.port())); dlg->setUsername(siteUrl.user()); if (dlg->exec()) { siteUrl.setUser(dlg->username()); siteUrl.setPass(dlg->password()); if (dlg->keepPassword()) { // Save password to the bookmarked site site->setProperty("username", dlg->username()); site->setProperty("password", dlg->password()); } delete dlg; } else { // Abort connection attempt delete dlg; return; } } if (session) { // Set the correct client for connection KFTPEngine::Thread *client = session->getClient(); // Now, connect to the server if (session->isRemote() && session->isConnected()) { if (Config::confirmDisconnects() && KMessageBox::warningYesNo(0, i18n("Do you want to drop current connection?")) == KMessageBox::No) return; } client->socket()->setCurrentUrl(siteUrl); // Set the session's site and connect session->setSite(site); session->reconnect(siteUrl); } else { // Just spawn a new session session = KFTPSession::Manager::self()->spawnRemoteSession(KFTPSession::IgnoreSide, siteUrl, site); KFTPSession::Manager::self()->setActive(session); } } void Manager::slotWalletExecuted() { // Get the sender KAction *action = (KAction*) QObject::sender(); // Just spawn a new session KFTPSession::Manager::self()->spawnRemoteSession(KFTPSession::IgnoreSide, action->data().value()); } void Manager::slotZeroconfExecuted() { // Get the sender KAction *action = (KAction*) QObject::sender(); KUrl url = action->data().value(); // FIXME //KFTPAPI::getInstance()->mainWindow()->slotQuickConnect("", url.host(), url.port()); } } #include "kftpbookmarks.moc" kftpgrabber-0.8.99~svn1214766/src/hi32-app-kftpgrabber.png0000644000175000017500000000423011276037142022511 0ustar michaelmichaelPNG  IHDR szz_IDATxWkl=ٝ>c2H4& OX_8ݻS{P/ 24MBf]p`}PD|r9;"wl$:vG[Uivhc!V"XS sbܰ,껜oϋ>Sk$E?RNA e`3 Aq La10dHQ<+ɻGqL"\S1ꁮN:,S tK!3i`{ PU>D,M#[8zn!4uAmq0Y*&5# v{ KZUSJKиh 4L΍>f$Y.\St~@1!h!08 Z` we-th̜h&\ P) ZEc/<9EUC%렖kQj9ʚ .`:2Us@Fe @ ʞ-ec8׀ȹ,`Hh0\<]@1sXѠy (*q` hX)l0Un$ KdPS䇔>H_z=uW gr^+r`HCLM~mr$V!dbį2)LSX;s^kIqIQ.IRfJ'-]s8kƒ. QfZe f"s@JC~=֓1&`iCf&H mlLEnyKHڵ~?zdVi$;CP9 I%NͤN+!&#; ce% ȓ3A\82:l6NMq%?{-KQ~SEF8hd7e&\Ȳ!wOQS~t-&%'@U޷ς<?aBG2: d@& 5*LJ0T!tRNzJ2>ȉ%!%~'U4R+El1 x6ls+9p![& 1u lEơ܀MĨ<>O?䛳 bݪe]ߊ Ə{wdoyp9Z E1+A].9 &d+{ ֽE{4ǂ sQB*X[Y+}. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUEKFTPTRANSFERDIR_H #define KFTPQUEUEKFTPTRANSFERDIR_H #include "kftptransfer.h" class DirectoryScanner; namespace KFTPQueue { /** * This class represents a queued directory transfer. It can have child transfers that * will be executed one by one, when this transfer is executed. * * @author Jernej Kos */ class TransferDir : public Transfer { Q_OBJECT public: /** * Possible transfer execution modes (= actions that can be executed when * the execute() method gets called). * * The following modes are supported: * Default - just executes the transfer * Ignore - does nothing but releases all connections * ScanOnly - starts a directory scan and switches to Ignore * ScanWithExecute - starts a directory scan and switches to Default */ enum ExecutionMode { Default, Ignore, ScanOnly, ScanWithExecute }; /** * Class constructor. * * @param parent The parent object */ TransferDir(QObject *parent); /** * @overload * Reimplemented from KFTPQueue::Transfer. */ void execute(); /** * @overload * Reimplemented from KFTPQueue::Transfer. */ void abort(); /** * Initiates a directory scan. This method will do nothing if there are * existing children or the scan has already been initiated. */ void scan(); private: bool m_scanned; QueueGroup *m_group; DirectoryScanner *m_srcScanner; ExecutionMode m_executionMode; private slots: void slotGroupDone(); void slotGroupInterrupted(); void slotDirScanDone(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/kftpqueueprocessor.h0000644000175000017500000000452711276037142022324 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUEPROCESSOR_H #define KFTPQUEUEPROCESSOR_H #include #include #include #include namespace KFTPQueue { class Site; } /** @author Jernej Kos */ class KFTPQueueProcessor : public QObject { friend class KFTPQueueManager; Q_OBJECT public: KFTPQueueProcessor(QObject *parent); void startProcessing(); void stopProcessing(); bool isRunning(); private: QPointer m_activeSite; bool m_running; void processActiveSite(); bool nextSite(); private slots: void slotSiteComplete(); void slotSiteAborted(); signals: void queueComplete(); void queueAborted(); }; #endif kftpgrabber-0.8.99~svn1214766/src/Messages.sh0000755000175000017500000000031311276037142020275 0ustar michaelmichael#! /usr/bin/env bash $EXTRACTRC `find . -name \*.ui -o -name \*.rc -o -name \*.kcfg` >> rc.cpp $XGETTEXT `find . -name \*.cc -o -name \*.cpp -o -name \*.h` rc.cpp -o $podir/kftpgrabber.pot rm -f rc.cpp kftpgrabber-0.8.99~svn1214766/src/kftptransferfile.h0000644000175000017500000000717111276037142021722 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUEKFTPTRANSFERFILE_H #define KFTPQUEUEKFTPTRANSFERFILE_H #include #include "kftptransfer.h" namespace KFTPSession { class Connection; } namespace KFTPEngine { class Event; class FileExistsWakeupEvent; } namespace KFTPQueue { /** * This class represents a queued file transfer. * * @author Jernej Kos */ class TransferFile : public Transfer { Q_OBJECT friend class Manager; public: /** * Class constructor. * * @param parent The parent object */ TransferFile(QObject *parent); /** * Wakes this transfer up after the action for the file exists situation * has been decided. The event is simply relayed to the underlying socket. * * @param event Event instance or 0 if nothing should be delivered */ void wakeup(KFTPEngine::FileExistsWakeupEvent *event); /** * @overload * Reimplemented from KFTPQueue::QueueObject. */ void execute(); /** * @overload * Reimplemented from KFTPQueue::Transfer. */ void abort(); /** * @overload * Reimplemented from KFTPQueue::Transfer. * * @param source The source session * @param destination The destination session * @return True if the sessions are ready for immediate use */ bool assignSessions(KFTPSession::Session *source = 0, KFTPSession::Session *destination = 0); private: /* Update timers */ QTimer *m_updateTimer; QTimer *m_dfTimer; /* FXP */ QTime m_elapsedTime; /** * @overload * Reimplemented from KFTPQueue::Transfer. */ void resetTransfer(); private slots: void slotTimerUpdate(); void slotTimerDiskFree(); void slotDiskFree(const QString &mountPoint, unsigned long kBSize, unsigned long kBUsed, unsigned long kBAvail); void slotEngineEvent(KFTPEngine::Event *event); void slotSessionAborting(); void slotConnectionLost(KFTPSession::Connection *connection); }; } #endif kftpgrabber-0.8.99~svn1214766/src/queuegroup.cpp0000644000175000017500000000756711276037142021116 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "queuegroup.h" #include "queueobject.h" #include "kftptransfer.h" #include "kftpsession.h" using namespace KFTPSession; namespace KFTPQueue { QueueGroup::QueueGroup(QueueObject *object) : QObject(object), m_object(object), m_childIterator(QListIterator(m_object->m_children)), m_directories(true) { } void QueueGroup::reset() { m_childIterator.toFront(); } int QueueGroup::executeNextTransfer() { // Check if there is actually something to execute if (!m_childIterator.hasNext()) { if (m_lastTransfer && m_lastTransfer->isRunning()) return -1; if (m_object->m_children.count() <= 1) emit done(); return -1; } else if (!m_directories && m_lastTransfer && m_lastTransfer->isDir()) { return 0; } Transfer *transfer = static_cast(m_childIterator.next()); // Check if we have enough connections available if (m_lastTransfer) { Session *sourceSession = m_lastTransfer->getSourceSession(); Session *destinationSession = m_lastTransfer->getDestinationSession(); if ((sourceSession && !sourceSession->isFreeConnection()) || (destinationSession && !destinationSession->isFreeConnection())) return 0; // Reserve the connections immediately transfer->assignSessions(sourceSession, destinationSession); } // Get the transfer instance and schedule it's execution transfer->QObject::disconnect(this); connect(transfer, SIGNAL(transferComplete(long)), this, SLOT(incrementAndExecute())); connect(transfer, SIGNAL(transferAbort(long)), this, SIGNAL(interrupted())); transfer->delayedExecute(); // Prepare for the next transfer m_lastTransfer = transfer; return 1; } void QueueGroup::incrementAndExecute() { if (QObject::sender()) { const Transfer *transfer = static_cast(QObject::sender()); if (!transfer->isDir()) m_directories = false; } int result = executeNextTransfer(); switch (result) { case 0: m_childIterator.previous(); break; case 1: { m_directories = false; incrementAndExecute(); break; } default: break; } if (result != -1 && !m_directories) m_directories = true; } } #include "queuegroup.moc" kftpgrabber-0.8.99~svn1214766/src/kftptransfer.cpp0000644000175000017500000002475311276037142021422 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftptransfer.h" #include "kftptransferdir.h" #include "widgets/systemtray.h" #include "kftpqueue.h" #include "kftpsession.h" #include "misc/config.h" #include using namespace KFTPSession; namespace KFTPQueue { FailedTransfer::FailedTransfer(QObject *parent, TransferFile *transfer, const QString &error) : QObject(parent), m_transfer(transfer), m_error(error) { // Reparent the transfer, we can't remove it from the QueueObject's children list yet, because // that will cause an iterator reset for directories, so we'll do that later in the fail method. transfer->parentObject()->addSize(-transfer->m_actualSize); KFTPQueue::Manager::self()->failedTransfers()->append(this); // Check if the transfer's site should be removed as well QueueObject *site = 0; if (transfer->parentObject()->getType() == QueueObject::Site && transfer->parentObject()->getChildrenList().count() == 1) { site = transfer->parentObject(); emit KFTPQueue::Manager::self()->objectRemoved(site); } // Complete reparenting and mark transfer as failed transfer->setParent(this); transfer->m_status = Transfer::Failed; delete site; } FailedTransfer::~ FailedTransfer() { } TransferFile *FailedTransfer::restore() { // Emit failed transfer removal emit KFTPQueue::Manager::self()->failedTransferBeforeRemoval(this); // Add the transfer back to the queue m_transfer->setParent(0); KFTPQueue::Manager::self()->insertTransfer(m_transfer); // Change the transfer's status, so it can be started m_transfer->m_status = Transfer::Stopped; // This object is now useless, so it shall be removed KFTPQueue::Manager::self()->failedTransfers()->removeAll(this); emit KFTPQueue::Manager::self()->failedTransferAfterRemoval(); deleteLater(); return m_transfer; } void FailedTransfer::fail(TransferFile *transfer, const QString &error) { // Should the transfer be retried if (KFTPCore::Config::failedAutoRetry() && transfer->m_retryCount < KFTPCore::Config::failedAutoRetryCount()) { // Semi-reset the current transfer transfer->addCompleted(-transfer->m_completed); transfer->m_retryCount++; transfer->m_resumed = 0; transfer->m_completed = 0; transfer->m_aborting = false; transfer->m_size = transfer->m_actualSize; transfer->setSpeed(0); // Restart the transfer transfer->delayedExecute(); } else { // Abort the transfer transfer->blockSignals(true); transfer->abort(); transfer->blockSignals(false); QPointer transferParent(transfer->parentObject()); emit KFTPQueue::Manager::self()->objectBeforeRemoval(transfer); // Create a new failed transfer (will automaticly reparent the transfer) FailedTransfer *ft = new FailedTransfer(KFTPQueue::Manager::self(), transfer, error); // Notify others about transfer's "completion" emit transfer->transferComplete(transfer->m_id); // Now that the iterators have been incremented we can remove the child without // doing any harm to the queue processing. if (transferParent) transferParent->delChildObject(transfer); // Fake transfer removal and signal new failed transfer emit KFTPQueue::Manager::self()->objectAfterRemoval(); emit KFTPQueue::Manager::self()->failedTransferAdded(ft); } } Transfer::Transfer(QObject *parent, Type type) : QueueObject(parent, type), m_deleteMe(false), m_openAfterTransfer(false), m_srcSession(0), m_dstSession(0), m_srcConnection(0), m_dstConnection(0), m_retryCount(0) { } Transfer::~Transfer() { } Connection *Transfer::getOppositeConnection(Connection *conn) { return m_srcConnection == conn ? m_dstConnection : m_srcConnection; } Connection *Transfer::remoteConnection() { return m_srcConnection ? m_srcConnection : m_dstConnection; } Connection *Transfer::initializeSession(Session *session) { if (!session->isFreeConnection()) { // We should wait for a connection to become available connect(session, SIGNAL(freeConnectionAvailable()), this, SLOT(slotConnectionAvailable())); if (m_status != Waiting) { m_status = Waiting; emit objectUpdated(); } return 0; } Connection *connection = session->assignConnection(); connection->acquire(this); connect(connection->getClient()->eventHandler(), SIGNAL(connected()), this, SLOT(slotConnectionConnected())); return connection; } void Transfer::deinitializeConnections() { if (m_srcConnection) { m_srcConnection->getClient()->eventHandler()->disconnect(this); m_srcConnection->release(); } if (m_dstConnection) { m_dstConnection->getClient()->eventHandler()->disconnect(this); m_dstConnection->release(); } } bool Transfer::assignSessions(Session *source, Session *destination) { bool result = true; // We need a source session if (!m_sourceUrl.isLocalFile() && !m_srcConnection) { if (!source) m_srcSession = KFTPSession::Manager::self()->spawnRemoteSession(IgnoreSide, m_sourceUrl, 0); else m_srcSession = source; if (!(m_srcConnection = initializeSession(m_srcSession))) result = false; } // We need a destination session if (!m_destUrl.isLocalFile() && !m_dstConnection) { if (!destination) m_dstSession = KFTPSession::Manager::self()->spawnRemoteSession(m_srcSession ? oppositeSide(m_srcSession->getSide()) : IgnoreSide, m_destUrl, 0); else m_dstSession = destination; if (!(m_dstConnection = initializeSession(m_dstSession))) result = false; } return result; } bool Transfer::connectionsReady() { return (m_sourceUrl.isLocalFile() || m_srcConnection) && (m_destUrl.isLocalFile() || m_dstConnection); } void Transfer::slotConnectionAvailable() { if (getStatus() != Waiting || (m_srcSession && !m_srcSession->isFreeConnection()) || (m_dstSession && !m_dstSession->isFreeConnection())) return; if (m_srcSession) m_srcSession->QObject::disconnect(this, SLOT(slotConnectionAvailable())); if (m_dstSession) m_dstSession->QObject::disconnect(this, SLOT(slotConnectionAvailable())); // Connection has become available, grab it now execute(); } void Transfer::slotConnectionConnected() { if ((m_srcConnection && !m_srcConnection->isConnected()) || (m_dstConnection && !m_dstConnection->isConnected())) return; // Everything is ready for immediate execution delayedExecute(); } void Transfer::faceDestruction(bool abortSession) { // This method is called before the object is deleted by the queue // manager. if (hasParentObject()) { parentObject()->addSize(-m_actualSize); parentObject()->delChildObject(this); } // Abort any dir scans that might be in progress if (abortSession) { KFTPSession::Session *session = KFTPSession::Manager::self()->find(this); if (session) session->abort(); } } Transfer *Transfer::parentTransfer() { if (!hasParentTransfer()) return 0L; return static_cast(parent()); } void Transfer::resetTransfer() { // Disconnect signals if (getStatus() != Waiting) { if (m_srcConnection) m_srcConnection->getClient()->eventHandler()->QObject::disconnect(this, SLOT(slotConnectionConnected())); if (m_dstConnection) m_dstConnection->getClient()->eventHandler()->QObject::disconnect(this, SLOT(slotConnectionConnected())); } // Reset connections & session pointers m_srcConnection = 0L; m_dstConnection = 0L; m_srcSession = 0L; m_dstSession = 0L; m_status = Stopped; m_resumed = 0; m_completed = 0; m_aborting = false; m_size = m_actualSize; m_retryCount = 0; // Set the transfer speed to zero setSpeed(0); } bool Transfer::canMove() { return !isRunning(); } void Transfer::update() { KFTPQueue::Manager::self()->doEmitUpdate(); statisticsUpdated(); } void Transfer::abort() { // Unlock if the transfer was locked unlock(); // Set the aborting flag m_aborting = true; emit transferAbort(m_id); } void Transfer::showTransCompleteBalloon() { // Show a balloon :P if (KFTPCore::Config::showBalloons() && !KFTPQueue::Manager::self()->isProcessing()) { if (!KFTPCore::Config::showBalloonWhenQueueEmpty() || (KFTPQueue::Manager::self()->topLevelObject()->getChildrenList().count() == 1 && !hasParentTransfer())) { QString transCompleteStr = i18n("Transfer of the following files is complete:"); transCompleteStr += "
"; transCompleteStr += getSourceUrl().fileName(); transCompleteStr += ""; KFTPWidgets::SystemTray::self()->showMessage(i18n("Information"), transCompleteStr); } } } void Transfer::lock() { // Transfers can only be locked if they are not currently running if (m_status == Stopped) { m_status = Locked; statisticsUpdated(); } } void Transfer::unlock() { if (isLocked()) { m_status = Stopped; statisticsUpdated(); } } } #include "kftptransfer.moc" kftpgrabber-0.8.99~svn1214766/src/statistics.cpp0000644000175000017500000000456511276037142021102 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "statistics.h" #include namespace KFTPQueue { class StatisticsPrivate { public: Statistics instance; }; K_GLOBAL_STATIC(StatisticsPrivate, statisticsPrivate) StatisticsSite::StatisticsSite() : m_lastFxpSpeed(0.0) { } Statistics *Statistics::self() { return &statisticsPrivate->instance; } Statistics::Statistics() { } Statistics::~Statistics() { qDeleteAll(m_sites); } StatisticsSite *Statistics::getSite(const KUrl &url) { // Reset the url's path and grab the site KUrl tmp = url; tmp.setPath("/"); StatisticsSite *site = m_sites[tmp.url()]; if (!site) { site = new StatisticsSite(); m_sites.insert(tmp.url(), site); } return site; } } #include "statistics.moc" kftpgrabber-0.8.99~svn1214766/src/kftpqueue.cpp0000644000175000017500000004455611276037142020725 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include #include "kftpqueue.h" #include "kftpbookmarks.h" #include "widgets/systemtray.h" #include "kftpqueueprocessor.h" #include "kftpsession.h" #include "misc/config.h" #include "misc/filter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KFTPEngine; using namespace KFTPCore::Filter; namespace KFTPQueue { OpenedFile::OpenedFile(TransferFile *transfer) : m_source(transfer->getSourceUrl()), m_dest(transfer->getDestUrl()), m_hash(QString::null) { // Calculate the file's MD5 hash QFile file(m_dest.path()); if (!file.open(QIODevice::ReadOnly)) { return; } KMD5 context; if (context.update(file)) m_hash = QString(context.hexDigest()); file.close(); } bool OpenedFile::hasChanged() { // Compare the file's MD5 hash with stored value QFile file(m_dest.path()); if (!file.open(QIODevice::ReadOnly)) { return false; } QString tmp = QString::null; KMD5 context; if (context.update(file)) tmp = QString(context.hexDigest()); file.close(); return tmp != m_hash; } UserDialogRequest::UserDialogRequest(TransferFile *transfer, filesize_t srcSize, time_t srcTime, filesize_t dstSize, time_t dstTime) : m_transfer(transfer), m_srcSize(srcSize), m_srcTime(srcTime), m_dstSize(dstSize), m_dstTime(dstTime) { } void UserDialogRequest::sendResponse(FileExistsWakeupEvent *event) { m_transfer->wakeup(event); delete this; } class ManagerPrivate { public: Manager instance; }; K_GLOBAL_STATIC(ManagerPrivate, managerPrivate) Manager *Manager::self() { return &managerPrivate->instance; } Manager::Manager() : m_topLevel(new QueueObject(this, QueueObject::Toplevel)), m_processingQueue(false), m_feDialogOpen(false), m_defaultFeAction(FE_DISABLE_ACT) { m_topLevel->setId(0); m_lastQID = 1; m_curDownSpeed = 0; m_curUpSpeed = 0; m_emitUpdate = true; // Create the queue processor object m_queueProc = new KFTPQueueProcessor(this); connect(m_queueProc, SIGNAL(queueComplete()), this, SLOT(slotQueueProcessingComplete())); connect(m_queueProc, SIGNAL(queueAborted()), this, SLOT(slotQueueProcessingAborted())); // Create the queue converter object m_converter = new KFTPQueueConverter(this); } Manager::~Manager() { } void Manager::stopAllTransfers() { if (isProcessing()) { abort(); } else { foreach (QueueObject *i, topLevelObject()->getChildrenList()) { if (i->isRunning()) { i->abort(); } else { foreach (QueueObject *t, i->getChildrenList()) { if (t->isRunning()) t->abort(); } } } } } Transfer *Manager::findTransfer(long id) { // First try the cache QueueObject *object = m_queueObjectCache[id]; if (!object) { object = m_topLevel->findChildObject(id); m_queueObjectCache.insert(id, object); } return static_cast(object); } Site *Manager::findSite(KUrl url, bool noCreate) { // Reset path url.setPath("/"); if (url.isLocalFile()) return NULL; // Find the appropriate site and if one doesn't exist create a new one foreach (QueueObject *i, topLevelObject()->getChildrenList()) { if (i->getType() == QueueObject::Site) { Site *site = static_cast(i); if (site->getUrl() == url) return site; } } // The site doesn't exist, let's create one if (!noCreate) { Site *site = new Site(topLevelObject(), url); site->setId(m_lastQID++); emit objectAdded(site); site->readyObject(); return site; } return 0; } void Manager::insertTransfer(Transfer *transfer) { // Set id transfer->setId(m_lastQID++); // Reparent transfer filesize_t size = transfer->getSize(); transfer->addSize(-size); if (transfer->hasParentObject()) transfer->parentObject()->delChildObject(transfer); Site *site = 0; switch (transfer->getTransferType()) { case Download: site = findSite(transfer->getSourceUrl()); break; case Upload: site = findSite(transfer->getDestUrl()); break; case FXP: site = findSite(transfer->getSourceUrl()); break; } transfer->setParent(site); site->addChildObject(transfer); transfer->addSize(size); emit objectAdded(transfer); transfer->readyObject(); if (m_emitUpdate) emit queueUpdate(); } Transfer *Manager::spawnTransfer(KUrl sourceUrl, KUrl destinationUrl, filesize_t size, bool dir, bool ignoreSkip, bool insertToQueue, QObject *parent, bool noScan) { const ActionChain *actionChain = Filters::self()->process(sourceUrl, size, dir); if (!ignoreSkip && (actionChain && actionChain->getAction(Action::Skip))) return 0; // Determine transfer type TransferType type; if (sourceUrl.isLocalFile()) type = Upload; else if (destinationUrl.isLocalFile()) type = Download; else type = FXP; // Should we lowercase the destination path ? if (actionChain && actionChain->getAction(Action::Lowercase)) destinationUrl.setPath(destinationUrl.directory() + "/" + destinationUrl.fileName().toLower()); // Reset a possible preconfigured default action setDefaultFileExistsAction(); if (!parent) parent = this; Transfer *transfer = 0L; if (dir) { transfer = new TransferDir(parent); } else { transfer = new TransferFile(parent); transfer->addSize(size); } transfer->setSourceUrl(sourceUrl); transfer->setDestUrl(destinationUrl); transfer->setTransferType(type); if (insertToQueue) { insertTransfer(transfer); } else { transfer->setId(m_lastQID++); emit objectAdded(transfer); transfer->readyObject(); } if (dir && !noScan) { // This is a directory, we should scan the directory and add all files/dirs found // as parent of current object static_cast(transfer)->scan(); } return transfer; } void Manager::removeTransfer(Transfer *transfer, bool abortSession) { if (!transfer) return; transfer->abort(); long id = transfer->getId(); long sid = transfer->parentObject()->getId(); // Remove transfer from cache m_queueObjectCache.remove(id); // Should the site be removed as well ? QueueObject *site = 0; if (transfer->parentObject()->getType() == QueueObject::Site && transfer->parentObject()->getChildrenList().count() == 1) site = transfer->parentObject(); // Signal destruction & delete transfer emit objectBeforeRemoval(transfer); transfer->faceDestruction(abortSession); delete transfer; emit objectAfterRemoval(); if (site) { emit objectRemoved(site); delete site; } if (m_emitUpdate) emit queueUpdate(); } void Manager::revalidateTransfer(Transfer *transfer) { QueueObject *i = transfer; while (i) { if (i->parentObject() == topLevelObject()) break; i = i->parentObject(); } // We have the site Site *curSite = static_cast(i); Site *site = 0; switch (transfer->getTransferType()) { case Download: site = findSite(transfer->getSourceUrl()); break; case Upload: site = findSite(transfer->getDestUrl()); break; case FXP: site = findSite(transfer->getSourceUrl()); break; } // If the sites don't match, reparent transfer if (site != curSite) { transfer->parentObject()->delChildObject(transfer); transfer->setParent(site); site->addChildObject(transfer); emit objectRemoved(transfer); emit objectAdded(transfer); if (curSite->getChildrenList().count() == 0) { emit objectRemoved(curSite); curSite->deleteLater(); } } } void Manager::removeFailedTransfer(FailedTransfer *transfer) { // Remove the transfer and signal removal emit failedTransferBeforeRemoval(transfer); m_failedTransfers.removeAll(transfer); delete transfer; emit failedTransferAfterRemoval(); } void Manager::clearFailedTransferList() { // Clear the failed transfers list foreach (FailedTransfer *transfer, m_failedTransfers) { removeFailedTransfer(transfer); } } void Manager::doEmitUpdate() { m_curDownSpeed = 0; m_curUpSpeed = 0; topLevelObject()->removeMarkedTransfers(); // Get download/upload speeds foreach (QueueObject *i, topLevelObject()->getChildrenList()) { foreach (QueueObject *t, i->getChildrenList()) { KFTPQueue::Transfer *tmp = static_cast(t); switch (tmp->getTransferType()) { case Download: m_curDownSpeed += tmp->getSpeed(); break; case Upload: m_curUpSpeed += tmp->getSpeed(); break; case FXP: { m_curDownSpeed += tmp->getSpeed(); m_curUpSpeed += tmp->getSpeed(); break; } } } } // Emit global update to all GUI objects emit queueUpdate(); } void Manager::start() { if (m_processingQueue) return; m_processingQueue = true; // Now, go trough all queued files and execute them - try to do as little server connects // as possible m_queueProc->startProcessing(); } void Manager::abort() { m_processingQueue = false; // Stop further queue processing m_queueProc->stopProcessing(); emit queueUpdate(); } void Manager::slotQueueProcessingComplete() { m_processingQueue = false; // Queue processing is now complete if (KFTPCore::Config::showBalloons()) KFTPWidgets::SystemTray::self()->showMessage(i18n("Information"), i18n("All queued transfers have been completed.")); emit queueUpdate(); } void Manager::slotQueueProcessingAborted() { m_processingQueue = false; } void Manager::clearQueue() { foreach (QueueObject *i, topLevelObject()->getChildrenList()) { foreach (QueueObject *t, i->getChildrenList()) removeTransfer(static_cast(t)); } } int Manager::getTransferPercentage() { return 0; } int Manager::getNumRunning(bool onlyDirs) { int running = 0; foreach (QueueObject *i, topLevelObject()->getChildrenList()) { foreach (QueueObject *t, i->getChildrenList()) { if (t->isRunning() && (!onlyDirs || t->isDir())) running++; } if (i->isRunning()) running++; } return running; } int Manager::getNumRunning(const KUrl &remoteUrl) { int running = 0; Site *site = findSite(remoteUrl, true); if (site) { foreach (QueueObject *i, site->getChildrenList()) { if (i->isRunning()) running++; } } return running; } KFTPEngine::FileExistsWakeupEvent *Manager::fileExistsAction(TransferFile *transfer, QList stat) { FileExistsWakeupEvent *event = new FileExistsWakeupEvent(); FileExistsActions *fa = NULL; FEAction action; filesize_t srcSize = 0; time_t srcTime = 0; filesize_t dstSize = 0; time_t dstTime = 0; // Check if there is a default action set action = getDefaultFileExistsAction(); if (action == FE_DISABLE_ACT) { switch (transfer->getTransferType()) { case KFTPQueue::Download: { KFileItem info(KFileItem::Unknown, KFileItem::Unknown, transfer->getDestUrl()); dstSize = info.size(); dstTime = info.time(KIO::UDSEntry::UDS_MODIFICATION_TIME); srcSize = stat[0].size(); srcTime = stat[0].time(); fa = KFTPCore::Config::self()->dActions(); break; } case KFTPQueue::Upload: { KFileItem info(KFileItem::Unknown, KFileItem::Unknown, transfer->getSourceUrl()); srcSize = info.size(); srcTime = info.time(KIO::UDSEntry::UDS_MODIFICATION_TIME); dstSize = stat[0].size(); dstTime = stat[0].time(); fa = KFTPCore::Config::self()->uActions(); break; } case KFTPQueue::FXP: { srcSize = stat[0].size(); srcTime = stat[0].time(); dstSize = stat[1].size(); dstTime = stat[1].time(); fa = KFTPCore::Config::self()->fActions(); break; } } // Now that we have all data, get the action and do it action = fa->getActionForSituation(srcSize, srcTime, dstSize, dstTime); } switch (action) { default: case FE_SKIP_ACT: event->action = FileExistsWakeupEvent::Skip; break; case FE_OVERWRITE_ACT: event->action = FileExistsWakeupEvent::Overwrite; break; case FE_RESUME_ACT: event->action = FileExistsWakeupEvent::Resume; break; case FE_RENAME_ACT: case FE_USER_ACT: { appendUserDialogRequest(new UserDialogRequest(transfer, srcSize, srcTime, dstSize, dstTime)); // Event shall be deferred delete event; event = 0; } } return event; } void Manager::appendUserDialogRequest(UserDialogRequest *request) { m_userDialogRequests.append(request); if (m_userDialogRequests.count() == 1) { processUserDialogRequest(); } } void Manager::processUserDialogRequest() { UserDialogRequest *request = m_userDialogRequests.first(); if (!request) return; FEAction action = getDefaultFileExistsAction(); FileExistsWakeupEvent *event = new FileExistsWakeupEvent(); if (action == FE_DISABLE_ACT || action == FE_USER_ACT) { // A dialog really needs to be displayed TransferFile *transfer = request->getTransfer(); KIO::RenameDialog dlg( (QWidget*)0, // ### parent i18n("File Exists"), transfer->getSourceUrl(), transfer->getDestUrl(), (KIO::RenameDialog_Mode) (KIO::M_OVERWRITE | KIO::M_RESUME | KIO::M_SKIP | KIO::M_MULTI), request->sourceSize(), request->destinationSize(), request->sourceTime(), request->destinationTime() ); int result = dlg.exec(); KUrl newDestUrl = dlg.newDestUrl(); switch (result) { case KIO::R_RENAME: { transfer->setDestUrl(newDestUrl); event->action = FileExistsWakeupEvent::Rename; event->newFileName = newDestUrl.pathOrUrl(); break; } case KIO::R_CANCEL: { // Abort queue processing abort(); transfer->abort(); // An event is not required, since we will not be recalling the process delete event; event = 0; break; } case KIO::R_AUTO_SKIP: setDefaultFileExistsAction(FE_SKIP_ACT); case KIO::R_SKIP: event->action = FileExistsWakeupEvent::Skip; break; case KIO::R_RESUME_ALL: setDefaultFileExistsAction(FE_RESUME_ACT); case KIO::R_RESUME: event->action = FileExistsWakeupEvent::Resume; break; case KIO::R_OVERWRITE_ALL: setDefaultFileExistsAction(FE_OVERWRITE_ACT); default: event->action = FileExistsWakeupEvent::Overwrite; break; } } else { switch (action) { default: case FE_SKIP_ACT: event->action = FileExistsWakeupEvent::Skip; break; case FE_OVERWRITE_ACT: event->action = FileExistsWakeupEvent::Overwrite; break; case FE_RESUME_ACT: event->action = FileExistsWakeupEvent::Resume; break; } } // Send a response to this request request->sendResponse(event); m_userDialogRequests.removeFirst(); if (!m_userDialogRequests.isEmpty()) processUserDialogRequest(); } void Manager::openAfterTransfer(TransferFile *transfer) { QString mimeType = KMimeType::findByUrl(transfer->getDestUrl(), 0, true, true)->name(); KService::Ptr offer = KMimeTypeTrader::self()->preferredService(mimeType, "Application"); if (!offer) { KOpenWithDialog dialog(KUrl::List(transfer->getDestUrl())); if (dialog.exec() == QDialog::Accepted) { offer = dialog.service(); if (!offer) offer = new KService("", dialog.text(), ""); } else { return; } } QStringList params = KRun::processDesktopExec(*offer, KUrl::List(transfer->getDestUrl()), false); K3Process *p = new K3Process(this); *p << params; connect(p, SIGNAL(processExited(K3Process*)), this, SLOT(slotEditProcessTerminated(K3Process*))); p->start(); // Save the process m_editProcessList.insert(p->pid(), OpenedFile(transfer)); } void Manager::slotEditProcessTerminated(K3Process *p) { // A process has terminated, we should reupload OpenedFile file = m_editProcessList[p->pid()]; // Only upload a file if it has been changed if (file.hasChanged()) { TransferFile *transfer = new TransferFile(KFTPQueue::Manager::self()); transfer->setSourceUrl(file.destination()); transfer->setDestUrl(file.source()); transfer->setTransferType(KFTPQueue::Upload); transfer->addSize(KFileItem(KFileItem::Unknown, KFileItem::Unknown, file.destination()).size()); insertTransfer(transfer); // Execute the transfer transfer->delayedExecute(); } // Cleanup m_editProcessList.remove(p->pid()); p->deleteLater(); } } #include "kftpqueue.moc" kftpgrabber-0.8.99~svn1214766/src/kftpqueue.h0000644000175000017500000003270611276037142020364 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUE_H #define KFTPQUEUE_H #include #include #include #include #include #include "kftpqueueprocessor.h" #include "kftpqueueconverter.h" #include "fileexistsactions.h" #include "engine/directorylisting.h" #include "engine/event.h" #include "directoryscanner.h" #include "kftptransfer.h" #include "kftptransferfile.h" #include "kftptransferdir.h" #include "site.h" namespace KFTPSession { class Session; class Connection; } class KFTPQueueConverter; class K3Process; typedef QList KFTPQueueTransfers; namespace KFTPQueue { class FailedTransfer; class ManagerPrivate; /** * This class represents an opened remote file. The file is stored locally * while its being displayed to the user. * * @author Jernej Kos */ class OpenedFile { public: OpenedFile() {} /** * Creates a new OpenedFile object. * * @param transfer The transfer used to transfer the file */ OpenedFile(TransferFile *transfer); /** * Get file's source (remote). * * @return File's remote source URL */ KUrl source() { return m_source; } /** * Get file's destination (local). * * @return File's local destination URL */ KUrl destination() { return m_dest; } /** * Has the file changed since the transfer ? * * @return True if the file has been changed since being transfered */ bool hasChanged(); private: KUrl m_source; KUrl m_dest; QString m_hash; }; /** * This class represents a request for "file already exists" dialog * display request. * * @author Jernej Kos */ class UserDialogRequest { public: /** * Class constructor. */ UserDialogRequest(TransferFile *transfer, filesize_t srcSize, time_t srcTime, filesize_t dstSize, time_t dstTime); /** * Sends a response to this request. * * @param event A valid file exists wakeup event */ void sendResponse(KFTPEngine::FileExistsWakeupEvent *event); /** * Returns the transfer that initiated the request. */ TransferFile *getTransfer() const { return m_transfer; } /** * Returns source file size. */ filesize_t sourceSize() const { return m_srcSize; } /** * Returns source file time. */ time_t sourceTime() const { return m_srcTime; } /** * Returns destination file size. */ filesize_t destinationSize() const { return m_dstSize; } /** * Returns destination file time. */ time_t destinationTime() const { return m_dstTime; } private: TransferFile *m_transfer; filesize_t m_srcSize; time_t m_srcTime; filesize_t m_dstSize; time_t m_dstTime; }; /** * This class is responsible for managing the complete queue hierarchy. All * queued items descend from QueueObject and are contained in a simple tree * model. Statistics and abort requests propagate from bottom to top and exec * requests go in the other direction. * * @author Jernej Kos */ class Manager : public QObject { Q_OBJECT friend class KFTPSession::Session; friend class KFTPSession::Connection; friend class ::KFTPQueueConverter; friend class ::DirectoryScanner; friend class FailedTransfer; friend class QueueObject; friend class ManagerPrivate; public: /** * Returns the global manager instance. */ static Manager *self(); /** * Stop all queued transfers. */ void stopAllTransfers(); /** * Get the toplevel queue object. The direct children of this object are different * KFTPQueue::Site objects that represent separate sites. * * @return A QueueObject representing the toplevel object */ QueueObject *topLevelObject() const { return m_topLevel; } /** * Queues a new transfer. This method will create the site if one doesn't exist yet * for this transfer. The object will be reparented under the assigned site. * * @param transfer The transfer to be queued */ void insertTransfer(Transfer *transfer); /** * Remove a transfer from the queue. The faceDestruction method will be called on the * transfer object before removal. After calling this method, you shouldn't use the * object anymore! * * @param transfer The transfer to be removed from queue * @param abortSession If true any session that this transfer is using is aborted */ void removeTransfer(Transfer *transfer, bool abortSession = true); /** * This method removes all the transfers from the queue. */ void clearQueue(); /** * Check if the transfer is under the correct site and move it if not. * * @param transfer The transfer to check */ void revalidateTransfer(Transfer *transfer); /** * Finds a transfer by its id. * * @param id The transfer's id * @return The transfer object */ Transfer *findTransfer(long id); /** * Finds a site by its URL. * * @param url The site's URL * @param noCreate If set to true the site will not be created when not found * and NULL will be returned * @return The site object */ Site *findSite(KUrl url, bool noCreate = false); /** * Remove a failed transfer from the list. * * @param transfer The failed transfer object to be removed */ void removeFailedTransfer(FailedTransfer *transfer); /** * Remove all failed transfers from the list. This method actually calls the * removeFailedTransfer for every failed transfer present. */ void clearFailedTransferList(); /** * Returns the list of failed transfers. * * @return The QList of FailedTransfer objects */ QList *failedTransfers() { return &m_failedTransfers; } /** * Return the queue converter (exporter). * * @return the KFTPQueueConverter object */ KFTPQueueConverter *getConverter() const { return m_converter; } /** * Opens the file with the registred application for it's MIME type and waits * for the process to exit (then it will reupload the file if it has changed). * * @param transfer The transfer whose destination should be opened */ void openAfterTransfer(TransferFile *transfer); /** * Should the update() be emitted on changes ? * * @param value True if the value should be emitted, false otherwise */ void setEmitUpdate(bool value) { m_emitUpdate = value; } /** * Does a global queue update and removes all transfers that have the "delete me" * variable set. */ void doEmitUpdate(); /** * Get the current download speed. * * @return The current download speed */ filesize_t getDownloadSpeed() const { return m_curDownSpeed; } /** * Get the current upload speed. * * @return The current upload speed */ filesize_t getUploadSpeed() const { return m_curUpSpeed; } /** * Get the percentage of the queue's completion. * * @return The percentage of the queue's completion */ int getTransferPercentage(); /** * Get the number of currently running transfers. * * @param onlyDirs Should only directories be counted * @return The number of currently running transfers */ int getNumRunning(bool onlyDirs = false); /** * Get the number of currently running transfers under a specific * site. * * @param url The remote URL * @return The number of currently running transfers */ int getNumRunning(const KUrl &remoteUrl); /** * Start the queue processing. */ void start(); /** * Abort the queue processing. */ void abort(); /** * Is the queue being processed ? * * @return True if the queue is being processed, false otherwise */ bool isProcessing() { return m_queueProc->isRunning(); } /** * Return the next available transfer id and reserve it. * * @return The next available transfer id */ long nextTransferId() { return m_lastQID++; } /** * Set a default action to take when encountering an existing file situation. Note that * the action set here will override any preconfigured user actions unless set to the * value of FE_DISABLE_ACT. * * @param action The action to take */ void setDefaultFileExistsAction(FEAction action = FE_DISABLE_ACT) { m_defaultFeAction = action; } /** * Get the default action preset for situations where a file already exists. * * @return A valid FEAction */ FEAction getDefaultFileExistsAction() const { return m_defaultFeAction; } /** * Decides what to do with the existing file. It will return a valid wakeup event to * dispatch. It will first consider the pre-configured "on file exists" action matrix. * * @param transfer The transfer object * @param srcStat Source file information (if remote) * @param dstStat Destination file information (if remote) * @return A FileExistsWakeupEvent that will be sent to the engine */ KFTPEngine::FileExistsWakeupEvent *fileExistsAction(KFTPQueue::TransferFile *transfer, QList stat); /** * Spawn a new transfer. * * @param sourceUrl Source URL * @param destinationUrl Destination URL * @param size Filesize * @param dir True if this transfer represents a directory * @param ignoreSkip Ignore skiplist for this transfer * @param insertToQueue Should the new transfer be queued * @param parent Optional parent object * @param noScan True if directory transfers shouldn't be scanned * @return A valid KFTPQueue::Transfer instance */ KFTPQueue::Transfer *spawnTransfer(KUrl sourceUrl, KUrl destinationUrl, filesize_t size, bool dir, bool ignoreSkip = false, bool insertToQueue = true, QObject *parent = 0L, bool noScan = false); protected: /** * Class constructor. */ Manager(); /** * Class destructor. */ ~Manager(); /** * Appends a new user dialog request. * * @param request Request instance */ void appendUserDialogRequest(UserDialogRequest *request); /** * Processes the top user dialog request by opening the desired "file * already exists" dialog. */ void processUserDialogRequest(); private: QueueObject *m_topLevel; QCache m_queueObjectCache; QMap m_editProcessList; QList m_failedTransfers; KFTPQueueProcessor *m_queueProc; KFTPQueueConverter *m_converter; long m_lastQID; bool m_emitUpdate; bool m_processingQueue; filesize_t m_curDownSpeed; filesize_t m_curUpSpeed; bool m_feDialogOpen; FEAction m_defaultFeAction; QList m_userDialogRequests; private slots: void slotQueueProcessingComplete(); void slotQueueProcessingAborted(); void slotEditProcessTerminated(K3Process *p); signals: void objectAdded(KFTPQueue::QueueObject *object); void objectRemoved(KFTPQueue::QueueObject *object); void objectChanged(KFTPQueue::QueueObject *object); void objectBeforeRemoval(KFTPQueue::QueueObject *object); void objectAfterRemoval(); void queueUpdate(); void failedTransferAdded(KFTPQueue::FailedTransfer*); void failedTransferBeforeRemoval(KFTPQueue::FailedTransfer*); void failedTransferAfterRemoval(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/kftpgrabber-logo.png0000644000175000017500000063366711276037142022154 0ustar michaelmichaelPNG  IHDR,br pHYs  tIME 5)ptEXtCommentKFTPGrabber logo@U72IDATxٮ,ٖnef?'N4φdf2 UD*UOzO$JPP$dL6y{;nfay@i9Ƿowfs1㯏>㯏>ABSRvV[Zt;յr=/wwͫ/Ϙq7*L< Aa[^晐()y}\_ݨsWWW۶qȔUmMo|:Ne`UOvnnS`,8@ڧycR d pORJ&12x @l`#M6P ZX(R8fbf2p tw W6kHhW1 *S{ " |h+znT+A^d.Amn&'U9<$3luoSھmkXv^:*턶Jko>?~hnnZb5??S~uՎd1!2ֿR]Lg l}ߙ |Woixۺ(! ?57/_5Byߍ?,,XXXHmNo߾7's;߃)sEN= =Ik1~e}ӐS꩎k53ޑSUQH$`[7fvww73"""DDDf, "zxXNBDѯRBDF@f,spH˲lfDsarΪڟ̘qT矫*3GDD,KDLӤSi9";"F97o c`vB@8",@,,n.IsIiLAMA dfsX@n dh@ ?v4ݎii3R 7ĈįзH7#sb^ 00100F8:P39cx8k3PPW$ 0pJxpLa6;c"{04V^hD* :A4@j1B@ԏ- j eρw( )sn.$7iH`A@ @\>~5޽F?O|9X?ǧMA#Im ̦ 駟~[W+ 6 Ɣ$afHa>ֶ^ag@7s&9 o~uv/xuuOȈ,Hm- t<~1Ȟ}_{˻a9]/R8=+nEYM- t,8rɃ$KPʐ8kSbjzRUG {RUU|`Bm|x[N jR$9e"Lq)2!Rb旗3?NDJ)7770Y=rΈx<?u]Uu6J)903ff lPVݝEZk-(Hߌ8 ثG  ܐnAvWmj[ 1yAymސm" "!CD o~k(Aݫ4^)DraFĠ4MV[?VJ0~>ExXfaN@H@ЫQh`rŭ?[-"+.H{D?7\jɳ9cE3Zi.ꇆŒa$ :ԫ@gJc & ^-Mȶ +a [z󇻇k)m'ש-Ͱ?o1IRI2kÊiӚi?<l[="OOQtxZ M_osϋ?7~_O?.Sx>_{nrxU՜M/{woTnli i/'o=[YV`7;çp."4͈I3?m6ľ5e(9midbN\ "2[)ktCyܱ".5Rs΄?ˆ(, "53swU=8777ת1#3MӴ,p8۶icƎȪ*"|ss+ٺ13i222# ަ#omڶ)Ӱ~3:)mn1rN4XܨjmmH4}ɅRʪ*ET6aVmnx~~|ibNlWcI_ӄi=öƉPlN=9)p"~L8_1듻F*fFFt1C88*"`=UunP8H7kjEbmH0axzj̹x(Cב: nFߗ@s؍]y-zeVݻ?[M벮7jE{V|=`V-גR`PMf5O))q~#Ê2ccĿ'Le$!`ԸqǼ=Ga^>IlrT(ˆLZssw4^]{@R bEM'F8Z۶ܙEy8ޟ:C]dDRjwy'1eYZ>fj 4m//%3"M.IfJĤaF*{vSy?0f/0@B""%B",}M9gMzLֶ[x008 c&dBUz_-sJHAM7 (p~|ŲcX4gŒh`!GQE8G D3!`P!`P8{8@F䌈`aF KCdD{gfBfbvr-a179wxAaXy psWJ8Z5:! uU[-<t3S3wL|mV  P#A0}GsE4ayYouFJzJ?HC6S+DŽUhHE5nop遼iCl0xvfZu,y;UuCe>onL:ѣJfbZkyƔR?<5Ͽ-j"ԈO93]?V<{\16}We߯pU",I">zT&9Sf%'I0tꀙ%'L9F]ؚ@$! ݋Vx065&_g@Gr>fZ'ڶmFDY۶ݿRq-ZC x2jCD4jen%KD||ɹZw}J9 0 CFi4a*H('IƛIPpSoBȓDZ35]낉@U ,8Aa`f6~>l4 >viLsMc:?αvZy2035"&7))7oGea" @   v~S:Q It  ,P*l`HџѰb— w״@B|ŴGho%ѢĈg4o.@TŒD! LBq8f뷛"?$h@l6k}22r;{áwinjW#<6_"Px#nyGhPK6&^]ӕ|.<(IZe]W$$pS0OQ$ WSՔ'涙0><ҫoQ ~ěm=?yDiw ^81P%{҅G (Ibv#.WU/=,ܙ΍0 $}_L';%qãVk>wOI#"ضm]u]Cܣ""̴?zc{ww,tkSo9`歵[~ U5"iYO?DJasd "Bœ3[T@0aJi%rBE6ΒK)M] aW$1p˪M -) Аe Zf$ !xⰠJ,|7Agv->xiƻ‰A@ ̨/ D$(<!A$DH: #0ݣw,g2n!msP@fAA={x!pu3jw9\`F8nFDmin|sD@k5Fp<5Wk}K%*cNH6غ9yquc\{Ik0 X:1-"}Қ֦)hqw{ݖnr Χ6~M=eYfΰi~ I^-nAD DJ)u-$ 0kJ.f̼}),s"pmu]~/yȁuJlFF~nGYe?YH1b-;,ihZWϔ ,SxeX )iP"'{6o ,!1ŤMSI +W H@P0afMɟ<$Lp#F@@c JL w4L.D \.ݎ!8$ " <<[i/i N4oHNy#}#3Vm\(% ,l5T$l@HN 9v0@DŠЕ{x@@(0!qlKHhvS0" C!QBJ*]sVOSX[}Ʋ6+/D~Dpic2kR14/O$nZڴ0Vz2H)#'jrʐKkWN3?}-~g_/ާ &7ckKmow,4ɽ"F8DtY,\[pc,IZm\s""А zTܼ:8Ho,9vhfjZN2u)^7j["_{@eOӺ., L"ӛ7`fWvM 0T Rʈ $I`%RUB96bRzu K)5abfo֦;<39ȟ\X} `sŮ$pO*5FWy<}?xjzynvdfs:Z[eူf#Fn:4Dpmk꺙N! YFD5 h`ץ5mXDP2I<0e @@y=#Dh jL>V$) tU>xq>YpyXRaҰp(C)ewbݻ ѫUO) 3j\>WWG]rƟiqt7̏+> cyq}g/sJ@\(N`u:DMѹk`Ie]]\1Zu) V(CD0 ޺Dt}sEiz 풅^궝N# EaDv""8RIFZvf*tNy>Ue 'w0La*mFHhjHbhS5bSV8|5` I02 icf룛c 1i3^=*/S~V`DVsHv4 ź'`=<¸BBVhO7p_'bNPhŌUv/(U> ,4Y~-OvO mV(SX]w斮 emnjvrX(YuwSmM{-Q\ݚ{0oOWˀ%K~a4~?oܦ<ҐrON<'hfy#ׅgTqADeд/uaLfTERoMͭjzQ63E !F'ԅ9fW8CD}ҽIL'=|7TD=qo )p˩4MM+~oR'OvN|E =<)Hݎ,K 8F`60b>k#. s᭶y>ˍO.M7kg=o'U9(.41ˎ.(YՍ׊ n)ĚQK{uvvQOFb$&d PH% cbs/dh#M-g -$1 2D pAPǤE*>:EhhL1.v#˧)%z:i"[||ކw.mm9a#2Onf֛nlng1P+0mjN{"ܺV )m10p7i;I)؉1*Š̈!ۙb@2^㺪S0-}f)voJ)I"$D  s۹Wu%&RJ>"34n?8gm jSAMIOAwq8i>珇>l!G_0\yȈo/J!p":5Gꯍ;/j d:m("LHf53>a#pݶL" BE8b Pv k4m]5@q)K.uQu;-jk"CJ%,J-"~ұ ̛_ @V%X@ Ӳ!+)Rú&#Rwa$ :0H@*ף`ݙ~+21f| y)q"SrCNdfR?>*`⩥UЉ y;ˎy8Q2:SH YkRIѺOk, τ,PP 5+ v7Wm,B075~y̘\K7뢺jZ'%9G . Ԙ0 Zk9gwo r 3K9=??8 f-O{Of">Kdq||"^">mI@K,:zh'DOG4u.ZV7I( !,`:̽E!b+0IXT7PS3*\ <(\wsfACp7"J#nu)wֳUǏouKS)rSi,/u/~^J靰NOܗ(pjc$Fg+ Re 77ё)hwSrDqxh'-ׁFB4 YąAU `GFBp;i؁D ͒%sr'V=5BCD|*\C/! " 0 "'pFV}pp/Ooο_}ܣbxV+)/0r ?~|\!Um5ԚӸ~}06)V];[Y !hP$=YxԵU?\=,tQhޭ,miaM6W'"m0UꒄkR!F; S ,S0qɆ$)1Ba8CLVi{ ?QඥZ%}[5snyѪhn7Cdff!sCPa_8kv^io['o??t;:Ooly”>-?/H^YվWyȈALBH""ף =]"t$w^LcPq%Nf ܢ%;RSmen(I?GS)t0rɽvZiݸK,q@iWֺI~͓?a]+ nnՅ.=.=J@QD, ΀ LVj6#ڴKZ54=00\!zHBT75 $$x.IJDHIDm8{pnt0 úCr|_^rD$1RAhpخD0B]674 zz:-%%bŘb )"G@.%ts@wCD0q ;7|z|}XnOU>^櫵j\۲{a_]ٝGZu<3d4MTSWSkxBSe^q[vRx$s`@& *h2p*}= f@HLl/&ԟqZC,2Ow?-z/t6ow˚&OKf+ tjé|cx.fnOmpnW_ڻe?rQ*T _>\ $rтu\ Q)it@pB"@dּhZm A$,2tDgr Kwj)A6@POG7$! T$*`%h=+M'>,Enhcqą fHLτwx;Ft;m>ɯ cpx@@[m233tJF5\# zx}^lJk`Cr[8sܵuĭ.T҈XsqU WЩhW??=)!%hpGA$f>rJIUpFq%S ]{ `y1Av7 ᳼|7tn- (tTE@}AoO?^I/qp@IT qk0 tN2\@.aj]vnޚɈhV{MYRJI 3^M<3V׹–dHHW2ͩ0ik˻Rm|%ĒIHPƱ Ra=Y굶:İ)i@D.\DKkWo7w󑈧azj=8hk͞F4 I4ZO\E!60bd`b8PvN8 蓣 1Q"D !fB$>~V* vR ~|<;p>)v %8V8<ؗ}- 21Ѯpp]@KB1ħ[V!4=}z-ʿ kҒjoS^Rn[T(fwŐA8/, ZD۪!5NòRy=1BfjZ?'vGZߕO~ӧwfy<.w;{w{3dý-exuW3|?<#(Xu`"ĞXy#BL5][> p.j͘_rc:CQiuY" Uۺ-nwխ%'r0  3oqNnΣ0[+[kR]H%UnkBНR~p>޽aRJ`)0130X2`$Oo۸]jn} ocVf*șu L~8 lAD8fmcHɛ2!剡QB6ץ'װ-X!AFHD4 ! ~0 B_璹0 APײcx='^{êFfS0E"m^]vtx#Ꜵr.qVi&o;|Ӗ=F)UքB͙DKjׯ4$ZJ#@Z6+t,fm 0fZ-s>?)%J|Jg@|>.Zsݢ my%%C BG 2eT=>b A%3l΁ ARK.HI, c ]4QZwǽɒ"?Fu=!Q8 h#{Jlŏήoֺ0?V4Hдd 8y8MEw~z7+qKǧC.%EWA[<DnL]H/9'"N9Y֚vY^ޓ`3vg,"]s 7 Q2#p.!TNuY{:MZO=a""d'O\" L¶n۶l[nR AO??{7o(̙qCC$'K c.w٬9 PB&F wߧ%lKY32L5r:6U14HyȏqAKͽyl $1#QѺ>%M591DpGwM4S0D h/ bwxk]}hd/B0eưAdk :D/ҫO.-π!cpU  <{1Q@KPn7vqzϊnK[}>q%w$-GvG[+RǑtjցP$FDFFU$N$@mWsmYZS`ln`a30 m͘ 1}_x%L$fA L¡Ǟ'HCdtyl_>,Ԑ#)pE_X\Қ Ibɥ(mv"+q̃imjrɹ"da7A(nȂԽ{:oaKDX,")D)ٴ.{'jWV{M n9+u V sL@B 0 C3 8yq2tuΕR=XUꠠjC) %H@a',4s//sWǘZӆH,2TH%=A[@p4Lv qK DL ӭgz}Hl{ȡԏu{jR$‰Ήp@FasŠՅDLöy+uԥDE7PZ=,@1c"hC*Ld(!-`XGT<>qܖٌaX`Ɋflf݉3cFNN֎-"ܢMWƗ/WWH0pwԦ˲2Q\Ka`"ZyP['%`E7;D "skJZL0de'^9mD4BزV\ץ^63tG`hKJP Xma/1"@ܪ Qq)=-F Z9 h|=sstw/3<0JTD8f0Hn7MOie'z\)W~Ɨ*24\j[k*ȉ}KW3 tIkji/9 S\$}l<rkDn9 2j$q4BD0 ϓ<''$RT$N_;B@}jBVSe @[-棭tQBmCF莫a,f طFEa'y?tě)ן#>7}Y>.C=:~GiԐjyIVF^䠗% }R2t}:2sDIB]%i?ƒ|ZE Q8m !D!,j3F2m` m!G3":U2EEx\G~ #Aںx}}jf[];[zw,5"=Dv]`vtFx7Nz|u!F Ѐ'&g?r {m2JíPL '+\hs݄R<֊8#6d u n< Oexh!-DfbnZ9[s?]a{Wk[fQUuTC/脜1$ X*(~ "w[6Lou:d7L{k.|5cwx<-)0!Eࡡuԭvg ") Dz*nצծbfbѐjAtP,İH.?;\B{9?ڦJa#Z @͘lm9gm@hn ՉO(1~&/+,58muf5Ĕmq}|Pˏg>~ OQ?jh̠q84"PPPBD'77a$tDB7SN~YHy&&a0cqSDovݑy` bD|ڕ˂̌!`Y3 Pu;ʉPBatB@Cp"\!"noo] {,LDJx wßiZf?GkWZWzǏx2phmtO|pWhGWUE'Y(ڻ@ zt r#1 MkSE2Lnf%y(vIRBY "hr:M[ELf6]Y3z=nX!P[ "`7UIdYOJD=024B8Q%$FЋF``7}"ܚ1j6Yu5_[WRխw[e (Xx;4[L$!$6?. ҫV_`( H16vEI!06B*=[9\q-|Bb71y*֜,A@ڰJ$!Dqz/cv'ݫf8.I#&̭555tn^-+Qڂ̈́cGf$k*vóOMn$IOikg eojy]cm9,yiKKxR`\VTu#j3'J%!  C@̘% D` ۘ )ּ*nyb~\JIn>d5w@Ԙ_jR9ܑ`%%w s,:fZo2rwŏ~?kJG,m< +纼7e`=}LWʷ9FY",ͯ?;?^nzxv,+.:gS9\6:K2dGqk팍u;!0Gw{Xsiߩ02'k7㋟v|VScb#D$Yݴ)7kB0, " 涩CvJHf$ỻmۖe9뺮뺴yYC{Q}ahӴsC0`K4ﭢ!"iS E$I | @"&$"`3_ (!;Pj&"ad0~m!|5r\|5|{",Ъsu"Qt?yƮ;fBaXxd;m\o~isӹFM Hay%,Ou[h sB8(-͹kipu>:J齾}!64g{1z7>KK)I ]2.(>N9ed3 9ZHbU!wS!Ywdʶ>F""~vhZ2RNHDvlU)xf cJJf>dҨ={`Y(/Y6;jӉWP<Oӻ-;6GnI9Ƿ-M%)֪2Թ%/s>dJ9եVR "7g ޲c C*HHQ.kyMn&VonG!3 ,Zo$[$EzXO 8jk=" Y*I' !0 FJ4W8\SiT60prBODԴtvk'JJ"AO%Q»pq&FFknS9/6$aI!,jbفp67`f-dlGgD "Rl zh֦I)Q".LƬi~;~?ZW 5+JЂMS >GĉYc ̊q`xs{U wn 0!)0&<ϞmyuW :425C $7Ёww) !Cr9{Z/8^! W `PPku`=\#râLlB7 `F">JFn͏vdاmѺpBH5ꪻa=_'k!D$`  r6ӟyr:V)!PJ;u 2"w\vK[8mmyZKJunzqTOif[y7J*}܎7d"NL#"C`*:VAJRY6a ^S0P(%-W?A H@ ATڪoU "ߜwLA)"4=O٦1!̐C9w&ײSϵnAC^j\"RDvnAҗ` *:TV6S6IsV75%-AEDZXƎmEb& 7'dC\yuToZdX̗XG@p]26)mKᰶ۝"^*5Co,kT'D Alh @JJz&?@>>m`iJ2RN,y ="i3njX^|p)]nR*q'7ovsjÃ#gZ.tM+g R4]9}W ӱQAx. {a<ڠ'",r"J3#0^}ONmj]˜0DIx:۶m)gWCfF$!Zta%' _W8?3K ^363H_Qc;ٓp ! G@"'v rr`peXmVcMZ7s\ -d8I$A TdK3v8#:k[Ε=y4O)Q䲟v &V=eQKSmO9Cw0 Uy]vͻW9x~EDi__Yn"ۧ!5 !!DZKX $B ؃!1Qv8WsBxi ,njL*o$e RRpMGX9O"ԚzX '6pqnj5Awa'I\7 ь̈=^rqMḅ! \fm-F@y''bPA[ Ap8hmhF) rdR20 !qyuk 224 +Z 'f%ٍ_?F?yww), Gk$ xlUFD^a;v&ꑰ@j#Џ_̗edMteVcbmj󖇜DCafb$NBz,祺zwas?q:nzy.h}%.u;N߽0 k͜O QO" =?>G!@+,LjV 9o P#.1=4za=o䁡NJC(''9+""Pt 6$D!2@fDBwfC%Eɉ"S'"kk n'j\h~wvU 8-j_$R*I$E$"FHv=Ak/a8@iDA ZC3tEkqҶ0r(#'&&EXAj`! Ć6"fAȰifÕQqkͻŢZ[q蛸̃1%m`(AH_2la DIh|⭉) y=Gz>UoV+&v3%0b-Ekbk@YYEJ9 x4]Ջ(ɪ'IMi-[Z!E8=~}5v뫭v<3G58gd`WVO8!+F_ u^DX˶,~s⑙7󾫫Y7Id!р= A( $[fWuUgޛskUȈk5PLϥ$s '!absa*&Cws[հ@`9L,Č)3# s.Q$ ^O?you]/ sXxHo0/)w>?j;|l94I!yOG 4#/^ y\efffY^2ػ=Ed;\]]r!A%Ľaݞպ8`a<,:#cR%͍"Y<Sf Xq!.[H@)Ɣ[u|)iz\5_/_Wqt \Ҷـ}Z[uVar;R1Q8@Qo'B@.Ct~pǧ*{4Np\"a) )9{w$9 4M̉8A7bfĸHH)${ dN#q/;2/\h!jh3cdFLJ`z$|Ē9Ӎm?d|Ujס֤MSϦ=*hmbC*Tnu۶}7 ZCdJ{R@?LtP@DBGLl6vfd jLh]&5m^c2mmf!w w ~N$Y!Ab R@r A=Y$4D`tb]}vVQ$'ilaD3p8v/iq|pod͞)ܝڗf0aI %AONDvTRջQ".O);?`?1[o }@Fljb߶w+V`Kf_),;U"%ܽ;=^;3y!M3~'?ןo޼l|?" 0Ow9nx2{%Qsm^\@{v =s[,v٦`nionn>S"\.{Utzx|8hfá~:vKocOi-;kb7 _ɟ Wt]24LC."W3 !! ]n0q6 oO2$$=oA"E00w»~NH"&H7~JW?oj1+PBV-JLBL(qS>*5׀xBԯ N0r%Uw鹕Ii{q`GWd4"c@Н\HЉoͅDH [,eF5oURvɉѺZ۪iӶg93Q*i*\v0-HapΜ ,`oZ}'dsl:9 ˎ +F n ND(M{Bt`^k#"c7׫E8IAF1 NrU2wl")(8?ew0ȐFq @@.\nJ_ 7^\w7 c\GmQ,̉#M&ï\H(bUo`ݻ8'aB7p?sNBE~^n/k7 g3Bq(]&v!Rtz$?iV;q-HDn{wW f=ڷv("9;մa߾}pY۶l6 5MJSG˔\]٫Wmn1=}i23 3 Q]UnsPG$YPAJ Kй-O/5zF~5MR"1RFp p$%}'t"cS4Nk &VpsVOކp4mZH ݛ[t3W+Ba7B]Wueއ9UYr_www?O.8$ ϭnUUY{ dDT\Yw&&FVip~MsJWה6Q(V;%I0[ڄ&`u4 kX(:hd hz! c8Psد|e鷝bA#9[cb!8p:u] DO9T6S {վq!ItuŶ᫛ؿuP@7 g板q'3%@00U Bp(` (2,¨0 }j]^Xm񅩫VD9eٮzGYDz7"@!STkd*Mxc@O5ڨm0$g `d @fj;aLڠw%]Fj6]s(V*.ZNo>b{4uy>\gbn[O9>Xs^!>v:%"!fBΝcQB<@Dh4L@z1Q cC"a:3;`D}$k.!30fAhwL`gClaaBL)Glk:[o߈I s7+( QN90FD&r?rX>)mk)At{,KCjo`Tw ^]_;zƔQ wɹVuo$R\%%ޤ?=&R<  8hĀ jִGIa,,SNYr&[O^ۘմߦ~=|4<鏿s#ͅiF¶#u@hMM#"sn[3A5x*|r]MOuqYf'avtDDfƉ.>>.ewFАc$Hr"v֧(Dp=GI9E͔BeUhNϫ!?YXFn E2sonˁx |:H|!)FN;3 -H!%ԑpԌ̠K44\Z0׿C_dm9U-yQEcMA;9R{4B .P7&0ڠE4vк;'NRD!Zj(†&b6նګZ|ءO;݈rVU9R+mvS>8>[BÅź!֫> 5pkW B-"TS8AΣhxtխF\)0=8;#' `h QQe''o@Sb^ʇ_=BE)8,,"T9QыRQ:JMg) cfT5_B1>>%Ksㄚp "X'us7 ncfiv`|;:|yJ^յ߿:6w.×#1}% bK?>}^?]}\[Nw*'IlGNy]wa}3D8.ON<-Q7jtᠦ_iv@fd0P%CZ6>^(j-R4hQ[g&IÀ<ɔET%eBanN'}kնu8}atfڦC\͛w6(+k2~xpwF;.ytd8dE\ތ7c<=ԳX}߽/YSו xpϦAL pAx"D^}>A/mj7v5CBO#uo7*7%bp'!D ʘ vGW{[׶w& veaaI)]4㗘e<Н {)Bm#!u;?ܙ&}՘Y$ܺAoF sDXM;Fn^wRL,/G9)Mp>4 sאKoR:u)΄(̷3x̼{PPF,S[49)^& ri/>\fo3daI)MJB9KʂaQum[4 o3?qJpĦ=Ҝ=ќo;8˻Og(]o}< myƖ꺮[zjkMM's5Vyy:Ky$KUyTxfI%Iq~4nn]=.­YmX52_O%QkQF$Aw$:c[Ѫǫŧ7m`[ aJD% JaH DeݠXt,^]Xoc8 %fqf59t_=fI: !`= FITO['-(z9DTzn[oSz"!;zX7dY7C+1sjxymӶ)`iYV{̗jVa/9RN 2Ğ]͚^萆T\Z0D; ,98"*sOS2X|kz"]KPD=E95mO&.a=i{)dePn=, SR~!̗6#sLڰ%<.ANӫW@uL89 0V-t<k "ۆ t=)*riɏz*WiLzp.z|'z6mrYu,Lj9pϩd); d$iq{־l{LlbV5%!abU|&v yaLJPJIpznu{d,8b!oXH}k#"O}f){O9ɴ #"0vy }KŔ18m5/B\` !%UM:qhA(:oG,H41kw[Zbܓp,:I.[7,4B!"< nf mܚa!SA;[<u-&\RsCM݅v_=2nzNfVR"M6O\ >o-8orzp7X޺Kqb9sA3Itu(xs(j2(Xǧ;w y(Rr""6L}P:Eixt=B4DEUc)z>xpɘwUρë(e4}otk'x RIHK)AT2;v3wmN7F|sogؾԧ[Ze0p N# ~hdzȄ=CGop}l /.wڗ;vaw=H@$[7wfaO$I"$< 4O<DUaه-6NNaAHFH͚Ҁ#.,pы H%t4vu%ʈ$EJ*m+Â}i(--|쮢 -!O Őrt QtNQs@'kj:"L[J-ku'@)W)hbHUSuM5xhեԇd)9YUx8máyN1]\ gB%h`4Iw ^b^M 3k7uy9G~8! R扵wpXay(9T{w>g|zk0{-3 Z7G{u0ss~ dtV[o[Q@׎5@ ;D=^ MX󀆸ax)3%pvհ>nֻ[-"1rthVϵ=5w. bGEhH> B34V6M!V"e&9E8:" Ęmg hgߖ5ԵumzmľiCF'hN聎DAOA;)cHB1P/А8 Qtڽ_7uӮl;O3rΥn궚G# s-e)$jֶ )`VwD"Dm3,  I&!DmݚKp0NSN9%Ķm^$唙Y8]35] pīcs_ !r"4 < 4x3@g^ ydS4!ڏQ/w^dvpDlnI ֈƱ d>g]a)- Oӏ]cpG,X틿ol,G1v˗/qܶ7K$$|Niu[SJ|:s9=C)e]׵!Qʜku%*VQP7IۓEG)P|:jeb:dpDPt"!pIxͽvd4 y B{~'vXdʐл1tdpB535 ڙx_K?+Y|)~{x~۾AEPaL9j8벮 9%O;ww&ٍjLͣHp"P1Đ>v."RItugƀhpso4;%]Q+ - ! *FڞG&.KNy.͘F)TR,|-ydXt?/_jfo̓D#*1@ϯC8խBL,Ę_\Ib+o/^>ՎKK##xs,NG}U-1_^矽~k̇Ǯx%IA%Ij od7R4SXIϏqld='{EvGW.FT0H;~t}8drCyQb3d Lڟ,\UPK{o>tQ\5!f8XWB9ه"z@'#:0%B&f K 35sMmQV)G_!WGox,dAڥ@r.z{{(0M 2Я% %!8"j]"J{PNW*\ԃ(%r$D[޷֗YSW1յ%_vS nP؛ NKOB]#>"05mlDr.¼41)~mp(R&ݘACHnC|pBXڈhWrK.E1,X"wI]$jK4) \=ԇW( Q Gh!Q1wIhZ wݜ+g_LB${SZʌ)w?$h/!g#m*/o. 0Ѫ_O&9*FWηpĒO._me(ED\j{%$!Zu9]r_䔙895Uus$ӐCJR@ڻ1?֧m>e{U(ѐKkuRpP<_A N(%iE$ƅP83\f0D>wK}P8%n]fZd?|-dxq!ט2 |yق0t: @XG]nEgFx1̡ C!``0Q$)H)iqE8;T{[z xp!oM]լ+0~o%d>Nxu{5_JAB@ʺ* '%MM "B!yJ"X4Akifտ._xvsKI'.Tz_)URB Sу|:X׈;  %pIBӛ)mX ;he]I_ݿ+:?K_ǜNt;pK`?LJom}tٻwO~}z|:ۺ==>u{iv!"?bպCnniUJ;"mcxș@Py$J1䒘EՔS<ڷX"^U.#prgD*"H9g@j@#h ^ֻٳd-sXyNoVz.EZ.IZWt8$䖓3Nhj!&q2Eշ݇y#jR][ؖ']6ڊhtsnCǞat\o0a Kx`:8e&aʀ`dM~OB62ʅX!MkUJY0麮̼OXΩCF4(FwtdLb`}@A@0dFTFK.CN%r]qX6X4EugnV]WkuUΉ8+;$s@1t8KFD1yeFgjUNw1Yq]K6=͎1:2^0>l#Gx0~>SA|͝0ݚp RBJ!@/NZkq ޼HCpD]/v,47Pz![|%< Zo8Jvݍ]:s%iq܋$_Z@|z4ћ5nd\|xDkcu!"MWhyN  ]襤Ea><-χ 6Ā@Ya8\hsPr Bxhφv9~H!D>Q>'_=7! cb%,C}Mi`#e$A*ygk`ъi8a$qeoS䭥w.s@  rPjəpή8zid%,pi[Fޚdg"p_5)*³ĎCh 讙h 5]aRʮ>i-sʎ=)̈&@^;O)aA 1I`B@HcI%' g;RrkȈ{x߿45k^kZQ=v Z`HaؗDiogGg^WG]HB@ 5ԗUP*1S_;%-Iz9ȴLe= |K@B<åh ,6HLi}O[Ǘ0xAP B\hb:q|×nƉ1XRVϕs&@xd-Zmxw_;ͻa=|dOO,)eYZoNeu3{㻇e]~ס<\/o_/mvXR ޟ|8xjw"$eKedWXua$!kh-eY-SN80 e(Fid⽝OV>"Q8 XG@*s' еm!6!}*pM3 O7H5(FPԭkɌ =eF%Mi֚`SjJK}zʏ673npO.zD|UG9a*ÁVAR36ǥxG:֎*t≼#`f̠dk}lz-6!q^k /O)NkI|pr9D].2$;xFS"4bb0eΘ2=/!`*LԼ/0#|.GDZwC[a픧2x@$q#qryFt2[hwHcv'AT$3Ms@0& 8a}4G[(yOk ʼ2$"i.1.JnXERt!ДAdgrV7Dn)z?]چOO2*6%z[*d{uLIZOCn 9~9J9i,y};3:Nup'b77mkRZfIPRII)M,y}lA U6 $ˆD8frqRh)"d>iqL{6$DL$EH,ׯT z{Xx4]1tDHȉme22iD!xyMp&;8=~SeTIawxDɐ^ryzG7ܿFhv^)ģ1Ցk"CT<'Bғ"o|ڷw|a_w|esۨ6p4{K<=:^]ֿyY?Zrw_;6皼~OTVuYSJ8~sssݯ}x8֖%36D_?q_Jy}k]^'b:U3b(v ꫇[EoӉ<խG.L,$vZYSD[3 5{18@Tr(C$rݧ[$'+_0LpvOZ_)t͠blI[k:"P~tZί^Wç'zz/%9PXS;| %)vP5&̴f4!' 3 S6P4E ׭jNDU/ F5CB5 {wX7V"^(:H@wP`-Ir3(BHTF;!a@wiLr!)HSN4zp|8uBff8r8~|j2 ){y)m#%\CSϯnG/ Sar7~zmq5 b_JJ:iyyZxJߗZ㫫wv"w n>6?tAGI$Z]q\˪C#1p?}O?/o?ӷ};?~arn>\f,mcDnU|Hfxz&'7Aw^DeY`LjܖeZr)¿/q}轳a,Kij9\ߎC]s/}M) #vBky`+eX~(Rp[aqgw~manmjnЛ֋>_g'B AA8`&L Fq -+ixY8.,ys_ [σ P_QN3Jٝ.^V,4>txL(MCn?!J~xeaFLKG@Yp]5z@\HC/)'%\VHiN1r@έu*MSIdi_#/_uX/ki?ڄKĮFoʇb,t{ZoF9{= 'v/zN'g@[ap/n-YN9l?G_ݿ?ߜ?4__X)9R}%ck0ne]jϽvaAɜ tuU<s"2g7'Bpaװ09~)qOYwd@BdN; őр|s꽰s`~Q֎nZ,W}iw@6.\FZ~~YsoL/'`eKCD\ÁOrs-Y2Sg3T Γ;|=k`9p_}Z7uChyi>[?#im2 ļ~>/r R_\_||O>j?Foq,mmmV=j@G˧2ގ@/b5H|sB4VMz8֬5v^/ CY -/OvݖW=f~A$S@cFߧ4o^mg`Gfz_tY{\~)3py)9E.puT0JWkua-7&v}WRˇK~:Ttg\u=z{rڑD:B{/~Rbđ<<{e2{Gw>#{awkm#>U}!6ZnRf+8zt 1to߾ɗ/J`MuDCɥBD\`aJÖ 3MByqDTVޭw,qN%:^NGc\w ǂuII"ޟ1<=.13: NٚÁo<\SB&Oҿ i(Eb<8ۭPcn] );Ru5K `!j{@p&8̷oAq$߾k~sey\~}q3`j4viuy26#V1 xUF83 ʐ6Xڹy@؋B^-m;1l#"`Bȅw\q rS| FNPݒuH9D %@1Ppw%@Om,y4HSԊKW;3χ] )~tJۧwPx}ɟ~u!?_>"/;Vʗ/e+ZXy󋣵 V`xi|e>w;p~s-,wPu[7mZj_mzs]u@(v{n[oͻ#P)i>a |-k{ߠ/]t;sC[Z_w6'6 a@D.Ļ]fK] uu )C'\&]` ٳA m"oEQr+m~|h)[N4I)0ڡy~qTx.p}'v %M( [fdRh=ؚGQ FݬD+H,;mn}3,=:K\ez܉y@$DZo8 ɯIv5u[.N]081K~zz ,o>~33^Gx]9Yx~:׭GJiazӉCܡz6:%`IR& ^n=ln4a8x"ǶmӑAz'ѵu rDԦ{;\P)8,3dZqwP-GҌiHSA!]$i$RfϙKMȁ0Kqi-(ɍs* .t>~zɟbo=u2]k.O5> 1q7/oNǛ/_}u|bv{_?/Z 5{o \@p>w<2SrѦˇe{ܼ?K6̫[3ڶ\mݞmTj5ֶf 2eO;vK &!m-V7o aae=7$BB(h>eDR"d302X7E= ^ξŎ G嗛0l2 Z .ӶiV8C/@`f4lc$pywDC20 S}>t UeM+ϩEr#Ӡ//.@[.k#QF~ a{VQ΋Zwu_+#GdqyzɪFD8_܃XϏI4q04s77!; N]ɪn۶,KDaH9Ov<4c*[%"0N~-Gq!@3 4SS>({(t>w/CACL hn8UO_n(0ek)?7v;-?Fy0;# u F7N9eHJ2Fw.%a)§8OZWnkl6Cԭj.<-pIomǒ|^)ŷJxF&[sʱ8vvЋ-FG^KU&ϑ=hݠt͗rV7|yӾ՛{8٨@a~gM۲Gf.7;L{z!4Q;;0?6Oa5 /m ֌`.3/h#~tvݖm[7wM滽YJ)¢ȥ# 0s=qU.O17"E|?ϺmaKǑm3Ay||L9MIXJ)HD-<0 B~j.OrQ E]а%LQwcLoOp[чzoLP/T^ 7zx.p/hok<`ǯ~q"pi8Ԧiʹ Q'1`~L< ̭uoS1#"{y ߻EtQD s&ἤn1Pu=kP(,|ʡ)~Eom "(y X DA;G:C `:9@L$ e 6.NӴݹ~N׼heWjn5A H,A6S79?}DE[|w|>眧2g,9LgdLdÇ=~KBʨJ)^nV]jm)tw #(3?u΅W!oHɤifpdy7 ȧo*wSKs9!EL0L's{۱y)8Q71$ dK!iP-u3i=*pS麰}xVNRd{~;ݯaQxD/?BMWC/Y?}xy:1]nrz+\[4#&a2K ~;tCsoB4! :k?"8ƛU@Bq `x c pXy auY7"ZcZ&3Cx}S7BQnql5B6n.fF {:D Jc Sɶm5 Ssp CV`)NPJ'`* fhΜ|Nx{|vm(!1?~q5AKs:.{/  5QAnbχ~wC7f#/\x[oCT:fn Y=YѵAdIy4圸xʓ] (`f$2m~x7 >>|p@FW]J܆*յ @Lj+,DahXkV?nirs4ySIABn R"Aɥ[9Oݸ}u|] ;9",<dEljvs}VIdty_4ljj~ۗnY|LADq133`prۑg w?xJ?/OO,+}bVX>G\7&o+~ Bؗd.S<,(0`5u$Z7p dLq0QӾw4VR@un4(#?V>bruޕ3 6HNnTG tmskK@Xqn}'tBBLNPrю@`:ymC@D A,_~bCGDI Hܗ| `ONneB%{:v<1Lg>MN2ݻ?lP~=<<})_Toov}ʼyz&Pa4*n,"# YrvI9"DRS#z"}Yz`:݋<|בbȋ4M~tEkf2*=CDq#b|i:pY׾`ak&hSºOSب|J{pwIͦ7S 5o5"@7DX@5RJ~3w-ʎsw`rtӷ~HcnN70 ,7L!:҄0x47u8mܦuO/3_FkNm^Z:[ ?EDmYqIA+ $ xP' Ub_5!D 1[@AkpJC3`Jb zv !SDhSLK41SLS)/,.x:r&;pW@EOSrw_Iݥvז_;/2M)zuΔoVSd}eIvG@1I3#WޟVI뭅G P&@w {.%/E8#P32yMoS;\rr* O3@ iFZp @Zk_|R2S2DDDLęzW7)uOOiUk^jSӮ`]^?z @㠵ÔWM@;FsU {@d$&(s#3 zE+;߲I[RDzqu0D %jBB @ֽ~%}@HǏͶ0r @Lp t=kEݨnӾ @d˜3!a[ :Rx 1\á$^̕9T'&°z"뺭jsN)1`8ЮoeBDvhP5oG"TJJ % E #r%D@$QunH%}Ef$ &A_a|Ax+R7{vE쫯[Ox'IW4 k/Y6k*&kpHU)SiDX?`T{pw[tB1 m|ڌ9c'1bP/8PݻhR̭  VEiII3%YZѻ"$faw"L9%IC v%a!#)eCFU/m[ʅ"㇏uoZr$HPND)'xamulgbRJe*'& U[ *U}̀VAmrʈ%\~[,!#A,I(uC/1 ; s@I]_>i:/_aAhLI٨7h*(fjˆ0SmcRֺӜDr~6,LD2T !ٮ"DT&$̩ {iwW71"ԡj-ϧDx&)i>Dm{4p6MRCsI2%BXBs)$kS@e!fRF -%??њ#5t O}NLl|x:M{Ι֛sF~~W$;"AKjRj_^ !_ޕ kf<,`;!izl74Or9&\n^gV?uGع錑:7 /eخNSJ.Q5u0@̜E[Yh,Kr830 j;Z _/,I)O,y^fbƜ9<0J܃K)DjNAWs3UqKy@`&f hz2gn.)IPnIokx0 ``DFf"|,!\U\w9#ϸ溿\n!o}*~wP&dTvnju皖&ŧÒCn&bJ۬d,="B*3+\J4 ̄8 :ti_t#] )/p?q1W~]-Mx8Trp'I\XܝXG)!{Dʉzۿ>}sN)JIewbrZDH ğ퉈_0bΉ^ )"jf[߶m%׮8 H3 i; 8Q(S!C&tuF ]$%v͔$H<Q2=F^|sILnIw`to|=aqiAGCJ mBDx%_9z*ܵ!x_5@p?.̚UI T[Ŧz۵u]h=< &d`D"%gYy`j0e L\YR y%QL$O⣢֦arط=qưp2>n {X%$BfF^UF01&䞒:&ڜyh) xTNPC>RE<S/C ?}n*~)$Tۧa\+q&D/ ė܃YfڞԐwQG)gp]ivf Ho}F Ȑ5-~ik2rE/?~+b-gǰPV6nj^x:E'.ybfpw9`=NK15DMgH{o·ww_|zKDZknDDʹk)9qQi( ?Tyכ '&F̹"}%~0yD x:8jՄԫ0`TP/LY8S D`G=7 8KTrCv0]n72O˔sh[z#(BLYo;F >y[Mytm7rO0Yr9M\1m%5&$/K'A f-Bah;޽w[qm;n,۾7hJ(TU/ʄP^|±ҕiպڵ璉)0ID70Jd$jD`Fq^yP w L" L.ad noXRp1 3z:g0 h[#?5ǯ0-.A$!Bj۴7}b&&7@m^痗HԵA2 Ht<Ld@s;ً =l(˃/G܃oWզG|,\]@f<[xbt透rMw KC Hi~eN4Tޠ1~ݯDy&?6*|%~|ʯV_wБ&lݵpM?>/CRE[<:3[m*Ii8% :#q=0r Qthio 1M|*HDm4q;if9MӜSi4ʡװnZ @f=ވ 2ϳZ2%c0/@#ZM f!-+f)(SÙ@>o2}NYgz8Nӧ22F3CBn)i_,\Wۭ믠$`O|@a9|dr!U4|8Ji;F4ͥHƫb|#  HM1,+@T! ^1e="@ $4Qf)!œ)ɠ2$<}~: ˼YNytDH& $"v1h)48983xFocba޽j8~8f6p\S6hxm,3ˌRn紑|uzGd"??s۪Wmn,+1/D(?jNm yHR7K{۫oj8J?!ޯۺVk)t:ee:νĩW MK.H0@0nj̛P5,"̮땈y6]éar.Yr@ۻ&JCɅ")S)SFۭr^a]7ND5 l@ӛvpI|^c@H{C Vooh0pڎiB.|Ig};^y)~JzHfoу_=I7jHT#`o|ߝ/q^( @¡GDe 4誻Z m {Y3ȐmZ&q "T{D3&Bp@ ެ5 Tj+#0>YhHa;Bγjs3(%[?9QbLËqXfs`ff@fDQ zECȟotKlhaj81 '5 źM3 2# +Q%ćLhsLG5 GurUӱIЈmersÐaJ\v7`.bOh -|uzkcbJչn)aq(fAI:!wQ͞oxݠ~[kffHܵƜ}JS'dzU!@y`XhD$J Z3p5B~Oz¼Yx""w.yʈ,Ho>P@i)%}iߵ=)K1`-e8jj $dR:r~8sJ]yцDda>$f8mzCp.$ԯ҈sfmW/^/>?>ä/:fv n@wrs2tHdίW MΩVnkkMiB߿̷[ں_A7`^ɍQb{<3gf(bۭ)$ }ojəu"uڰw"V{#aDX0p #[ a =L"r8x:&N2C cCl9gfF 7NDw$47pڵ2!ǎkefD,$B#րK)t<D"pCC Z6})0KUP$ȲWfD8OƱ|9aXshA&YW)7s/ٟ!:{NnA`VETHi_zZ/Su j h(b:2~@ ~뭚d1qI)Mr.ڻ~,Yf @wjVf?}pXIiru䔅-J.//IH!c^iD䔺Y $a @vL>|RIeLwh۳DKΚB礻76,$\qG7͊Y9nW{*8S72;%>Q~Yk-dE(8xOf̖bR@54%NLn[p L#%l=%\1zқE7$"daxzٚQ8;KHBM lAozo bY LF9z}GC(>7ܠHF⏻1I!@П*dx9؄@mtN?RRUL s]WHVI<@x&3NW$ҁ"C` Ha7jKRԯ'VZ痶df>I;p:ƾ7nf~xFO@JH.C3r!_·n][^һ/Ωx>"2-DӇ{mu׵@q<r)㧍@[ ~s37ii8M . ᯾zZ%7YG$afίg@f17WnȘXo@e vN1Ͽ=O9wۅ8&ES͐aQ7dp";sU2!1AJ@ϗ/~{ɐX#7=GowcH)~jY/ϟ\@;uMA%պ>P.[pLjX w%1Z= ?>#֊*5 rtD]5GgLk74t{5xt -WDmfש;#aJ)G@;G"i-K/ UG*brpL<̢ 5q d5"{<,#!vfv[oyJIཻkE7pD+Y#sw>Kt@f]>-Y7&*,Lݼ}{k'!*(r )V/&99ȁk!4*kl_g2-}\\wgxʿr)9:nL.?mp hR47ߕ%1uKn{1Op\s}}5HE$%y*sJ{f?~ag 1$Ocۋ=Ľ9yw^=<։ZL_ _V{էx)侭%gt\HfYJZAh[O|5Ynpη;1r (La1♄ f;2CǜI& :h,;cV]nޭkpUf`>M!I8GZ2ScZ魧V sp aFD4DD9':Δ1 " 55AmrxJ`4*w`Gف"~7ily[DDD8a:&)!g (rY+(,rӽn0ێڮ4ˑD%4.u'W-Ge &L܀ 3R;~Q= ՏFbP=)( v)EX,!"YT׶DX&iHo7oie@n۶ ϟ2eH6l(TDDU!pD|91#ۭR^=N1[s bR [ǾﭷmL;.gOK$N2o1EnF۞bokRp %ս, J}~12B>AOb4Sx;EX #KJ k;2M:PH̔sz[V዇jnnĨfhjsdk̸'v՗V[%%efI\rVۺ&(G T&bcq$82=%~\|SJe*@sEj/cS&ҷK!^{hOD\ sHOCBDWr)`y }6~S`3~buSdۆF)ljU`iՊ1$Jt2 ڴ粤$q<˳?,\;__ה,'R:^s(UwxLxvQph?UC9ysDU"dp{F6(Eo0Tr9af5뜳tBwf [ 'FFdsfM%p[pGQA(K{rsYd8.c:NLә?^wuzw^*JnԻa?'n c!18Qo/ARf)("7kP(H@t"Ц_5##xA122R)H)$IQkUqxAIU|7xdf$IDxx[N-T&$L)ADhnoaa( N4%of~(dcerHo=E8aLna+nfV$F"b!a4H]X pHŌO2͐)0 J&B2 {@ohpct!zHU ar7'aZ^jLj6XD' aO9 Ҽ֤+Y$ 37Hsn^ @LP lW5zxOA )"@@o 4$ӑ_k~<懔RW-Ц!!</J>Q3jJKvkKl?|+_tPW\nkb~VvpI/OŵkkÌ(~]eB.S/ 5sMlCW.cUM`}m۾azUS4\8wD0$L??Q7UL)q"beZq"U+sn} ,@5gKN,E__VCtwXF]>c8E℄thR7[7r؞juwL 9Ml( V}}=PϿy?]{u8M?^CZ/z}{@˾>Cʘ2>( ,cw T)0 BoL@@aD_'lz덶o?X_QhFHXV#")d2rb :zI*qd3qCS@ pmbCg};,g7@i>߭JcVgDxA!ƒ$H¥Lc-#$a  Y74g'5^뛢 Z:*-"|<N 9G߭ݚ6f"7\*Ԃp?:%yt_M|\i:LRBA d9TC]nR_Յncp4#o/N_ف?7H;nrynh.Sb`=09?)eaqP*~H=@ s3a q.O{L%MkeL߆V]F~|7_aP/{N= gDL#zf9 @3H*nC6o6 0vFî98koAIFb@÷-# ȲRJR h ÝR2RR2"C߷[T =zu#>:&Ɗp 7{I(!q!)SD8wU:m\MJ m~YQe&JtýL)K Վ[Hӗ喓^~(vb[qQD[)NN?-_')1vM7D8z`zkզ00 !а lA`ιLXH̃:"'JanHoϛǷ};K?M^!`T8`dyy[77Gb}}Ȍi9O*aZ }n\L-ZtC6 hS$S9GG]WB獦{:͘p\ гs{WArBbym@hUI{\w(dQ8vn O?^S})_V/PF.`LD+B~6}>?'dˢr-v-$_|5"(u]7kQu{w$y'clP v w-fCba} ɳ: N~>"s=r?+::Ƶ6D0omG.eTP<"{SȉGkomof[O۾ºu3JIa* XwS(ID4Mk_jчBBi܆ݏKH_oݱdtD . B){={"G*ܕDVn]P$z+Lh!W059fƭ'UF$Gs4of[k[ݪՔXk^*H8PoZ8"\EHo۾NOx e~_KND|JW~}Im[0Y=Yq6%bXр|v}5pL)aJ)nO{Sē~cCF<GvidS؟(ԍ=$##V[@)ffSff@)IЁ<}۠0=[8QʩRrQӑ+af/{k >8l`p2pAHLo3j77ZT%fRnȩ=sb?΀of-,1s03mLU8rPISc燼]JV1 'BZX;82c$9v9~V =rIDD'e`4V.H~։JkMA5pgUevI @m$LBo wT]oHx:M F6}\pRKȈ(HLXKN 7cmuz;Ffi;$,1}_mumU #H@&Kf!FxCUb:H,2va!'1V۶m["SF>O)I$3γ{9f:(/! pf|<>} NURA@I tk{yI1?dyO5G p( 0бt"*99eٔ.~BFP ޾( s)?G%O-#wݸߨ?;^Nkw 'IܾkA{o[¾)HJH̝PT kSGD`F3$ryO|{eLSQdfx8pxjeao׈O6ޘzDDl"dCB2)l)}`~X77ؿaɩ0!OeI")I&aA$oZ@ te"|f7h99|f,MVb P[ދ{wu#F$; 93DG@;^Qm=HF8U _bx2Lȸ_?K3-@םuG_>|ALÂxmJzus UP@Bd"!J4nʹ ^M50zc lnmת|J(|H8/Dž9#&rݬYi ,Y0)j[[ QœhWN\]}B)wrn9=K9؅ r|t>'J3,G}\FEHPJeIw8wAՑuohf&Fàǭ>a A]Ŀ޶$Bx3 a9,q&lp Za1lժñ<.e(%?}s\F̬"5[voDX|_?~S?5Gd^3w0/S*,9U֛SFfJ|8f@{-Cic˄ӌ䆌0aCY9kx;%!`"z烧/Wę2 h~$ZaO9D0 0a/- zkS6^#i,"D{ a>~4ͳljs] <8Uކb5(%o7^;#ǟ-FN2Z%|]A%LFX^+\A7"f"`IRtH<4eb?n^ay܁oPv!'Hsu%D ^JSp&W5q]R2=7be[XC) sp%QzLs"o)6: h$`EJ-K2M d9ѸrJ1p]Z-<h|<-;I5$)%aau.?ajoyW2j{x&3 f50dd8%#Q'Qmzkp4.xȭ`4^_%e Ywh#_wҚ_|?x:40<;yեܥD˙ħ`M t!%H2Mr  `υ sPQ=(Q'Is&8`Z|Ysa)ӌoSY@MR*&\̺UHJOjտC8TW#Dl&fyc",ֵ[mDIE뎙 t!1O^9^J1Zl~<Z4*BbIu0 RJTl۾mkTD294 `DTS!9o~^ YmxZkoezF]d03ⳡct(T8sQpψQPwȌ o xFR2ur!kh9Fh! pu xprAu'rn/)Fx"4@0&&fA7aÄ %E*'( !%oIɁ t@Ctxs0P };ߟLo)""R0MG mʘҷݦnUvy2 e88E |qw}а:8#OSB N7G3R[YOO|, f<ݰ8cs&~¼)i[lbvj-l⩜r\c;cr-%%cQ#Nwv| ^7,g}(P7/0~KO;v)\kD|G@c2@G,?>q^CpZjLo6lD|I>O¹GvtL5xjfnRFϭiJD>MT+"!l1T>ם=l^朋?2/.fsH" z, '7]E8ip\RjIy' fp0άq{OG38RJix0&@Fre! (ԷKJ|s/' LFQo8jBz#_ֲr:.)~Z&!^nZ7$ fn_5~?$Dp`F40p"MN)f-_ xF@ &)@H(0@BFPvqH͵8uo!&bFq* 8Uv:yIhRsa|AM\ ;d$mSAc>.͚"vݿzK"u>6oGA19cTf^Ĕ_Ⱥ)_,nB`hBF/]הc`oҿ|H26v3 I)A?һW]KPkVCp˜)2uv_>~K)OGUDi~H"PRF@% Hr8Ir`GZ7|{ptx}lz7򑖿r~hoj-O)V0e؈kf}Zq$qɭ9GMI䍻1H.LDHc=84V5^ˆVsE”tym[vއ}c9Zk}ۿ^dUD(DLX2)Jb!l H@1"(bيe:l)Z1Y%,Jc59t{M*}x{k9}YQ6Eui0Zk5L=DGaLd`Z뺮iPRJ i[kJAʜu=]_ L;!ytɐ-GsΒS&±)dJP $#צ0y ,ęl44]BxHɫf"y/g7ӑ /mDfi pju@7yR( r qp޼-\")$DnsQyrO)>avmxjf.IwOJ+m"ԾD| a<feNô;^^^%20fm'$ʛ{»݃M,ZG2f/0q*8(V//)Ak6jMXy!"=%߿+_p<_Oթtͨs޼D`f?۞mMyFfV[_G>2SzNwr-CSnηZٴ{tY˽ö SnVxM))oHxeYNQL'Hݍf1m` ę릯LB"=ҙ׫o,̂z|<0hǴr)X>]**9s))"(eDju *fS[ת-!RB[$a<t|pebz5-">ͰDDS~1JN&OEN/HO.GRʷ?޼+0#cD)'fZW9QRXB cf620ħW 2?}LhW%IFd`8<@%$M5KСy3HowNfS~(pHܑd`vF`kk%|K=i- ؤ,X`-щ@ TEU+8\=QJ} u^~tkSͫ0Z9B w;|A.r}3 {EY}R⫫u^ݽZ-Ciۚ0/d%=%*'ANuξPh1WT*48{h/ԆiЂbr&k-c'5\H0V)SLLy|'~|wmEPhl7e7ĺXzsۦՇLmj˲"SzU#r Kf]x|\}!BNd|ʣKƏ$ 0!&bY&r= "2 뺚s$ɛq EpͰɒ "дZDa<gFC yRk) a᳻gna͎҃ }]Zx[@"<8km9L$D@N5wnf_,%{3j<;:PRwf\Ϸ3O>}Y&e]R $VFn Ew8 *[k6۲-qM48Q~KkrCwJUs~yyzb`U%AN[}ؐn4CM?>6VL_o{X<~zss_ΝFjM-HkE>d,f'8&ʃGN0 w\ಹs"=Ԭ.^Jc2uwv9Z$'߼X缑42;JعVεETjaGH!GMߙ=׷a~xzep]z}idh*nǽޱJ$iYC' Ds"rHJL Fڼs$u]kԭ$(yew\QV)Z'p.,\hd=̃6&CGCP"I:|govqy6lYXDh(끉#HH89;a0VIB,u]r oJ=["ABt GXX68 t.0|؎2&`} s5JQv$vՅ4Kvt'4j Dj,,@K{+1`|}$YP6Z(9|k^Jq 2UIx^W.K~JR "z%.9Ir_ڣᕻNѯq渽bӸ>yVrWFKKD4؇-sNUjXNGb_VkXs?y\nK[_Y+8*SyswZ0t=ca4leꑢ/BuvwN˸jۻK5i`) "WZn۶vz' a|2eEXOJzPײF*IӠ{#P /J޽SFdL0nHAa߼ณPj>a*E!LkaˤtCvJwomn+ :TfgJ Ym5LRPD |Z*D EC=Ow8ưcjSmi3UPJH] e?mƝ{4 \8)$/IWizZu)R e1d(93)nQ\": ӮL)݇٘2ayO9f:+AJFi]1XQQHCE]`vQ[M%ts` ?+qViZ'56|xz}%Cơki ]MrIÊ T䩴Cj41p_N[_2%($7GDMSNLED섉H/ d&ʻH!lXt:niV=qF8y#c!Ʃӛe0,yeZ$Ɣ( M͗&yc{)Mq~9lϥt}BrACH3{P;@r'BXsۘG, #=aK[veㅓH_TRjAL9\ 4YVN';;m';==֒^^"8O> l 8 !T {5E;ff`9&Gk #8jl}^^L$+-$1SBʹͥZk4A@8LL4͚t8( <۾u1O "a3h:7#~Ip 屐 Vr(C-0 TCFg/>{s]V{GD4NcFNA6WwypR%o "eiwGNxP mʧﱝE7LƾaMiEf!>Ѷl%)n\uYZd(2@dqʾsRZץY{v/ fCv˛S40X%fp>\s#$NfvGND&dL!AW17nqGxl#Vzsv`Nd9%|㽴Yxz[PG$ؠ_W^9<~oo7~+(ls:_.>6Zm6cBV6]as'm)afq2 #{~8M(9 Lp9VF!}^y̒)倶rDi {{f|]OO|~:y4\PQ7:om"J4I0KР8HR$f ~*9aSx-ySM0 0 g݆;ĉ#%Z#9NNO<./4`=9ͪyD ˝qj|LXٛAaDv.T4pۈؔMJoe(iH0vckM1%VkV)֬q%"Z47Ii܃jemԅuƈ0i -v:$h4j¡*c}oW;w-Yeds^6$7۰b_w|ZW[?( nH's AAATi?O}rwy|x]>{yu{w;o<~' K<}\S LDF|2H bR@A=Efk,N2[̗ۖ͂\dy;=2R |v?/<gb ;9Y0CRx-;s)q&d05,$, އ4))[jŜX|"G]its""0G݇z~?}_^kPczA[49gAUDdL.r9UHI⍬﵄7%$GNA.V=v+j:+ epQ@uGCeG[]lqXޯd$"i#{k̒4D/Eq0X nb[cu/-9sOLIFQ#`+,IZEݥ<FP꜉ 'sG]mҘExht~ΙN`DOaJعÓC Xt @þrKDb9GN>E gp*-%)(Eh$5)dB4!o)pP:z3h# xr(La]Kx wx3KBDxrx'm0 t1͋1c'Woޏ:0UM;INHH|&gͭ5۪7oOw[LvK$N2H$.vGP]ˡwpuy=C]iO$떯iڸ{ڝl=~ru; 4 #.)u{wfPɥR[ڼ i8Lk"K˘eLyIk8jګVu-&y49ϧNVOƖŪ G$^Ǥo]oԑǢzkO~',|]h3s"mC?Ԏ"i}QqCp~;;oK2ȁ`~]굖\B%zѳxIp `AP,&U=NLuEN%6SpEY/jrNLUEu|0={EpxsT@i H%j#pxvy!YH91SûU!тI(]CT)ڢf*C1{bEtQWD L$NKuøH84؝ $ _\;ߴ%KJ rPȍ3LG<)'5Ex0)8a(nU%)r 9& OFoR?^-e9=ka\&ʦM׶1$pb]+M0*! 5Z汰 3Kpd$B ki򘐁|fb)4%NV׶2=еc3!YiLˇ=`jpFe$ yrwZvjLy pߛH RVNm_yɝͽiwnRJ)=$Xv.vo9@k]8ԎtJ@_+,7%mU"BBq'>ԍh: =lO_!ôL 9AH LXB)v[92B -S-ÌeSBjFbċ&' lN끙`%)rZ疂lqтEX8z((" @hD+80c᠀!}&&LrnyfSu~gU9\RjXfl{FDyj&,ۓ2ZއSCkMH]$"Xx#@:Ȥ1F"0 J@*"B&Dr@CKS"yCHF-RY&/)9%eVsJ|Ȣc |yGC~NoUdXկX$aaPflLQF0e!9N_1 . N`&9dmlf=(I%)H  rggaJ!DAL(ہ(gO@y͝;Wvs%ܭ#:e>_\YJ%4Y]%lwCP0sy ?FDhui(Q*>'rWZ`ڈ{OϷ ] UuG03EOe"F`?~GGE[QE8"4+BWɤ''( { SO!lcgs=ׁw}kf!R~OLzՁ.Q\B€޴ cȁ4AfǞ,<8 ,}W[׵; V7GE2G mZӦj uQ̝Å336M4l#,tX X;1UV]YO FH9;g r7߼uErryY{XUXW4yr<ݿ?܉+B>Hk ʒ+d٪$b˯@pQJݻƿ? sf6`o??6B,L]}g21gnϚ$煘`LS90M%87&Wʄa ;- }e072[8!=w#q$篜iHVZ/g7MzSa_"LlTk{xx%hmܮ PSK9-EXr/Ȕ;c'V}# 0uZeB8F׾ Ȝ_}2[B`JfM$:gUS9(X8}5je{p؆dhOJFб"vIFeF8:^֘ &W&DΉ 0cYmP<@oHr6R>V3%TNp8YЩG+9OgY;> SAw"gdG$i9`8`LEgF  ddNsLKBmnŝ"ʔ}Dj "p"ehݞFD*9݄®,EѤh@ @ ZU &l7K]1.QS]p=ekڒYK&W[GFFY#E8Ap(5'xyigFBBɌU&cy*!m؃{wuVJyCWՏ}s1~sWɽ̓|w|<)ғoosfƿ/mϷǎ2a*^87k@L5$x5ޤh  C-Ȝ CEf#H_bF[ERa ( 6DtF5苘~4,&[-4HgSurQ5l~?[qn/t!RH)Ӳx1!D]]>>چǷφ)5ZLp[KJ9AF:%Gs&f^rFj"&&B90 "6HfNXJޖDLݴZ_]5LL!/wj hEf]N(Ӫ RI@mm.33"᣺ ofA')"h0>M '2ru~3;on'7?:'b< =w=O7On̓wCaиU?>o7TbWd ē'ϿK_/˿ r  Axi,SHJiMʴeK[ ֏ڐ{nO $l\[xu/&MQHQI3r4xXB|7-"""ɰD )Wd0[R)$n'jv`a.e>u_ƾQB4D-Q4")i_nC,Xm1+].ɈL>}.<ޛw7wOh6+F4fN"Ot)/c"G"jM5 ]v +(#1bڼ3OR?7GLXkąjoƃYrJ HvCfOG1"0P~KnD6[;. aȅ/{^ZCHv &A-3zRyNZq^pkX])F;Y1 MڞkR ͙y^fάv$paɡaO3Ç$8f~p|v7wCio($O|޽["IqZE|p~7_jH"8czL4X2n9|Nq~y\*ąv3>0Kqazěצv}?A$e}\u;{ſbBB|J\;Fwnu*Vk {_&vuĺtJ@PN} gI⃤RhCWkW]_\e#n) VtM4=pf4NIŞZϦ0yk[7!pCf FUg C;ג\8A`1K4`a[?̗v&r]ZSjX}`Y3EJp7K#ݎm_1]ikï?saӋ7> b@Rf"G_־)x/3_ϏwG8Gn0L ]bjIk$,䛒6^VҢ/)0movIŋ5g.p-t1\!֚<8X=nld="rcuq-~0_9K~~~j8pwO6g1@%U\Zx'߷mWv糿}dP)zW Z+djL¾9e˸U3al|q0RD88#8 sTrua/=% -z8 =,%̹ ,wOC6DժY7W`^UۖKf&1V۲,;\ʉ{HvkR.%'QRӦy\ᢇ&SNAyDf|zK0g>|c'WO9%NJD,qJR,)mFKw>ywoݘO\||=ץo֣B^]t~O^O}K*"׿ J!!"4΍{ã&gL~x${p% <60 + P׾7fLa9~nnՂYB֫%$9]%[dtKh@>4$,mFH'k5i/7ԼYҺ֠ N2<Xf{|HyWiͥ X&$MPP&cҨ mҰ @I@0$<YTdӡoI-ԡD9IM Fp *>}턉|]a9QF $ol_ۂ)=mmeD#8lie'( `3;/L_2.1EJ8)9%lvv֞s]L+/^Iь\sqVMDx_k 2wT$|񒆄@yiÍRIC7]--sJœSI1/FVWfaK̉@4#=%U`N&Nø*tqa+o.`,y?G(Iey:ԫKy݃YxI<<_NNJeo޻]|1M^TFϞ/*,~f}*kzu?ceȿ:VU*~;ݞ5Q, x/z\$Ћk02Ez{JŵKX>Xl{F:& c~#qqt=Bk_j[zt: u=]qk< DG/y&,Gx+zcY̾181 ff7.ƛ Ö0?Hkxt IZU+ƗO.P=0M{]oeP7_R:ܾw g9?HJ,")K_ q_>h<؀oߒ)*L7gAVrFN<ՏD(4zO"SvPJ o30O_=~^>zJ_;!ªI,O6Z3hw|3g*۳/?|3?›o<~>SmSc[^(PR~sۏ&V/9q{{~/kzCjDXb]0>pB-zC۽$Hd-FM aښ-"^];=;&)PXS_=11H]L$ ?=B$"4jt-cS }zHrpjD$T"$Rev19:+ƌ,thC79|x{wλO`J"儂8 {LޜQdYq=U.K3?|ݘ h)um"̑V/Li(!x[nDL9B['7RWpD 2fj=^83'&&8IҖf-rsucq7e3C[t*ZwcIm۴Ŏ{Dl< ؝K8m8F9^ZIv+@9ɱ4g~ӷ{kdUe+"6S]oΦW+8 œWo=KZw}w|Gų ݂`~ 1NG} 3+t'_ſueNwKݣ?k)XpsC;0sCUl5ڞ8O_v]ͱ>wşia@[mn>r zP9o!C61$]*)٧B;Uu^.sM$d0SՆ WiOQ ?c"9])J,b@>*Z-$ Zm]JB}[Y?Oj9'1u S_E7On_mK+)g+9̭yO6@D$\XWp}Xr t4y=X3 s%FёF"^/<#[G F7\򽚦wyP*M1RW'whaؚ ̒īa0/$]y#LqNӰkP!=764%dԷrA`YUxa,z@$iN"sJaa4[0sNgջ5ܑdXꪭC;I8pV_k&RU3$==:+PoQoZ.9_s^؊z_9ȶH1FZ_Y~Up@z9M֏Y^/Aޒ L)! [sF8$m_ |݃xHZj>F4T`Iv{4Ռ/&qGO~d8߂_Դ@Z6g>ya}q_}f̟>g%%f)ٜx3|g\jRf6>E`WQ9pC dgum=cdaDf̩y 3Zu4DܿCo tV9al\E1v]M۶ٻfd -''B!e*7DxwwZmKDscbfwZr&oSa*D۝8W cs4"uj'e_ܹ{6[Y)LN!`_‰.B a_|Of4E?~ogo %̻u_8 msok_p["W^D۾o5bG1 PLrdzg_}}4v{ahܔ:qJ3؋)wWh*p =͉jduҙ {9 =_GG]~3WsB):p$0$Ի3etD n._7GcV&`mi.|a8Pztw1 Z!L]laN܉NDv `eyw?ڏ cK/7nFz,!7{gӵI>>`{R9܃=E|vޤv'Ĕ2BGBuDx>|?N__zpE \U̳~۠,eY_ztOc?30QE D⏅m |vQNDծ|;29 ?; s5( p6ntD#="h0zNq{ڿ2zOB bN9rI] uIGݘ hQ6UXWɇ,h(Cs '''1XK^@=ԑbNv>k% 9Tssc Bki\ 2E8ǃ3noeN`B$P߬tNޝ?w:۸!w7Xxx|wӯ LMF!94#;; 0=zoNЉ~,gyAwaM RkŢ,zrZޤH& υI|ykvҐ5զeYsΎPh@P.z)ҼINiLZi 55l=s^\8)'ycn,HK >]jd톫Ɛ`HôA=[iӸq It:ohrlDm}DW>+B*}~G>ZxG3 gGUڿ@=yz{ d^#&W1/8֔2?TdU-o8eKmK`KԘӮn^5|qGi]T]{#Uo> '%:Nk*K,cur[!?ZfH](]8;O53&Z+`[ϔ}ߎU0Uu"lwmusC^:R#2$1IhcQL-Bɒǔ4 ߝ ._xop>V0 8qK@XVtLDCv`q_}gO?HS&i FI&5w?KV%cȀV˖&0+Y"„ 0l.I6eр¥垛!6N8Ha{VI!D XXJ)'3'"RUA#Nn)8y(=u9qu-=0,^N4@D)Lp!'$dř$4QX61XXcDnjŲf 5IV40 D)eN{[)Ӗ q+9eޘLЭ攆^v޴SO3ԲYAx{rY_ngAZg .|{v&;kϾVO`y>'Y9VNA7/n>-;ވűOW,h3O:b$  d"(^r^.\DDm'~wKRӂ5^A{'>6WrpmԝE4Q7ZVzpxI$,#Ye.Sd#/Z?hVfc\b+syz4N U6`x;;(n|X͞u0i)gA I)YiX[1Ltk>P^[{`]m!)3\TVd^껊`H30Sh*1% 䁅8f:ImSAnjZw^SfמYMXꡃ**WҦiC^% IiD;1۞l֐b1n6$1X` tȃv9[ȉE((":`<,(&N6ی#'4sߴ1MMt >o~K|/Ƿa s~ gu3>p`m{g~S튙WPL%o>0#lWd?ћ.軧ׯ4$웋@h*lڸw6)T>8fx Tx<iEsDŽ1+ݝ y)} \IQ O*]Ni0:jprJDs8@kTS3S?1p 0Խoc(Tj!NH[ܝXpC$3/xY.=t(>Rlq1GleH}:ݼ~=,̒V+IEJ/F}{of<ם֪f  EKH?9QdNDBRg2R#2& Q^CfyR)eLD%o6MVe]G$-S^H7 C 'Jhؤ*N/̭Mc&w5k t H2 PE͜xi`f*HG<¾E2?g2ˇ.QpcDR&m#`\<4A8GK( wbl}hnje陔fAs,jfC.@ -%JPJ&b!zDVI)QF$0ԔSJ 0A%04 )/ם?>o ![ci\n]+ޯS̔ڐN͈^{>}oz;@fitN7.2%W 9Wq߸>U1ۼ*o:w{/>-u0zMɅga(uZuM??T^S3„\eIBD[[KiJlg@#E]$ēns65 \$wEA~=~ ,y1[g wNUEDB' ᧡'z F$jQ>Ng_"Fu1 ][r ܵYXrhp@Fd*;)nD3 5uRU VYoCFP#x#"qNQ WI&! fӣFM(A!Zx֑}St/qm٭E4B&ޕ09Ff& De;N7"absozxĮl7_rwE:Z϶}2مxk"8$B)a=pd5&t}_lmv24RftUR@_MG[j5`E.'xk󊛜fV*SO76K.P~X,WSS0_{w75{Y8C)2(h18 }GձBe*5pw FMoI8%[8umOΦ&48.zV ޻ʑɄAy`+25kq !O d 4[916@pr$y5d0 ǘ gmIDD$+b(b & |T`*3kV:]QyYp"+IO^2ZC 48᠌'Vv$)W.:aHɲ8; 0M d[wi29_CӜ)w.yUXex6-.ߺUm辋[rXFO xUukΤݡwUx?W~c5C._\Г+LǗк(W|48SVN=kOwG /k@ ..w♊_URbMڃybnR1:FotWη7_F(ssB+"؍};5JycQ#bXW^\ mm{WL_`J挱hSTTLQ/Gnȉ|4_^E5@,saT8"~qAAv1.5tX+W~R%޳+񞑨Yo#G÷/|eookwgTMUe=y$D`RmaIHef  sbP3?PMwק4/f?% Ո}++7 y2L~g%f$3qn|A>nG7}w-z^x3٦Yj ?[@>w:,S>V2vY?wݢ:Rk$<{|KT{NcmE w"RI+f%fT[%ﵷ1H֭%Dbj k D ]}}F8|x_LyQ31)Gu3Eb)<Tndd+ D(h$]ջVc;C=5zݑod/%6aj'_Z| &G7ce1z͔+#vއYnGHUEi20?;K M/~ޭJSӘW2|Qui9;썕~"O 0|ݭ 4Nz+qVd[f4i/F,!3;3f_{nO<ž8|1wfOZbFYDJ.gqS\ 7q`! -h ]Tm۝\*-@CL%@Z2x`b1s#5,wIJQX&WϥZ۲;^ʤZdܕ\V.:ź8G<37,Ʀr0UZb$NW"2W0BkLXhy螸^VVtA`)gfr[yQ4c=v:;<[gtr&D;+iuKJmBؙEl"F qJgG g4dtRj3@ ޽L!/^ˋmWׁ e g|_<:^.+wk2#r)C$"1D4|Pd|}wԼ;vR+%2N9*ZLj\qT/)gTl %wn2bCjhrNf||XfB1e┒}o/׸!`<"_/?j!T(c |}oo#d#LVU}_tEno7PS'5rj~G.` 7_OtlXuAoZ@xa` .` Tlf&8{H;Pͬ2%76L1R*r5{A8W0 9W{U(,vA'Q^\|ˆc{p@ C r3O™1xV5<4 ́=;9Ʉ9+iZC魸 Cm ^TURhb2Z":@ŠŒq ww ζϾÞ&aKko]z|=O""bt'ڦ|΃Bpgw\%޻ӏV/21Ɠ|mT֯}bH)<+1aX^g 8(4T56!,3ƭedBOk-$z:1!:TSÙSL!{?=:Z>тb4b3uw#-|?%K7VuRA hU6u:GLvbMa7xpJa!b2ӌƺ|t"eVU*p_br55u PwyEL֕ټx"ͯ5Y_ߞ)OLD wPSdad1NRa |,pvƮ[0@2VR1|3AlH3X2hBQnгQ9Պ 0-j%o7 PIw#{ ?je:lmێ1yQM\B#Ϙ<$n7</)^8$,1N &(RDW}OۍɤˎLZxa<81Opvtp CnNvn4r1 k^lF%g P2I&A N蝂xYJ!y iٸF$Rd92Т NbԐvZIi&B dkcfڱq C#EW&)"T& X3x 4,gobS``er5ޥ &rs5ot&i YCP\,Lx$;_Rj'=ioo}ayt٧/6gݿx "8:~ȪS0jĹ遭zW?6I*nUuZêV|_}vݼb;NzUus`g}SEGbSjؠc@W? {K+^SOpJ.u&,^@_M 0h5Zj%D"jUj!Hh0LXKqvaw@31 ^XR*4I""Q9d( z A.$81`zu DŔ@뽷% 0~9l7ɠ0X)$Q?Kx)KdgJjX  *,eeQGHpu M3vm@#LleNT_p#s6b"c1F/g'b9vX\bhm,i(̀`lƒ&f2U;IN(Ɓ]!Fg`ԀQjXf0o`KdbJJM4 XbXfR&.L i*=Ao:y*\뇹S߼%?v\7f ڹ,υ J@)ݓUdS-Xu]W굥B p[x<ڊUN,UZ3{{?]Ja:WUU)5J"',zJNԬ$W-1B"hn@H1*\S=T-X5zrVG23D_#g⬰%_g~n'2v5jR\.өs!if,n/ ޤÊ1I,S˶1ebr&l]߱xE8oB27&!?r+mpP\=(BSX@Pr,wy:sv8W $@uff&'37LT=|_DuBF 7A&STKhfV%X@(B (pC#@(p'L h+S d.DdWGb!0 dҰ U$|92pWG Np K]fpIBy?`lEޘ`{$"58I&3!'DKjL UW)HN(LD>A&JR 2}3r88nu. ׃e]jU e@d:R:,5:ևȹy /j)fv|bbB?0Gq4 NZItc{fӤ}6[NXHAOJ Sn'Ο;%aUHO>3}cRɕc$O 1"b0A_wD=3dX_O7sf1VRTSI<짪A,@aRJ۶ϫ*PJq1z=Z>*`s?B&~s0rjDz㷾{-2zUVEKe:N+gH^ԭx _C! "޷cs?u ,Y -3  Q!t_ `1;z؋[ b⢖1@R@.HhQ >%["&^f?sAp6y`+{jZRSRTօ0͌jb^Ȯw{H@ޏ*U:)40Y(]x!kq0@@- M+bfZjZS&a0 EukB^yb|@Lb$Hĕab-/_<$mE8n΋eMĔgM 0Q!Uޞ͗A4={Ijï& rIŪm.xSfn l51=siޭVfE3l+/>fN1RT5nCP?q*^o[ޗf#+ݭ&V//1sΝ|*V*XTGF  Q`o TtŇ>xuP?==9xlo<;?z7<{N` 0Q d֗B@S!aMLK0AB 82 Un`Fӕj|$X,Xe@WUnP($N Ps6jͨ2Pa" ^~A<ݞ> Z֢HC4E乷ܯe!"PT nFLDCB9ZtcHRf\Om۪Ç̉eY#}!EQ״Q!h =fc MWC>:gܹ^K>͹0C׭g1!plm:REG>T0 k(*N,m_{S{Lڜ6V 9{G}7䧃a)W>w\Fta}i^rGVmfJi(#"!]Glr]x?o]_m)Tj*t*&B2HܳпkMDSϧvTYt*<~]o0*OT;FV61H%Xж~pz!Ә,"g0y̡jFEj h#/o[|}Œ~W7$c r]@66w[)aZ[dl ́(MAГ$ѵ[yX\Z6([ V@#s)ԞZN̪Z&ΑU$803Zln \DA^ Y3RrAqnEj_#ĺardQ`4!ٮYZ Ɣ96ы[^洝B NG- MH dYFcuƙyě+)AZDI p`0zKvq$n&8G/_^D39V6DC8-_v|gwc64o[q$p)h>' QxbSjU^srsOb~R\">=osMO~ųg]UXW|ϫ[O~t wS13FV{EFkM[ Zm%M0T=bZ+ ԪtUSfzo=~p^~LʩSG[QT@֝7=Ź3}~t{qߟ<"Y"ÃC_7~}h_ox\ɥz6 #돶L}mOnwӭ;+_<ŔXƉGя'}6}%u!Pum]r!2kIV,_?p7".@ B`&A DLyU< (dՆ'|$!ĹZ؉@FV8i%]@ vs" ,5,*ɪT8b'c"AIb;>۹".LL`Nə!I"V}7I{G(&jD\DMMmC,83yPgik ӈaW 5nήP(Gsٰӌҙ@DU9nݺWb{oP,(hZrg[1Ho+Kz6k/$iG.mDݝE;^G' S|칇oڟ'!ʃ?rNj;pQ5x☩SW_NjrtZ` (n^xPӃEۤVԺ?>^믿 x景٢P xZF\0!C1?ŒV_}}?ǹ¥jpj6+yy?`g+'?;|wZNG؋[C<⬨\8{/o_7SLX#?_^Q~aw?٩fDMDs߄kߘye(;G3s&{MV/%f-/~*=\zWFvjz{_-W fPr6/>oy<sQ(ؠ㞂%ͣĩ 5,[W0ݜD6RvGOu3,s&pZ %+Z -75-d"t# aL ˢj?anM@T a( pnBYzd0)MnBh0 Fnd yYT3 yU=R_ A߹2wξ%M6h}ԥ~K)/ThZ[ZLR" "edk0q0U4^6eUJ֠'S ' vs2\xV"?ys Gސ Sϗv 1F~r29rN-<*ə.SÐ}˗oJ5?/_~}#U_N"jRsI|bdItzr7ZqN;dH֊8h:;+WcVL~cW7n6J#nR@W%B>~?rozO?tZs{㿵YKKoyOw鵍Z ?F?JrܘOn _Qч+/L?ٟ;e~KLYg\[Kh ~{p~ua)_v]03MM 2_=,A> :EzT&w#&&Q؈I˜)'U1ff@"ǐGwˮHh4z3q9zMpmP &i_X訡$'a#Wpe QaT 0ea] h[F!?wL:\j%P@.Ֆ2OقvO7_ L[b/]zݺ" y+ TƲòPVE(3is{ȥxp#dvUlmn\ڭɤޘͦ?#} ɭuA6`=<[ֵ-^v>Vyx_O׿SzD*+j#"!Ry2W qZuwRS+?L"잾´RJI)!5[?ܣ;Ը 3[.4ikwYKwn}i'o~'tO}v#y镐=IibI>0yF^Եee۟uyO䇿V7o7b'%0ٟ/b(9״Jߜ|X,y: abf5nƗTP\{$ԭ86Nmm!kL(2Ei%> Q$'i'jMv"@1n 9y?V҇@GDU?ɉdނM-"|mcW!'灱rĉTAܕpr7ȗbe]˔%=RZʆx}6յ K1+kh/!v1RL%Hnq 87{ |ZޘJ3o>ܺ=|3kʝl4fq`b!)JT$q2iSK)<j%-έõ7̹Mrq6o7o|/bi!s|6(`D2OIG/?z.z{{v]˯\y~xIĹLc`?y1Ɠ|{-k/CD0Tsh[|C}^נZ9ėRj<7LWsyZ[)ZJtZ|>gkuឡz⭫:V^Ur%5c+Z憞6}9ZK)'wͬ1g0՛D왡 !PZUT Wn0#+>wFo%Q%TGi=g=0V`\0A8 EsSq+VR}-F%1@[*O"9Nq!ZQfRP f=GN 89T:2* FE:y9* O DFGL3E" 5 :8`J {g܂y%xHurdb:sD |6r0ݩHd9ۛ W4!qrsϐZ""ͦХ.]+v&FD|!ޔbX]^鏇8T:s$.f֤Ae!M/rkyg(z{' >3jܘ<=^ 7=|mY/~ykm3{`Al@ְW>m75MU1k]7^qcC3ϼ\v??3pUwgFQ'$"1|6_=8^O7~~# Z~O߫*= G>|5_|2Tkf|޶f1;?yq?ƘsQ͊[-ˏ|?'"uʵOGn8wE ~"*|7^o~cgky%O3?uf}3?wvBj7:%#ȇo\S[!O~[vOZ֬|W>Q|X^~;v#D ^%ĀW‡?w>oMݹiCE(G>|ʵϜԔ@k9IG_yj{v˦[|c_إǷދiMjz'NcTY35 Ip{_B@1~K PW&E*݂G& i j"`R/0v2 G$ch`uDhNDNT(baP %P&ʱ6T8L;eJкLً;CۏL={{|0r%?+];{O lkaPKIلtxty8ڝ Na";5 /gqwnQClXLgc`]wwӃ1'.+CM θC]<^^|u-gd>u;o~gyûxL'W  _| _w7|i=a+^{wVӫg>~WQDDF!)~:ԏZG70p:E)#f3wyQ; lMTh%Qq٬t]B(ESRJZ;PJ>)y\IQ=f4Mm; zT}Z-ju;Q3N'IeB 1F"8d@XxcfE3vuCUT*1fJWL"B4'._Y߸W~{ܐ5Q(`⽛M!5oRVe1NmXXIf15@Ge-!$ٮV*q\C\@=* +T&@`&{cT'tTb@nd c.\W0+z>m'ABĈzCWs4zNfcφ﵋ϭ!-^_"!QIzp#fĭl}M+r 7H5HM|^~U|\يc^ʋ'ڜr'ysO",~͎H ύI؆RNk7ݏSٛ з~e_yݟ{V|mm=!R?¥x3[8w_[o=oa#Ǎ]NNpm}k==2{OS]=+>+~臾㾋ԣ9;st~#z/u⫶$Ml*"Zb*M̴UBCDNd$Tc\ A_ZBWZ_ǏˇGW O>_{]9rnXcr~_ѿohRh5a.^`qu׏qqsjѺZN|71UBOŋapEM )VցOr Y}SknP0ɪb sJ31& t^f(%u晸5F; 炐`E<9[V-s@npDE.kQmrQ8l饗m\<>}Q2L'WG m[/΅n]ݙ"XPr=VuSgZ-gv]ܾSu)QbONRtMpw8:%,=C_x s^DI3?N(//tKW\5vf~\E8Ko Dn&T[fMB ̂@'Ex2Bv#=bn~SNH4qnyDD_څ|_^{o~яsΧ/FMal6fU{/mu.e}η779"n8yug"3?YFfB()ʮ4N~by7?ϵ)~zoG=1Ym V-b*i4c;ל;̇B1fZ/_oC)Y]FBd?z< oOgϚB ?~g2W$ zqUY[4%' fN8)paMpi9)ČHa0sY-LP],(@lX'k@dJ))VF6.ꛇH !-FkYC,ZY> ə&›\q4a}0W %_KI6^Vev|/_Rh+8ߣ7J_6[\.eOv?.qCXOfٍxcckU81u+ pr RJ_ktp_C{f W޺qΕ+]7_,7n:sf{FE9(n\r[7ohч:sfLg}{7&wkx}s=upxP;ʾHtNG ',F0j~&Sg+ 'v/tj@\M\Tr>L&j/}.o3;7]ޠ'Lmy[o}ۿ%֝ߋܴRTC\vM^u]}MgagsC>Obpm}_[Ⱥ B/dtY|w?R/?'f)X9, "نrrffg%i;M1ow^./ؘO9^|_/Mϝ A@̏o@E~ko2VNG̨\yrlxhΥ7Lձ.@L3(a087hֈ db\r kӑMr@!Ji9$TWYg[cmg K0lHkLAz@`t<$POVܗ9.,H0ӲVW'PY[USժL~'rx:rm8wܼ-e}}МiKa,{;kv;Z]/ClIT߹=<~B@KB9k:Mpt:~{O1 uk]z3\/~o#C^|c2O77gims~wn- "_}KuCi'3gmWC/gXzW iib%4M1:&=5b.V*̧grΧ6L\Q*RD1Ƣ%P jR:z6);T0dwL&MQѲsIbDR>ԶVYJiT\}],yCiEU&윕XsN-kaRJ.Y].*@QCEek/ٽR 1S}7ߝņJ0f%s銰Lx8Џ )tdLw8a&}EكmmĄztD Q! R32RjiDfVQYK(&@l@Kg]Ҙ HXZsDZIἔ#mUaĦD(ZBBY$-HPjJ4R?+CKA`v*jњ @1;yllcޯ7'dvʚw6֕#Cdu7J lbL^rs2z>ܵ[37׬LPn+zݼңg/@۷^|oڶ F!"4qmp_h/8ڰ_X LVhBXm QƉ,[>.YsUQ91f2X>jnzqsvj .pbKJpHno^s6Xɪ(L]\!Y&kgRZbҕ:l0%7w$Ȅ`$yډq+NMU}QhBi6RZ>ޥi̱8^x4`L p#f"~nBt̞f]-*]v AR\8K=/_p쵫K}|O|lΝT !Wn~Op>9ĐRh'i{s~^3/kw^Uj\:>8l>ۻy`66g%joƿu&~ ՁID4~+(D^1ho y]Lmx\W PkwӶmmU7ͬu6S3fNZץheC د1&5̓H۴s^WЫZJ J)GG{{}?t]ZBu,JZt:'5f0 {ikk ;ɳpjS AY@X8=V (I!!7ˤn]3`fal¡ ̛f1޺Ly` v-+~y“F"cpFQ9i)Q9TDN]T$A0th"`#S[9#\% !ԉA0)!tSUgg6'Y1s˯)DdqduvV"d-oHXB;̜ي[iVGnM?livp@Mugҝ},I@ЪRg83YZ@0HZc6.Veq @6ya|"B?r_O;^xszCʯ1@$put|g:>wf{ύWA}y꩗^}&NdUF#ڿ~}~g7n9:Z]o˛nVP-AX8P]+U{*4jyU:[+Ez3 HpC)EMm Lb!䢦urc`Rofbյ𝎁ڶM)]_i_NL^K/[ X .@}ߧ&Im4MJ!'艪\9\ +Rt҆Tz-L)Z׺\ Fi}/uV;u93nx])[jZ95 e*)t܇GPq~藋e< ydf12ԺÙij2TCAU͍݊ݖ/ "8EBSyMux1:*ɹaFe/9Ԅܼ6S1 aka3(䤬0f %7) 8T]b0ӤmglZYlbjҰEQaBfPsiX~ҖʹD(LPR؝vխ=V]Iu[T2s=Q x((QL\jͩsu P"0"'cnSl4 .ivotI Sni;B\®/uS8#%HM%g/W8PHViF2$He62aU@!Q G¸, B*ϊц]Eׯy݄֔6A 4Z,DP` U/VSdn ܈)PI316Do%V7ÃeLΤ { D`X1ra &dT9"M*>mӢZl흺A>^~5hQS" i%vAVLmH8>sT f>yQ9ֹnlͺ.2Ou#Vxa3X6[w+F4BXZ8YnDm:}b򳫭l圹fwxhܘJ  2MxSQJ7߿wo EUXe5J)!\r),Z 3bl\@sܲ{g220/C6!I`قMQUMG՟ږy׍1kݜ6DfdUe5TUXDP ( J0{' _|eȀ-X"eѤLb݉W3k|1։" 8g9}bgxrF8%Ԟ =18HQ0׺\a;mkJ. bBpfBTe}Äj^ROg/nӇ$_>#p Ai"}ordt`Y0F6  (|=ɘ{xpĐ @A|/.o[lw7=/=B|'_PըO/CO/70`,mִ1sǣh5tW@«p $p@ F|`L]7uؐ Xq{˲#=q5d@v`9,XRoACNfs=$$CI#Cf]^f%DOK@df91{&ЉAe[Rt$Bg24$d"'GG1%$tkۏa݈оj$$<" :6%Dh&YF 'F=v뙼n>==K!.wl]_Q#1-|6*vgN6Xa\S !!X]Mhγ~מs˩I rUTgi_oej/?s߅5SOܓ%FA .;h8D L")n{O%Erǵ7"LȆBfQEΩlB t?~LfzǖVZ; Ǜ|}v+¤\Ri+/tǧ(9< o !z`zA >2fBDxwkIC#ob'Y0E0:P^l: I ;dNs֚Z@h[wwdt6mxmz a`@L,dnNCLD߿/SA<_·.rX~Z[o?_?i S B^n rݒ/e+ 7D S1j)"?)5$<6J̜hG֭޻a6qrX4Ddem*Dz0ܳhnU#ơFqԼḠyTu뭍_>}rl8ne*cS>%CZ3w4F ! o3TpSyE`PsDzxz{YX|kxh62rai:ܤ^.9n9ӷq&"[e*)/[]<S5L",a၀Hν{])+:#r@|}Z R΀< x-tIy5Sw DUE@+4{'#2v []ʕ&Ș3S=,΃88e-t /^G.,{7\<_AnɄdeL%@a)v~/ B4{{֍F {J"-y;? 0t%_[#ΝI(_ &&%ag!h<3832TBjV W tCP |u*<}6W}KO?7jy-%#5fO&5cö<+멧wݛ˧K~"At^Dih\Q.ܴ`F6ÆuMi6N3A6ԓn;29 n!Ȼ՝rFНB Ut*sX6~^9a\VTHN3 Dvv=#N[%2!BxԾJ'{w'bGz/Wu>][>wOe!4^c'\8Sg__7dId-I ?aa\,CẁQMTKf4>CHPr wN=>ӯ֧OY &B LR&Buc[4M6,e!cJ9_7}QNLi=)nusUEHFDTnB-RJ6ZtUJ2qҠ"Y2a\&t9&]5vy76:˼'<۶m)e<uO76v~;t@@!,@(ȂۺmkaMdn[־?>;29rIcO e/M<-#"1k!L ܚy'$! &0tj)O٩yw֢tC^ C[{9%!KGĒe[R[]w0r%"#' p3y""*"뺎9ڈ5[k]D,%MR`qJkpAk5Sy]-1]ey#2r9 f)TEi:QTq[k?K.#.sV@&atsw{swW| [``@&pMo_Uݜ HxtȘ8FDZGdR!F 4c#! 0F $=q["=!!n*P`abR\RUa z]jpGn<7uGwͤBiմÇw~\ d@N] Rr]G}8ou=to XR!^8 1ss?kZ1]ۚ^q%IJv;͞Ds" Kl[JZL0euyT5d7ysohukܶK:>Uj:.W!"# p)sbWӗp;I|˷]p]֭&b(m_^Vg>J'm:R ;A$1r}Ip3];u "4c ;u!7*)Ti{9n%*&`7s&qj0V78Sn{9`ؘc RS]2LQy,^^f6c3ÌN3rbt~}r<BZ0pkB$9F'J3DӔalfc^@$ wGh;O2mm_aƒ {uT$<)@#(On]mt{XKʌng]2_<9wf{y|)xG{UrkЬR2#]801"i?撚崉pR! 92Kn̓L{  u%G3_ˏϣ7]&"ݮh>8lj1aDthWZ}\w?f1 , ;vn锆ir&$&ABѧncXjWGL!gAODY$ $*t~:_;f9@kr&%E cQd<@C[7Qc}[Pƈ p`dT5ov+}|#[9BRk{W p%6p**,dVL<%6o[ᕟw'%88x}ye|lr/ L-X-BAWR }Q71;0H"DL,İH>7 yvt5x})sJJa#Y ]eM9gS 47 ϙL/o_i(1اgw|[V޿KtK7"Fܝ,a\=lly~q?n=_AxӼ"2pT&BD'77a!"IHHBB2lWA)1q$TBLW*0cqWD$_+p*AW"$0XWDzʉFS u9 MemFrB;a_ `cpS`z޽U4J;AGpeضm~O;3PPJ8EIn߈1~N"L`n̐KN<'ZY\~[n7zA LN+!+E%Ɖ`y~'(HEg7(]P':`kIE|0x×˻uz.6Han$VKOʹݙ_a ~a8}]_Xd$EMZT ۉpp3@-@ Y4e᷇Y  `΢xR3?q*B ӂJ8&@jS[s vw0 g/YK`wIHt'H-wo|ߝw> :҄"[Y!;#4K=Vpfud"x2.GvjlHJ8?]m'Z^8}h7qu 0b$>;ؚ#.lBcTܼE("10_7#@L,޵uU$,S_3f隘R/XDSɰ/2 QA ib2PJfjH[Vsz% "hf£DD8܃#i424C8\%$ƪmɻCvL +F8Vn*8߿R,ghD8%<3'$'Dw@ĸLˈ\ɕj=M3S$a! ΄"$ d`=t-}SOs9{8jgl3`~ Tˎi䞸y pX𩥵mKac6D2 zZPoEY.%WN  '!İpp@N{l93\ SEE!$EۍdDzwNO4ծwPrKdetJ^ݚG{kf[juhլ: iJ <31A,pB0Sa3CW™!8eݛ!o[6#DWwˇfWQ,)1|wp!n7oOOśo_@j˩'-ߡjWm6'ߎő blCj<7Wn;z]$'I*iMǀ0r2b@,9zi"˔CmʍbI[=) 0GzXwO~ gf ʜ; AL=:s1#-rxx(  ^U!;%$3Xs3ЌQ^83' B1Һl4H:|# F(fIVf.(2IN9ra@@B&&.X1GHopb` 0xˆӴe'yDp2n'`~Wl&'G0"ڇ_Ja0Ȼ1y)֝,A@ֱJ$!Dqzsc'ݫe8I! ̭w55t t S1-+/́ ǎ5H$EbMgt}os'I'%H¿]#t~ ݵ[k|ly.Rק5y%%<)0̌;/=$AAJܛl7;J2Yc[CU#HKWm DD~yO6^yaaIfc`Su$-,X9Q7_/UwE^O{; Oװ~G@Ehe! ̧ߵh@Ϧ7 RO7#d0hC@c+E\)ִII$8x,Ĭ"JNS*HHQIurYv lՄ<%w‘%e{Na=*P31x - TWm:'DA\m{6mkP1!"Ѳ xo@89&`OS9coxG\y֨m`|wM2q۷G…il!`D!%6\%y.`ޘ9Ƒ ¬qxu\D䰤eS@rȺcd{_#00oOi <: LJHf>2n)V7] P|䐁i"!_Kۥ&%41꺚6kg e'}"ak^[bR7u.vi90 tG@H4- `B+䒉@E\?t}Vk4%Ya~9W`gl#{tP)*>u~sgˢ(Rhq&c(|w|?Z7^+ lmJЃMS k'f'V$ŗxc)2p(Ʊ"*S /pi͂NuG&ͰqLM:0n^RI# ~28;g/8gL"@J֔~SDK㰮a*3px$h5vz64 I%v,tχş ?Z0I洤َ2RN,y"xD|9_8hwAvR ^_f 1C ԕ9i +?`zl@/z}+|P'^kk[!0,L`QVkpH9e3%Hs]Vr@W'cOc +D7JadGBU ! G@"'v rr`pmQRJovz׵קNݪjFH"#mL r)'w}9P"A!fɂ3L!(* viNAD; 8z׮fLĜҘ=$,DD v;~tu#PhSR2 >{mG 7T3baU "; ʠ rxKey 3d"_­xDG`skuЃ"8"Ea^#RDv+0?}$!6[J9%H;hw"H7ZN K z艴6êƎ:͢з+1 F@Aͼ(^}_>ٱ!MjG.p+Օpr"mt@SޫERR-咦,@+k 23O4i j\u7뭹Az[?_G~޿) BX0ķDқ 5\C֞:yzz& u@ﭓ]W;421y׶ys͘xw=O9'* \[nwyɂx^o?WgC vc۷7U\G '19VOo4u@ж99= @sP6NmZԚvΘ(Sc6u񔓠xAmU[M{kS릪˲D -,YDH8 5{Z5"2x+oJsZq{DvdD"`de\SN- "(EU-|{㺻[!G_᷾h>;9A8<{77vH8DŽ!5|xgSBDEO3Du*$DHLN-T )rFqBRF ua H)a).GkjC>2Uqb,A)=њ5Lfk`F%vG@YYEJ9 kckA"{6mSl^ǯڭmDB%h;vni:=I2!'%4x"uC,7S`1"$E}F̂avc7FӅ 7ƾgƽw͵U5Ӱ+uci ,3, $JʩQt 6M 6U?]0*BJv+bvI?i{tyj7ݍn6dn ZnErNDvu[o:Yb#^ޟFR,۷9  fRw#O5p ȯˋdJwl?ju1ppjd2w݀J:r[0$m@8,r&p7q.㑱[rr'4-^ƚ?滿O')po4"|:_14Βi'GԵ7Ζ'w)*Yޏtn_hXrk/NNJ9s)M-Qņakb2 p EHkF!`8v1V#@z07(DÇ_OhL9b 8'MOͺx_<34Z?o_G hXHX2cZ1$spAaS7E"+ss,kKQr ʰ0\ E(c?u1[=.1 s #1kW,=F-36?w ӫ!X04ȸxInw7F$Z Y{ag jfGJk8 ZpJ| ,`2C͂7 B#O}5oa`- (XMjf&&B#v>~/kғ-狨k@0p!'SjXMmo4X_>"Q^X)ƹz '' -l*CD=qĂ9 c )w?pD&i֔Ox~_m 1~p)FjPL?~' !::D?ynQ .gP @H@>ӯNϻD|/P<mwku'G@;(B`{UlB /rXo/a5Gmfxp̎=?V{CM5vw$8W^;OebaZX@E9Gk',=#Yysz:0;2Y8@,QJ% $AY r9凊Nƒ(#eMrYWOF0x"zw&66 nC `o]ɼ?_ #DGF~FF]<;#?h>ưN5A1dd xy סqFOoՋ뱦Ֆ'p1@%߉=/gcn*#" Xh^kCL% 61Т@-0@*avJA_]zmIصn 9?9PddI`Zkr4&w8K6#8`xAbb#7'v"&=XBPQZ)P>/.dN@d8&IMܖ[H /B24,ȅ}Iv}g ^BAL~3p&.Â9Q`EB3z  L{RS$ v^/߽@9 v嗼AK{_09N0 žtI؅|~#&y7g϶UNG$?9l?" {Xo~TDrCwtĔ)6}'*34 M AHqG3E 4FX!aJcT z$)U wىUqE`0 /',6Vrm~LyGd*cr+,)ef弢#ATpt׾xE2`ogm g~_3 [B6k-9$E$a.K)YRIR$g~g4|mr?V޵/l fzH;<<7ni:DV۶m&31&:DHнE7suo[Ca'PL{q}v 8=: ӣ`^됈hYA%\<4 ˠ*#jm* w epDG"aV*LP!:1E]"A:c yXH%Af^n3&ŒLDADDnhi7!'7WQݝYn`D8<.IӮ-Jzs eI=˗ 0b=v!UKxw5 3 Q]U'nh7H,9$P9skawYtFCwGEXRN8x p)y&iL|f&X LA CP { 7̿>a"$ckzAmP NC"RQKH\͖;;j5@ϊ+ҋX|QC&i۟O'Zbn[orgh z ۹j딈Xz I;uB""6@~J  gdDe`}"a:3;`D}$k. !30fI|Y$BpWx.?}Q_'~7M)~ܺ\,߾y#wtNZ'ͯ/'2B2 I] ׋_g AAA[" un)8u+?!I鼞tN352x_k9O4c9Hs& s(`"$~"Y\P#Rqko9SYHSV;%IO:`ZvB47&Y`81'5zH` Gv9?4N_ggjSB䱿94HlH t.e3B߱ϰگ$b᫛ ǹ@A|caP@,EKG0+Lov;4o l=0![j5@L4XC4chr~ٽTswج𽹫f;λyO [@X`2xshڻInBu^rL;|Ո(PB1בbySRJcXn. UqS5 lnx=a(iXCٺKz ؒ撞ݧo(e؆'$B!' ORc6L kDܶͨ@8H"X7g˥r) Dx><:}K\W>+"8w9_t>퐰m}ԴnQiDr.>mcg7MjB}"W;7µq)͉m쇭UU>EHZ)%/vt0 6䑽W ,D,S0;t% kw"3㓷)BFB{&IX?HuZ8C uwNM`+:#!E*nk5X 9)}t}lAiF!?Ki/wOO8 xrZ?WI~ckSĢ9Gqx .5pG8 & d ƥ߼871M;h'굞PB0 OdBI,DP0Dh[p'}kն/0^N]dm>nww6g(+k28Fq3we}bgG}V',>{[?/%#YSו xpk#!^/Hën/mjv;BӅ3uo7*7%bp'!D' ʜM~T( 矿BS$tULC^lr2)RLLKœ ` ̀4BviX3ǔᷳ jDfMϏ萦T\Z0D; ,98"*2,y`!wCt'1(mfB.CRhBVB|)ҦtzM {}߃Y=:ӋGd$7_W@uL89 0V-t<kʐ~ױm@_wO9Ӳuz޶ ]ZE =>ux^[Wn~>`W:p,pDH9pϩd)0cϕJ\e^_+IRRUCWO+HoƑ1#"uև8;=\7} RȜ7s3 rPhAr!$mk(ZN:/S8RP0<;@H*Y#!a DL,t7:$xua"Exiř3L[:<ï$hp=BXOAReaEefm-U:fE۵-w^a֍:3!PPX7CժP:gN Om65Ll\V}\[+^r (MfFEDlΙcIE&O %ޟϊ[[,w3$@CTT<箝-' 5y~|)P`z-Dgs%?{ RIHK)AR2;v3wmnŠFo'ؾ/0~}l}7L>k~|%v8YL(/Eݒ~ݼOK>Ԯ}y܇4#H"nŸp) %t쭛t R9 z1Wq$@0v 3L|UOp[KISCDg`){8:"j-kkqxĉt^\g9ɴ  ²(d&b2Ίf zlD1`y=_}.vu-&\RsCM݅FTr*@(=ׯxC +C% [mme"`vTb!Z)ppRh:@4 ٣GH)18kSgoquZm!#GvnT۱ؾvH;*]$~Qe+KtEt/_/K/B>T_/ko}ȸp"U-SP4[b\2 ѸrM[ rGb{7$x{{GNQ87MB, |=!B]WAͬi*CLS /R/US.ߗ9zHηyrę`y>= ̜AЅ/Y 1xwZPMÙKWBě:ϗݮ%ai.O`B*9u8/d;$  +Ke2|o>^XYHQ6f9Q.8^s~RLo5Zv|ܖ~fw8%xPۧrpM +NGw?4TSIR%552Ϫ]% ݷmsmݦiҮ< 7m̌UTGᆙ[k#9ZB"YXԆ8<, bz'b@@0:8C蝹sZ՚G2"'ScYgbk2=s|ﭺdU]Ź& 4=H?Rz7 $VX$or9{o3[TG1[|'w^k]D 0cN$A  bnXuZIʘI$zfjpcͭ!P;#͌ c]+ygXNENY0za.?i<==>|/O]IIK.>=|ZmOogNYzvmMTJ<)?nۖRVpelO={Bpurbp@' d߽D!@NJ084$@9~,o{w`2H`o-!Q,-|%KA Kp?ڮQ̔zaB~^6c&Mހ؆Hbs{!_]Ny>Gũ6<,y=,wMh};Ϗ?Ͽ+h?OD.0j7gc&D }2`PcA)M:ED4$`}l=C7l!\p< fAIu=H#EDxGP7T{K90()! 315KJ9[YDN{N)SlLRzO2$)(>~2kUM%-m8Ed" ACTIO 0"\b 91 )GBOIJW }H"V|mk<=0YdnfX!BմH]@nO ^?QgۧG(<$97f}'??(,⿔/8ЭX`2 ̌PpHh<; z۶MM߽}<>'Y;ȴm>%a(̌#v6 "$^=5Ls I\51̡杄s"I.pjYRֻuKoj[Frs(Q.W7rIp-V7pS<==4M4sffD<9qSJ޷'g9YjY2 V5 @1Zk % wjd!("ȼsnuO9 ( F@F0f[[r:\2@pfWb@oY'H>w%mNi`b2;#enȂ@tBr`8ͩP !5\X؎o;M{j9-XK[DA$mg`S,=: nn.9=K CG'T3SCB$ _|  Ȑ!&]mLBCIĚG66p$sAI )+c_ߢcА4+['C¡ |CVZ"Yxâe$hu-ޮiS0]*z no:QJ "3! :5GBb/ܲn9/6h_D0M(#[ MZʌ)w_&h ~H ;sv\\IchՇoᗓo~7;pĒO.n۶Ow~MIXry/{<ֺs&i>*G*I`a(XxG0 $i'nz Ng&"wWGlu葩$.풆S(`oeH93Oj@y(I(dJ`fр,yz+TRe(XQUe F}.*ޫ3 ;S|JY('STO}_iyu }D`Lyiaf|-*X? ~L1HHSnE9Sdj "c\sR.ֵ)2Dp(r.A /x"i[fj?qUDLumkɅ}N9"Ѐv0Dj`!Aa;WB0HDLqlGk^77So䭩Uw&9Zk.yνi<q&̷Rno6‰DtSSPc梈>MК32p81yvwKI'ڮTz)U{ 0@0ǯF"BG  %pIBS$ڰ(2Ɠveh$=)f֡|8|D~W<}Go}g%=u~:_.mOӲ.?S>{ߋHRJ34i Mr? ށ?af{^"OY2Z r≦%־v4fڻve,$ݺwރ Iӛ|@Y(w/__ YNN"_R}8NɲjWYo% /n2Sƺ#1[fSGAUkMݻ0HhO5\8yH8$WgÑ4=yoY0zJ;8aW k~s Ix7ߤ<~mM& ~ 2Y8_@[\]Yxy#FyT?4ᔣ3 v_4(؜I:G-rOd^!',ah}hZm}9甒'O1OtgOJ.5perCȅH.1<̭uWr X&at{:ye%V,,B @D(IPj8E}*8Դ!&&BAd@D$)]oT4`_&v>Jq}D>q,-yǟɀxl|.W97L5!aƈ 1 G_z~C Wz";ʩꙌ2P?931o uPA7 I!3M>U#A/?hJ=B#$h靆lx.k7j,J:T޵]|wwkNi  C8̟eAc=ư'ƒJN@qj]֐ñԬY[{jEA )g0=4W+{NZ7G޳mHB@ 5ԗUP*1S_;%ϲ_qz 2-9|' !QZ~. wS4v:?ƭrKfjh!a.4 wR8nƉ1XRWWϕs&@xd-W}]?0iV???8u﫞Ӳ,)eYZo?F׍qGZkk}gwF\~6%q}'`hy)=8a}{있@}K @\ʀţx$;&Zu^,pJLF 2 7#㉅Ix( %y)`gp.6j>lw.WKFDφD?a7zg/}J,eVi9E u䠌$]9"k`ъi8a$qu7oLJS䭥/\0~@A@9>V+E3]qTWM#0JXҒ5ɐ',E'jR2Tٳ/L8f`FR0 PJI/ֺ=yh}}oT%&(АKI"$h.\ )(vM% "N)7L-d24R2 Y3Fޑe,uĈ9L( +WIM(w2]ߦ@d1i{;]&R3={vc\rfh2N A< %SR86nߦӫL?m3Y|dnחWsoJwO@TZk)%w#pn۶Ewg0ۺe5,2 %O) f镃?ۡӳh5mϦrzr {[=?l{BK.6k[!Nӳ >ŗĶY^#iqL{6$DL$EH,nTÄ"{Xx41tDHȉme22iD!b{Mp&;8?~|`$yvǏxFɐ^r9-s}9A0%`]WJ(zLuȐ= б1B/ox|aOƢQm$q3qry3[hwHcv'AT$3Ms@0& 8a}2G[(e5[e^atK4Y%7KO"3}EOozhJ 2̳Vtc"^׶\a n3]BAS-3%mh=uJ  i7w${9MdI"7JBfxxPk !O[ݒ$7"De4_bN,0z<`ݜ $p7 ` F.36nP, G.Cq;٪9 e"2b/"mkh ]$w{<y*LXnO`/ؿҷ?uZӂ r^X'S kTwt0xR,ݡrYv̶m7779gw#<-<==\W?,D^P @)"dȄ1&Fɶ 0w"pJ. KR)08ɼ[x@BoZz$IOčAp|KN_<<Ey5# Wί"#qn]\l1ţYW˖E&#n gwJٝ^V,4>vxLO(MCη<5C:|+xe§aFLKG@Yq]5zyi AS$d`upc.+Hc4'Ęy[qx_xҶֶt!A֣S~/+l1Lf$Bm;Pr[gVA=Vak֚iw]ˇ+"r!dp yѮ۲ڽ8r,ůoE2[1fACJc @  s:# 3 +xïS=Ok|ټ"9*o:Oy{V)kx+D Oog\u={{ rڑDW:B{?( CzIqBǟXJ9ֽr^B߁U).m{p:<PJ[mU ROS.y=Cu?v؝z4B@t,S"AXiW4tsCJ%c8 Әƒ0iQ84m]而.@Bf]#ү= 24NCc.G)Kzq 2 hCz!2 'dS=.Qm~F"AX Ȯ "bяvt֒eIKc<. hse*˻ޯE;p4xfPF 10D$͡ {>t*w%3?zfJyrogu6z` ,i~׺)KB;cM ͟2 8nn!<X?5~.z0!x,:nΌ^/<$ (Jqӧ>i,PKBT̜#ğfݤ6Dהw;P+6<}J@%3 wܠj0 Ͼ?/A>Щrnz0F-¢սV",%3s^mw~ٷ>i} W?f=(upEwsx,p;_ᨫ[7wn`PHWt80y&n͞BHHlxO([yj}^DKrIzNyal}csi78g/ﷻN.(YbB2$@SJ-vri퇬(fZIYV7 il՜n6pJ,$$sɤ(H03zI3 jMr2{48vN\)$1]xLq& t5LĶayO_N!HfB؀p\q rS| FNPݒuH9D %@1Ppw%@Om,y4HSԊ򻥫]jJۅC߮I:kk>~~u!\>"Ç?\7jGk#5;Nk(Sa)ͫOO/}9G~sֶf 2eOs(<6}0Vò^C穮:ގ a[l}mN)%Bv9<a(S ݌{Sdˀ[Zp:L%-[Cmx. gu 03v|1 ju@>DCn20 S}>t UeM+ϩEr'Ӡ/n_^>{M]ɯz7+\^Gm{;'¦EG/gh_W@וy#06[SF돱}[#  2xe"YUv8tYxUv"ba&2s3{<%I4y<Ӽn>= k_iC=&XxXX!$ ZN/:MSUQ[.DIoj`Y 䔒dB ѹ5;Ք "< ю m5vUnAtmp z~A;\P)8"3dZ/q;vWSwki4)A .4C LC%A&%84{ʖRIOvbF%^:BS?V`rss@]۞޴sG C٭rƬŷT߾T;~(.ly:?k>i]6֬_.? r@C9,y8?~y_}Kf2dʈ44hַF||Qd7Gp0 ֪!eJERIgT\f @V4aȹSN02 ljlcPrښi ځRY h;4 X|;TS6z5jLS-|ѷo/_k@h|U:oYehL==xP ZO|`C/zZ?6*P?mO3luslO=]odY"zu)t`h ¿bl;".ADs׮۲mfPeC}F.ew0sqUkkm QE$ 2 WQ&b)Kw?O*3j;goZ~,4Ckm8ÈH2 E$!A.YdʘQ"C8n\Sfތ>w/CACL h8Mԯ^n]nhֶ3)G~ZFy0;# u F7N9neHJ2Fw.%a)§8OZWn[l6CԭjOW.O<}\c'm{Ktu6B_ߍ^0WTuczzl͛yxvPjC÷`Ę10꛶kc9&773L>=U鉿˒K£Â0 !H ܞO-&8O]޷f@ jUq$F$bC9<'hzp z*Hhcjp"pukxr@,.kJ* 9Ĝf0E)ލy\3܇C+> [|zez݊gl3D$pC"w aLy7 ԯ*wSKc9!EL0L'7v@`Lca;R=5_֑oD@ɼR =Um>AHOr"S?vwW}7Q&B?`685007B'$%$ naH Z׶m# )߱0~Y+}%a.<2 Ap3`.֍z]3,/g5MCn([ۖ.狫dj;: [kn;930߳"™xD3w"@E4 Yo^ Ilݥvҗ_:O2 )ry~-"^Է;SdybAvG@1Am>Uk @L2 4,zw<ጀOP6  'I; 9KSN%=ߴei-Zk;2UJD)g'=ITU]TS!D֙)%ER" ʉy%uS7O%]bqG8 f˶l Ihvx'@g#ֺVUi[{tj#X{۶Ɨ+_ߌkoavɯujscCDJjl}swV) Y]jSVALlea Gh͐Rx\VM" ޑ!H.iYǯ,=r)@D mڶ@JIi@bD0\9x@vKn HDUy !M;< Ib!_ )?]oyŢ% Yxû R?,k{y)n@>}Af@X*ݼ_ "dmuXT NᐪcS<"c0`S=8ǵ;Sx~i v#խ[&ܺiUDę[0眉,Ѹ^Z%1 C@ai*<][[ݮ׋.IT M E ~6JJSC^JF"I]VSJf̴/$&ڟ LIqL甗ȧeSn]]^{=!,Lk]ݵ](~S$a1kmer򪩇("XCwh 3H`"(b3@PBwt2AfI%%u4Nd+r.@E AG)YZ%}@H^}{w9Nryڐ 3dUA5JujȘrT$D wek7P#52&@m,̻t(jH%aKX\#ȉMUp%8wۛۜ(%1b435}XZ =8hy"ى]޺vծH,у܂z=A p:r fƀgJ32 2I!aNN9@rpΏQ`x5%{Ծxn}0?QCr $7K鲥""7"mr6ĞI_m5Au?,L~n.s\;rӣ?^q8aixs?W¡Ðooa= R@=H777 ѳLU7VWf I$qJ)4O"g#JTu[ً;o9`e$܉189ծ}[O?m˚rax}ڶn0$ ԭQZ mۺcwP$ L@Zyו3@  2pI&_G^?m" ]"z Pfင$B] Ef1~ 'y+À_Ov3q$Ejz:~ínC뵵!Lam;9NWxw>20㮇 XcsfZ><Ё NsFMa|YqAZ$ЁE@8D |<bum`j7EaA jZC(OׅE8} (") H0#U^\vcۑhfD{}ӇTn$f"Klnlu IsFab2w4'( )%NBFI =v -z !^KS ُifJ̃m밺K[Z,xW+߿J2R^lx0R`NKTѧ"S Fm)؞x[˯ADZt3olBq15Oڽ:b$1b%߫V!p);cbd13GDޕX*C%\zkCֵYmu$s;,w.ZgF dʰ̌ݵOL/{&$I$ɎFDbnۺ+xzz)rYk{ `Rַ$y 2LJGS9ᡦ20 iN>$4&Dta=2NDK9%wlizjK fy<tӭDpi."0xCwg){8!8,r;R~uYOo?\ZS!Pǐd^{Ȅ%jQ;0m}[>i.}Jn,x^d z +k4vg A;nSl3souLb*{XiL,^1 I"N jD) 1K@j,H򎜌47~LT{57Sr26sČ7SUc@DRNQ @DZݽO([‚}75"#3pV{*.OG sӏˆe$n+bCߜ|ʄpjᘱn\Ԥ0O:I`c:x"vkmZ8@ ]/x.!&Af&f!|OB[P7A@$ ߼o:vޫ4|Wǡ f[3t؏?Qʰ="D@ۿ`. R9ʶm;]Dľ@h_glnj醙Dx?$,$)a<D[,n'yȹqS9 0䜅$a `DR1CYTcC{1ܽ>z9O9ZC]קțN' pi:gBwB.#d:f.6 ˼˵6D=EysoVl#~;r] rN8&Dݕ3=(^7^7ihp\֊KHgSJ.Q5u"#4;83'f(SB,/Kr820 j;Z ܟO,I0y=\зuK1,\9c[D@v!3#P*B{rOILHd{jSj{urmNR.G* (4bΧA"LYn? H_}p}f*~1$#Tڇwa\+q&D/ħ܃YFZԐڏA᭔8T4U;oD>wDAdȚ&'|4)H)EoWA`$@XAb)؞[o9;h75gMTx?}`< 8l 9'"߃ttǧNL^/㓙mۚsBn}]}IHYCΑ2gRӾuA@pP9]]#&tuF {n80HK)Ix <0n-O<2|M# zP>˹K}cYlA ;0: ӗ=G 7]tQ%iB jK/WBآ$Pv28`PRUE6fUǧiͬY5P`$@@1QڭM[7]YBɣ2aBF FNYXI)!B݁QrӘ<l<,C0Ix|%GJY,_~9W!r8/%<ќ5{C|߿ZiוUSBI šWI)ro3~56ow"hgȇUjGL( =O}{ztǗ|yӍڇW| >H+o}޸ :to}OyN,褪[s mnae)+˵Ja5/K`k:2uP:(o 1A$iLC_{)VX$$,BBB $'l"0dgM#1:CX6A 9SJ˯@ແ.WϑB}rQ""`HwϴsPe]""dnnDLP.aЍ/ń3RX2=^׀/Xx3-okX><`5{d]F[s823CDTuoiӴ@4ņzWy!l޼$z"]{ڪ޾€p3$IU7f&$ 'y>JpK{}.<t ,"0 dÊct"<y4UU5n><}Zm,Hznn V,@86!甙amz]$`@D!aTE7y3׭9%تi͗0$I2 CGARX$ihtO]-8/6᷇=dAzbq+A }YҐ+&_ V wC2aO{ߏt)0.MFY@K"xe{loD Qj, Bi29|ʀ|sGzw=`ߔΧS lb=ޗ.. ~ _ 3ih6*LY \3h"aՆX Oo?'~}O&lݵpM?^?N9q ufqwjk*IiHuF{+kn<|;E=A.,L{cHLe/rn_e6U5eYmU)'ծ t%OaO0()[s ޜ!ck="#22wBӀW8FνcWغ^qfΆ8{xp s<O[A?~w*0璂ݏe۞Hn\wޥ!b:/bVTcoؕF_K^Xο{l|o:֠)9PUy8? }mlݭ(|d 3]pb1ҒQG# x9\Oi%HDSOu⋶Q~>=cS8Q$〚Sh[BO _{{3^.dMw~q05ޖZcNx: p{mmSZ]z/s S""p=,<'YDf\hGSK){nlvnKF3z^[kڛB@x p<K)$A@"pPr1Ô!0ah];@f='sWRqT뷟6eL>ִ=aD \B,eŬB8epd7zn.oo|ٿoKp/V<ݩՔu>i"0;'UU m7oG(]Ĝ= 2Ÿ) mK(I 7"3"PڈoӢ 7 9i,Zk>8B I!bqݮM3 2# +QRP0s`}*ksBi(Y@# 齺tW _5틐ԟg\ @n[8>;L äiEL^q 䤅ҶPNS^/` ޿OA ~:,%qw-%|]ݡ3(W'D7|>_!+;``k m[_M)s*L?hUЦ[>za(G0pk½v!ְŒw@fn0688q~7fBd,9t>]VnXu%$Rʈ41/H4"rJ,ɰj]6Lm (TJ)%")Z.3,ђb)~5@EE"X!~m7Gk.4*(ͅg2-tz`r)9:L.?^W'G@in)Kb=bܺ}n70:۵#Xd)eB">n/5㏃?X9%y-9] 7 Q;0 Lӄt3mnn,е! $*yD !033b +A7dLh(Gq(!Ƥ4uS^O4$ݠI"T͐ZE66*eBbO_|[ɐ?ڏoX#]/pyH韽{?o(zS~ٶnzztƧ|ިk2* p'PҊCw=֣3R`!WM{ԫF 1 zvCCwxWG+yEAj@!>qJ)!Q O 3B{04+sD vhM|Nf8PHx[72 "C0#@"c{""vg(vqep,sj SCppv`n7b\Km,+SʭU"p""pp0LLՔg (vrY3(_/rѭn0ۆsZ0˞eD %0׷.]8_쩚2K%0 rFtBJDm`.ԯwg5rn>2HAY@cN-Ēdw)Ȣ А$Imcrn772 Zu]{Ly׺{܊-Y%*p;G1 h]/<VCMuH80$D,)D>o \O%<3ɸDbU)eHjCX۶ѺCv,M7>=㶂vJ)8[:$ '!>]J/g%&8 :IJrݿK6O_ձxޜ]۵y9h901b`zZk7Vd|}z3WLkm0*hbD9'I9:\i+Ћ2ňz"껷_5@(j )h2 תNU+~pFļ(]҅D3hz6 Zt9Y/Xd̛ux? ?sN8';A?þ?Q{C^|Ч~Uk+c.KJ;'}y羔˃`5@O@f)tI9a<&Lnl(p_xo{B8WdT!W i]co3 :X(EBXz2 H)2 |^ǙAgcvc\ϧi#b6wm\7zUSY fҨ ,LzYYcӃ@¶S_#$FHAB BWga)t\7"=][ %Ԟ_d)D~Bi+=h}w$-;&K~N/߱}k[U0!/;`L8JkjR'=` Uc&bS$C/YȺm_C$|Ãi Rl66 jA`]k \Jch c鴐o[ڥiSk&"`^|XZpgS}?.i~/+M;+D %p*I8@5)^꫺壝wl+n0{EO_p?J"9j!"D2}YeP`$! =nYg#n|Qb֭311/svC`skNNY2: TE$wG󩔂9y6J!N)YED.<Ƒ`4$)\Ҏ9Ii}}21qJiz ]50=0Q/g̭S)e„Ik! I!S"& ćWN96`|;u:t~|sx]W*vF*z`8{s>`R0iiATpI}z& @fÓ;uതiw9b-̔XJ>ȏoK _e؉Ǯገ ёc2b!Bhp=#@8X# vA ֧(ס)ۯM 4Lpʜssv]5],_' غ#YebXb9%̳ܵiD Q@lgzGtӐLko {ppG愈3 Gr!1݌fVknn^j%nfRn޷=sbLo1Cf-,1s03v*(N1't~חcn.q!NPOgY"f@Qȏejv/b箯Â)%L)i+~?p*ޔxrp^XclȈy:pdnvQ ޕ"3e0ޔX#Dbxj (%T@F\"̀8OSh Oo@fοq2TU-‰ DMǐ "3mHm53no|`nT䟐2$$ŠJq$X7;ޭz C[jN/9YK=[-oE򃻺n Ò|ǜ#y` J_Q}W$zd |CVfBQi"8o]O-5F8/5i )t5 rD)^^zmU #H@&Kf"%ccnb"wص/FozkEX)2iBDR( 7qܳ4ӡllDyI3ZT^%V4i $i_nm=/) 懬du$˱L)(ҝM[U)(!;+k?*{0aY21qӕ3 }q7D [Ŭ-v.X8Iz} {צUDRDbLRRHX:"3%I{`""3nY8|8%|x~'#,{}Xnj `ʒoqr` Ytukhf&FCǼ2a A]8ZUDf2<|.ԖSA;7i#|8Ey$,9#yvV8qΗs8GaB0 "XOy?7cb5(%7؍N7%FN2Z%|A%mV8?*bL3iUJv9B@PVLg.^Ww`wK9AH \phg =Q?uE)8V -au7s^R2z co:Z`RJ(Ls"~cJy@M=Z9 ; {j˒L<jYrN)1z][k ϓV6*:nuzSV֛U! 13H"ӥ+,Mf>GN)3K@ԭVk#RJk}y-]&&.PJXG;z^1fS f h^.e.iXaY~u}Oydܽ¼L,{٬^22SWi&b"fmo][ 3)[oi.N3"2Fh$݄ef10TKMFwJ,? Δ7OD<'ъ[zc L7ZD0 0awږLsq4yg9k#/NazZ +">;׿n !:HJf@)y*]uPhu[kTD29[F~CD5@`kJc/6d;7$E&3si)>:FB3!X< uẄz:Q gD@)(%S'g#߂=|m@T`@è9D~<XvV݈/e˳t$CDh)'"`LL^]k$N 1: KT(O)QBJ"oNɁ t@Ct폙xL m=L76  cC)S.,x^.EUGkD:B+zWql-z2D|m fdIEF " |djԶf*Lf4jja~NKF$N&y=죞0no\p[h.NKrݠ||J|iF wÑx,÷rB!/G{\N5٣7x t 4.bZЃy>J,AEaTRDiJ$%ZpieS)FUӎ1R7O_NTL{)uzg'j?GTW"oDl&fymc",ڵ[mXI?" Fd&fۄTF3e^F/fsH U si= '7]E8ip\RjIn3aX]>c/@ 6Ps` h$\bɠB}=N̗?r@`:̔hvOa>p@r-WN{0C םp23DH O?"80#[k8&B'3XUR/'_`f?Ơ]gJ<0d}}z1='s И) fiiVwǻs!8-5&{+6"Ӥ_>xu{vtL5xikZF)]RFϭiJD6MT+"!b#É hP!&RޛHa$\Vk]՜K@0^ _R& 0xI,1/7H m2VCF|9|1(Bwr>NE| Bf Qٝ/gJBEڝ̣.9A@@pWx߿7$ a&D7: Ơٍ:\jflē<793Sƅ"gg4 `QPi9Z{}=ĤjyʄX %M->@Ǥ5E}"yޡVo{A19cTf (Љ)ӞuU"X܄\: D f2~󏋝)nj{H26Ov1 I)Aӛ/W]vKPkC#$஧9E#Rdm }j?R: |](D,&Kd/eq†po4h/B7[blW$Y}+qMޠ-)L"V'@5D%y|rkQSq7@e !zF9} 29@tL@fr˒y3˸ѓ $"C?~VHD48hkfNSLHaDD' D;͗| m4q:N {sYgHaCR4-Hĉ|w%uXBPO,~ i|sŲ6v018ah 0R39AVHض ` c"Q5kX4uYWIitHXmlH>yD2O~]C Go޴uYX@7WTJ u[d"m{2Yn%u",7V{ a%~6ie}Y h$dvrbTN2dH=T?* 8' Dء]~92Wok6^_N0ã_aw͏,b|mJ]+܏yJ=t_JF^/j?].s&B]\E_234mۮ/3υ8>r?^~2y+;;QsGr;o/ ?҇0 J=ҽx2&=a~^լX@C(g!l6Zv) Y8 {PPLAdwSB9pGKW~&}K^a]9"kEܞ93ikK_˅ T8H )AA%/# ,7#WLP3GD}m9gjXs\q!b&)<I"?wբQA. 4 \i/t̄ >矟* ͂u cf|^5geK^{ufhkFHHXc /eIeffmRaJF,͐ `Ie bZ#pTa\}BZ+zP"hx<̟_7Fu_ȱ- u메 Sf$Rmf^Kٽ>LmVworIIJuԫՑhpў+l7:5ԠaH{gO0R\z`l?)C)W#aJ_%-Dᗻy`\?y%}.tspIϰm4"V;nuzjC< 88-s?WO[9H;BF~T́0g8~^耜`8ryǮ6ߥR-4\,anVSSER@')"9 lld 7DPf#^Bm=mwxGX}fj@u"oq q@t?|N ,B(n0nkuRi,"`X؈y ަ""$ˆ=R& 25@2\WF#q^+@tiUA3SaMpY|~\4VJ1u]EP;엨t q$nҩu߭~h.%OF d`qm 뗏-2Z@6(0 #!`}xE,e[WU^q9q+6Mi.yޥQ$9_)tm-3dtN>r~&4y ŗ'`kSS|~" ⹸OO++:7AxZį}:#ۯr[ *<In Byy8P5s4[MeIo?KpxL"[ӶvO!hϭ,PWuma,1hTn4qNv 1NC]{YL@<=C "wwWѺLjZsvC:!2/Y7.rzyVռPq 0?|~5LK},|8 (, C}ߞ+2v=~S L98ZLf'Tw}ظ]J3Mę'Z0Hfu;3ia@|=SıX>럿?Uw5l!%(rذSގTBLޑݝ옷J0D$B $@wݔ CX02_}_t3Ih4WGD[]j?# z5sF"&a^ 0H,PGNߚp][ ׶m㣎z]EDsf"`ᮭP!:0\ 2Oٺt9ExqZD$(B?~^N$#M$7!yP@hD]m.t!pMozvoooQ0wV_2\*\^KI?׀  e P Ni0U)eL6AQ0(a cE4Jo@ n<4=,bJHa_)!eLvcݜdcw{Oi3zOKNkm 2r\xǥ$6kݚsBTskWz)\D@zu[=7!En8tgtw Mק-͢['K_ID o_^m0P4ר)K nube.H\‘ KFBsW'ߑ[D89pp$ OHs%t1 ۸2ޗV}6F@%^fh.f=D/ 4WOHJbd99Gw^[GBDEta׾Nz+&"iJScz: Ws5Wnٹ;,HػJJe`k${8 aڹQjzLqҔ(V,S(s8LRT|+J5D "\SٮNڝlw><hO<x}_& XJ \J(>~J@U`G7>*1-c#Or(7. <@t:'!`!"ppdJ<ZaL<x QhE#@ !' p3h]_?>J5'1 ǑAvh xna,ҷng٠w.<۵[a.sʄWz:#j1QX5 ˔!A 4ڽ /ߟ1n-!X0Iꠐ $3C נ̃20, xYB SN3WDGeX矔+V |A옽J"+ f$A\ @Ǩ(y'kş^.9aNB<`7IKb&ɥl 6n) J@x\ܝCf4ih3Ĵ =0q"TA "5an#zkn%In~^ Dx ^)ADGJ^ܫ#$ d[ @ts<])!v|%~ϔ.ϗ\v6'"N[]ȝkBE n3JDHkzQƌfԍ<6{ `E_ =÷DH၃1a3!) ! H\vQ1>0BB@ZB(mn9ӭDj/ۿMɏlg7 |aOSkڀ)$ TEbU׿^;Y#<Kݗ n'zÅSᶵ쇷{0>R8?Lh_Q Q3Н+ЕɅ9n!| ;%TD{pDy7fjh#ؙRƾwE aU\A#H;յ"b}| Dy/ =PXK* XN#)'G6FFBU{y~?*FPxA80APL-&i[,.Bk!]dV۶`yZ<9qPxP#'&",!@$J= k=>laD$xx pFJ@)Ⱦ"yFKmH2^BL3 ,D v]aPBF%>[𺊷yuY/Wnr--)D@s,n@X"p7"FƧbmX'=MxD>DYF>4(`a؆!4< ;F3OY?gfJQF-BG&ɐc) k[HҾ1~ vRD&Jdյ;<({s-g[9.$[r0z-w,Įi^%$K9~qwp*uC쿔m#xq2}׸Ofz( ܌$Vd ? `DP0eJ9sh` v8IcxfzW0 <!_H!:xb|~~yy#9͚yDܕa/[Z(x"B^V`]= ;^9"lԠĢN$YF@DG,.53Ĥo漟@D9-}LAdNC5kP*pwK BbmP7oG1e*T< } [t{E7TחV%C%Caؠ!aF[/h(^bniB2QaH" "mH Ar;9#)>b(4j@a8 G~>bdF_ 57x_귿_'%C' )#AX)yw/-@ oE=D$Ȃ A C:RvI=w}+06*)֡/ytd[NɣwE Z2׿uKD6$MX9h38M}EȐG=^:6F(ŭusʜ0R%{tmAH#p,V'wg(BwMyv1gH1nlK`,o4GLZUv9"SJ)Ke{G>"b΋o."?q]*1#r 8@֔JE9/N#h{kĴKKH/ ASDLe.%=<>[x[8\'Bf) S0jYMva=\=e=$TWT޺ GlH oƍd/㇧n??~/%?ݗh /~*pyJ61GA")0uSwΒLdhb;#jXN 1Cy $gXLJ/qq?>QuG Se}00rjs"6m;#:"|OZ3/C>Wy١0 J`l3DgDNzv ǀ Dp!"ą y<Qkzw涰<"bp52P1#S)o-LFNƌ$ %: fk۹ix<=E{- K;\=4Ko4V8v?gӔ[0qo3׳Z?,93E4@PmR^UG 3 +ΒɆ!>"iRik7rM4C}:!tѥU$":"$%VDH+:k(1wOG~R|> phD"fF= DL1z,X݃CXgA=H`֐[G M;U!x|F `_߾y|oݿyzcÒޡ "A@ G7n cksZk1젡 ;> ]/ۺ{X9u0#ӄHSR7nBcMVo1&?㭽G N!\8Ik=M:aszyӇ,yOgT|}Dn l)gu{Y]!s  dWחJ6r@-ў2=`C#j@#$߽D@YSͤ~]Yxڵ{xxpcY(3eBN0sc`s |6kiʤdnDܰU D8zp[O@nN+.LĜYTdz j谮맛 #(8q̣zwֶ:@Y>hh9rmlK.68_\kĶu,ēm@{_١E֚S ף^:;g. B'LBu[z΁!Z' Dȏ x4T 5?f>!"m0J$ ٮI0& C0$!78ngQPB8{F ՠH @\A`UC1z }POOO>>)Iqazw4: msܾ)!008nr iOzwG7c$$#/={}1! iW.#v$n>=]yuu̍EZ)>}d6]`R5Yx%f{]PK waR=UKMBgkL[GJrn#q@2@F%qӒT:il|c|wkj"Lw $  jzK3`f=ִ!vd=qhFS$OҦ^&U'bF"8ͧR1̉eZ/mzh{ҁbQ֭1V$@ 23DZ/(2MHJ"2M) _~m;Fs7H7+^``08[=瞶^k5~_1Z֑_GCUTdb]}*a] rƢ"$GC0U a C6 -MNpS0\zuȑ64Dƺ+ L:A5ǐIMT\ rd&f~/ra &$0t`5 [;^}_?ַ }˗9֓ԾTY":3ԧ?y;k[=ߚ]&5PT$/mprE;@bSF4}o߷=`k\ H8q޷3Rx2H) "&a\,M @} q(/rztZgιA[53fO%Ji)Ku`J1Ζ0zhD9/K6 i a5-˴u~jf>{5nқ2?O.tF釞 "(+#@μJnBR/Ɗ :s `l< Ü+*u! jǤ## %U[M;Vu7N#8k3+"BjYCG9gH<LĤcp{q?~1EUTE ÀL\p/y\Jv1EǼ }?k&1AͰmLDɐBRL2hR3EU`T`|N&Njhk2O먪"zΣ~;+at .𜴘PABmH 0u.v"W(mS\ON[:0ҍv@!WVsLQ h d }዗.V8g~>W_o f "lb{G~7uC[Wm+5Qa9\znmu(%@H--̯˄H.v|Ә 'cZB fj`j cJ!`Wo$WqBDM$%l%"``TDr)t. BOYA 1&s/nAנdh)e ıw:˜rB& <,zCQHf,+iY90)EܭЩU~buti@UhU7ΌUjrXfr$S4д%gDMP$TS``yOf4*cY-V}ߗRr=JzO,q5BD"ēdGG}}7Y3H4A~w|wG~~cV~pTϩMUzjz^xɬ=wߤزF(Z3"L*=Īl# "@)5%& . #hQwÿx|h=\e_JM/9^ vDJ:eVTTHݍ欧>!qsCb=oNjlm{)THd13cJ119@: +~GvVrH U0#jQ2$ С MU4 \j|9qV#7n_;gMHĈa5.p*PY+ @T5Dż+1 sզqN\R]Hx2,[%\r)C;kz@R9Āptt|3ץ*:'rJ yBnZ,mD0f$*YLQM}l9k&B6A})bLb 7VRD@iED6tW_Ԁ?KL@T  2G׸~1`A !FPVBD-hbOk9wnűp6tnÍa/g桜nkkV<<cޢ dE$$&5@,W&\3oW˵jcCWOsYMԓ'%;kXw$UҸ33ϐɴ0Kqr:gTG0`[Dq ;l#W[LϾt5n޸eO uujDpSO]recb RoO?~{#_#`&@VH&'7ӭ3:FDMF9ZqCfDX'zիS;a^XB7't.G 5^x[ww| $TƋ;$,**lϑ[ >tJprrm:viTd[Xm13MaNyTA Rr$愸Je7;WDd5*O!9#DcrJ~:U($5s{n (E [ r-h@ e1@ AȨ2Cf5lS-z.z?I8IY. zd}|5yu)%a:62MO܉ rVADŽs60S,X=αUj(vCERRoar/"٭kmb1Akrtҽ5h̼=*ZDULև+u:MXQѫZ;iIS}$z329ܵ1yh:lBSU`5SDrF-A5 J^5lj=#i6SEA5',}m)\ՃKJS,eo6wYap8B[λ?=9k\2a&n"i3*7ژ} ?O+xV c$"P DDtK_ _g=?/}k"IH|ߏL??g\K>X* !XYmV>d1}6 Q۷!ֶ-Eݙ2g kN#y/ggVp{ ݴ$;tD47 wVy^>;=Opiz2Tc-n`cLYI٨c$AB&tcl ) cL1Ie}qb7މ <s!1}_y0S[7C?T'V(Sy;#Q¨6Zd Ԫ\%}~"zw<zb򹗆)䭛yLj:7^6 C0] nɑBQ1DjNh h&-Ls0E0GI К.I@DI"kCF2PC T 0ViͰBΫj2ʆM~1lDXJٟr;[[ a\:*p33\d„b[QbBc6phjAAT׋SdnOB,24Ϣe(sVGcYDU89_u(إjvw^9I)@s np e]DDng@\HHgݛ1 #1>G_'oo$Gz>]|G_o\|¥K\Z󶷿|P]ڝ~޹3yˏ52T3ֳ .=py2||_Bz7pGCV^3Ȓg>~w'̤#I;N0{CXh+eyU\aLF ØGQU) y4R,2LJ@2h^b ;+ 'E ZJI)*!unHH)c%Kiv96D=2JaU~\#smKY)E !V+E]rH`hu%9܅'"Y) ΕDS -x"n]pW_QM;!_e~Gp~+wΡeOcԇMe,mu@?:ދb(sd &ۮ j!NA` VtLdC%(P]%U!TMuݻwilc'Y\D~_=̟~sy])qLGGG'GÃ\^Nssp2pعt*ʯ'^ϑ bs7&4%Lhfӭ)H).mA=SS!NjL )džJR$G HZUKӘJ.)'jvP1;wP7^t.g׵}17['w?sy-Eg:닄G+h٨Zk):0pb́2cUbdph:԰^<ګw<qb"Mv>v/eKiS g缃bԱ&NӠ(!".`3"!!d1A\2c"rwdo̹RDUJ+PJף5F /;c?JV9Jř#wzQEUEJŚ11KQ"dM66cEƣ&}Z23*#S@j4 9PKؖAtRr]:5jRۀ,rƕKs]h)x*,QA gzcg Cd\YV L$ۨͫB}jhj(qYr)(2o 6*`bU@# b=[ ua*L"a,Y04bqc*c?zZUJ%vNtyG@_hT-bn <qmLXL 1g2 (=@1)xFDFL+3#ԫ0or_sj7酦~;^$b%)ͧZ?4bΥx!YЌHX)k%j*aLʘPD)s+O5󆌰 B '( ̴dbC4:yYTAMUy y'Ds6%R ;1"ZB4Ps̮3`d{c*,b6m2p̒p iuwZ[Ԣ ^ WtD(_.)gΝ vJv`0}!r,ЬK kU9(ENVfbBԍc46ݭ!m6oFl&?q6|#SeSC;ӅqYf1gvf}5`obJ)p%tUǟ賯<_Ư{n]kPHۜc8 \&y_.29bE|K149 &f HQng`,CW=#A^ː^ö/9k i2N6ñk;>7UvF-G(\(L3 O<_g?/7~96O{MO< oBX) jK ]y4AIZ]>/~CwVV1*EMYFwn^˗]h<̷û>0McRAkډ +)N)5Hhc7;\r TV= iVT7ʖO3񰼚"h8&y}F42z{%1tVRVYT qHB"@Q<C|)Ng:(. I)"2ߚ!8FIM]3X{PѦ-(hEhI*;;^Ac,rtiيuVNGU睢QpH U%c0vFbq;35 ;'ޑ#{}ץjʤi_|p/ 3qKN9(Uzp~fSRI*0ZVnRH\eU$TȞ2EJNy#nMiLqsU0abj >FY~2q0ɤ#{nIyx"%MVGū! |[s;YM~ƫP$ 05":|f{Vp* Hrܷ;X쓰 ? ;,%:w1ywIY+90$wPq#gߤiɦ!j(k/×wqr>OΊiHT,%x\j[6O茊UL8m,B&L THE,AU6]_8:91ƴ^L!<ξBh'̋ |Ži 0̆fnEi%k݅ߏ7rR ~&>x\4`Dj毙 g6Z uV_0@ƪ,SދO9f\P\Ą@Οk09NkM#Rqywg]&. hDBŷwH<hQԒ*so~[vNjn^gjE&2+Y`>s pCjxbeض'4tC3X4`Vx#BC=Z~ӝa֗~$CegY'jn y,) *1v}\nDl= `ŀA:6=y?^A$ń.82d%230i&?G\&jba#=lRPAA˚ٗ^'lȾ]̈hc ŀ-3"`w£oCWrAB08Y?wY;'tzGGH6-Cc6r:BN%Id c@H a]zlz:2?v$"$O*K]Gk6q0P -vWZЍDr y?D;~z%/ C U^&xɑJ8Y\ݵX0y5D4d66t3ET6;MPU{ c^%t&iĞ]b zRmZT5D[eoCHnUb=ٛw\`~ۗ.{"5Dk4fV32+V̍#+Tסh"b]m N]PCͪw AQJdlzR4)%eUTSU"2;CQqX,DĦ ]y(mh亄/"8"";$d]ӡTD1$Q3 fU(jMqq9:#B`h'ne-c=K&We,2Ovc!LΏ՗^~eŜ!]vWRl #?vp,-р ÒN)̀9դHz-)bYiM]br}?}MO:>O*= χt}H[tpi^Nfjht]es!n%?MZkK sA|ђ-i(iHJD(-ͩ9[YÞ{Z^!; c7zynP9 W륪oVfDb27=&$cwV`ܯ/={Y_tqRO=[w|懾;z?ӿvdMě۱,/]껇%~O|M¬vy_~n޽il_;'o?{{,/͏>_uD_ހ !o}[߸./M{n cT$ײַOv esf3dQYY qJrh ̧n&`pxxXDזQ)k>X#4t98;s!C#@B:kLE]5I>Jʨ|*hhP^꛽y0.'jbh% Pzk0+HR"w>C !wTL dw 0(9ccQ@o_}4HkDR0q}F@4'[ӱ<<E.k"5 XT#5M!!C+ *PHa2 #I"( M)+Dׄ6􋾖옙i;%!6LyȥS6"%ٓm\-Y)')*z{L)":QjcqP^МiS64 dqՔRH.$1E#T8ny<$i6:D9louٞm\ZS0jp$#m2IU4Uv _ؾ~.D|}'wyiU%K+_t9S_}$loK?Nc9=[ys5̺׾ `{o~o|#=gOMJ{r_ox駻Ս/e~ma/ib}sTCy7ᅣÑ߽}pnd2q,eieY:1R>nߺw~w3CEFRɐ88]#"꜀$ɸJ^<:mM%9t*&t^hbȦP $NOOy˧iʹ(:?*#Yn'Ƞ}rW'g>ohzûG@CLÚlk:'"POfUuqMͺ36@̖c>Oӏ?xeSqN@i([^ziaL鵯yW 67P 78ECT 8 Oӂ%>bLиp 眏=^{$LȢ'y) q疫L&GԌx12Ifew@<ɣjR˖692cFٹd2t$ [~gzt.`(ćev|\4+@Ve5ijl^ug5!:=?~GUܹs7o\}^?mӟߙR݃;};;/ ;v<0"o:G_d!fS;Y/ˬ33I8fE"Q4޽ud\tÆy&b!gι1%b\bk\3 "T @UJ.z\W|g:7Q޽}x|&{I=*}idΖc6^e 1/Ue4-EQK_BU$Iַ sXV0$JS +Qľ%$<ĭ۸խ< wi旑;- CRjj{[N8?]2Ny* Pq#sT<|ب<99vfځgia,P$a)~@ 113P<ۋM܍ܰ9b좧Hʪ,%՚KL䐘}p!nEdjFy@7;Bp&dy^{ LC #.8ipL%Q|~S, U]5DV,YB䃃ry*f|Dz'7wlJ'!6zc \<ʞ_^,_̈LR/8e^)@mWs8gf`zӓ>ԳWg~?ܧTTDEEUUZ3wyx?οSu@GҹK_B/y~ٟI=|‡snP3U} ~gK+!Q1#'ןGi;}cc]~Rzۻ>%;7oYHN0wynn܎M'߸{׼5/ ccdǛ9=h+"{4$4mZ5i_qV|?zX@ `0%$@踘Cf%$ $(*\?-"%%pH Sb9-q9!9=ZWd[mBҗ0'-iy'X) bzKDIupJaY3y Llkm,0)b4QO!C t%-);"LT0:490$$1ŤX@r,Wa@`j8{^!0'jxg*z%+JS;"Qdj+Ɂ%U >٘rR5`J[*UeǮ攳HUEF1h<Ǯ`My̴#  Bpy&#.i)h]C ]Y!Зyi[ƦiLCC5$u~w9w1R(u%^kܷ_y űIdfr$*C? gA^uIO}wc~'}{?o?R3Q7>g>KO]zs_U__{k;|痿+"}}Ǟ2O|gf[7<Ѩ7}wo?7nW=ՏEyg?Z~ן(R֫ !!تI>/'>s]xrà 6|6"wn߾|lܹۻ۟'MobTUSZ nY#`vj0CS!)hI1^qښc.X{Rڶ/#3;x`2&d7! yTJ=D@0躎 D;9'w&2:O&otKTdJ+Q1^eą, 9d.2084s˸y8vQ#]۔v\.+<:镣$ɱL%$.3:fu)Z1Cd$"F 2qy"DŽ*8IӢ&]:IM*f7;-2W7Cy>0Dh)SIL.lz$QJZ`\cGt\{8hfƠYQo4.^aJ=TC7ۇ'fOs };ݓoT?3>W/poiLg>v~V/,׫7Oo'~= Lڭ_/f?;3s{[n\uxڝ_w'~[Ѓ^e^ҍ뇧k#|&"xl}i??]0S{d:%sl=>\-W}s>rv۷}ѵkڶe"rxttXrA/t:f6e m`$|@$Comqr8L7SJ>8f!|k^ʩju ^}L Ue|TSQ ϼeϺyo2'>W!ywJ۶c}=g12;w!콛Ng?Ͽww'm1B|85iL^ܕ\~fqzvݮߕ=A~5z[YEUiHFlNL.StbI)~w}{FhgJ.0fw#& D(f\PwqukBZ{&`^!%fAeT[Q!fa L0""FJjD˗-葄} MJXTjau]2Z K}d99T^ܻtqR}`*RG{tZdzs|CRrNG)"&ض _8>9)޻&v׮r6tҵ]ķ/SO=v L'"꺮{:n%rO%g睪J&BCwqE'dLcwphsv'.(Gf|u  *08d1,grS%kumX48K)4, -$aE&B)CvGswt\d(C؎Th\yE~wM0Yv$lS7fm& 8LB>9[scz`k'!3%Ɉ\2#)72Q1pCw Jޜ(fƆ ,fKM`*ZKC8Vּ@&+0a$ V_a1v?E$A6RadbF"0~ТUS>N1mT^n]v*xL/ "US1D"RAб{s$R6jG1u&a{aX 2Q*y4 {W&\9~V=8O 餌 bu ɰV!*L%Zin FEFSnCYѼwU_ ^{h "rEvW8)G`.6 e„ !:3IJQ P"̀"|4< (C8A iAAt@H!\01O< **-F) \}v(/J1QKܰg߹i#" П%gm Babq6a:  072)8ͫqg:JJd g aMn$xqU߆p|D9xбo[Zuc@@$100BB>"d43+EW&wPTbΘIaUI_CD 0uD+K̳ٹU36WA8~~˟{8,7/_ёa6N3f0ŋ2 cj{`D";NNNr){D2iSNlP%QD6+UC\ GLU$6t:=<< (MRd0-T,h+c޼b`cpAʄ0j s +giFYG)]؛6S"d|xmgҸbenPw^Rb m9aV ʲpCaM2z 9 @ X2['-Ki)1"cA35vy̔AETD @z9A֎gVj fY4A<0 0pCXz;0BAJԏf#u&Dž tFHrRcj<#[80*J!d5$L&ZL*YKNL1r[A8Lhw/Y2Avz<'6uI?_.,,`p4૳v+L ѧ! @َz*ۑO-S[T%D8cBEc~M56 УM gjL{nӴzϿ j0q}lͶ3#;FD򸒍yьQea@3n*:_ЅV!ge+ZsRqwwTc jnBpLcJ%OONΟ?Ae_J=쨈8C,ܹug{gVhҰJ+fܑCEME qՓnZ,P-2%9d_ .js"DIfލU!_:o`cNj' PBl:)hmQYee`hqDB癉tE 2J)@s)y\Fi}m W4بfn^8sffTJTT@HឫCT\>J6hB) p,ÐCcYYN EBkC(V jIP"a,=*S%T ys2dvG1U]eXaBhdbMQ40%͗Ƽ.y]߿Dݻewy}WNh(Z)p$tqa$F%F`Ӝ^ %]8x7S +7GK gGU@d kM tA0Lجh5hr3,xJݱ(C@45bhXz)vg簡q 'DB0s,K403)|kKE"\@"q ܌d&VsRVߓ"$#B0n?HD ˘FUK9Xlb4ʑR4-s< zLU iD省 4 ػEL߼h\RJe,;;HGC=)]/żrx,zn!"ǑdD@ "6̽:Ab=" pNbkE 3K"FXDI T A -@ENٍȳG#:jdlDJD-2 }\Vacp%(Yg5c%$,%3z( Z {̞lD{9bс9Ӭ=D!twF19:L(|xd)xlV08SH j\sBiK:^* '{%IYܾuԯFܿߙۆkJĒ$' HH^@S%Ogz4,Rbj@l۴gu TUw(m! C 0SF;謩T30:tG|85A)l% u2jŦކS"q?g>&0鴪ɇ{%&~ ?яUTMC H P^m2/?8梢iLǠcT*"GGXU0D< $,|9eL)聠͐{CqFf(E8 MӜm~QU5SRF@`f3jce-\WŠ`j7N9:# [73+%² 9I0R1g$D2tK.ṳP&Dyr, P 8 Vb!8 1Y50^"Y92j 500G+**%1)U?"0G "+cLC@G -k9BrPHCS( ӃE">1^~eƸENnōK0e <qf'׊n_HzN:W>ܠ9DRC4TR1^ 2~75e1+`dj@в9! hog׫+fg 24VﵞpvXԿld /$Dz yfq˺"H.9zց21T̙ qy_z>3BǨs권4CYXi4$ӘRbsM)pJ(" h\rҢǧ' ۖ j?qPPy['HD!xfB0\n_eٕÝS@I` &KSpK_ ` hFNDh/Ȝ: HaZa5$PbkJuD YrPJJdEcD[g#wöiJЌ&&u5,V'N˺u d݆Fjly?Uּ*J*)#HXQ ``(&3rP(tK) x4#{U L՜T>&W&'wrT+⣻~mu֍}b{bIʁV>nw^W/`" 㘑cl9ǿfb%q7#燷T<z3\֥@k;8tQZ{dyYo/D߹]xY!\|^r:7X ~}of8@ .ܼy.񘜩YUT׋ܱ!8绮zy})#D|t34"2R?U+G*3s\CatmF70H)1~*5\D CPL)ž df$"Lc }yS4MlT"5"P=͙xJ'(< @B-xiܝ"6e7I"Ip`e;`U `B' %08a !qx\`@dQͩt֣Q$,j1*}Me4H9CLEYd@֌eШ%`(窋[WN̬e"Mq:sڸ$I|JkO*݃(pai@P"ĉ l! ۏ$h::Eؼ& u|δ]hkL%W7/]r±qv38~WF=h`l]fy~~K%Z5<rxn`R61M]V,!ODms,%mc9ouޙqG0Rt᭵朧7Ossn̰%gj|>eQ.XJIz~^^mRRXp }h 96) XnD&q$>l6F.%s;D4% *LBs)k$琴jk{4-^>"B#Rq[ $@&=)1n\wKN6ˆ&-r{( ;'NLdlT$#AS HFsHozSPRH0R4HDN,cxq)CT5R44bS֔T c":-`̃A-ZoAtGv-Oo~G&",HYD}[ݜƑaCyo90q `*b=jY﹂8W D䥈ߨLP!l"@U]^Xa3-i%@,֡IjBs7_o(] ^JcQLO-\?Yϼ>\`ݎ'OHtZ꜉F>r;D SSB#Yx2U AhØ} f~ض}j3Z1aScrREAK{.#p >׳1/_~nw!gUa` &fec^ʿE\c Xo**#X*"’SuY5%-K5 w0sZϫj-)'+ImkDX{ߏnºHϷTXDP[Eo2S'|.1i`f9#289+˽×A:qaW)yގ˜9AT$%Qa%pp0:nݓsFD`pnG"vb 9kU$ * Copyright (C) 2004 Markus Brueffer * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "mainwindow.h" #include "misc/config.h" #include #include #include #include #include #include #include #include "kftpsession.h" static const char description[] = I18N_NOOP("KFTPgrabber - an FTP client for KDE"); static const char version[] = "0.8.99"; int main(int argc, char **argv) { KAboutData about("kftpgrabber", 0, ki18n("KFTPgrabber"), version, ki18n(description), KAboutData::License_GPL, ki18n("(C) 2008, The KFTPgrabber developers"), KLocalizedString(), "http://www.kftp.org"); about.addAuthor(ki18n("Jernej Kos"), ki18n("Lead developer"), "kostko@unimatrix-one.org"); about.addAuthor(ki18n("Markus Brüffer"), ki18n("Developer"), "markus@brueffer.de"); about.addCredit(ki18n("Lee Joseph"), ki18n("Fedora ambassador responsible for promotion, testing and debugging; also a package maintainer for Fedora-compatible distributions"), "cyberspy@cyberspy.ws"); about.addCredit(ki18n("libssh2 Developers"), ki18n("SSH library"), "libssh2-devel@lists.sourceforge.net"); about.addCredit(ki18n("Anthony D. Urso"), ki18n("otpCalc code")); about.addCredit(ki18n("Kopete Developers"), ki18n("KopeteBalloon popup code"), "kopete-devel@kde.org"); about.addCredit(ki18n("KSysGuard Developers"), ki18n("Traffic graph widget"), "cs@kde.org"); about.addCredit(ki18n("Bob Ziuchkovski"), ki18n("Icon design"), "ziuchkov@uiuc.edu"); about.addCredit(ki18n("Tobias Ussing"), ki18n("Testing and debugging"), "thehole@mail.seriesdb.com"); about.addCredit(ki18n("Tim Kosse"), ki18n("Directory parser code"), "tim.kosse@gmx.de"); about.addCredit(ki18n("Peter Penz"), ki18n("Listview column handling code"), "peter.penz@gmx.at"); KCmdLineArgs::init(argc, argv, &about); KCmdLineOptions options; options.add("+[url]", ki18n("An optional URL to connect to")); KCmdLineArgs::addCmdLineOptions(options); KUniqueApplication app; if (app.isSessionRestored()) { RESTORE(MainWindow); } else { MainWindow *mainWindow = 0; KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); KSplashScreen *splash = 0L; QString splashPath = KStandardDirs::locate("appdata", "kftpgrabber-logo.png"); if (!KFTPCore::Config::startMinimized() && KFTPCore::Config::showSplash()) { // Show the splash screen if (!splashPath.isNull()) { QPixmap splashImage = QPixmap(splashPath); splash = new KSplashScreen(splashImage); splash->setMaximumWidth(400); splash->show(); } } mainWindow = new MainWindow(); if (!KFTPCore::Config::startMinimized()) mainWindow->show(); // Check if an URL was passed as a command line argument if (args->count() == 1) { KUrl remoteUrl = args->url(0); if (!remoteUrl.isLocalFile()) { if (!remoteUrl.port()) remoteUrl.setPort(21); if (!remoteUrl.hasUser()) remoteUrl.setUser("anonymous"); if (!remoteUrl.hasPass()) { if (!KFTPCore::Config::anonMail().isEmpty()) remoteUrl.setPass(KFTPCore::Config::anonMail()); else remoteUrl.setPass("userlogin@anonymo.us"); } KFTPSession::Manager::self()->spawnRemoteSession(KFTPSession::IgnoreSide, remoteUrl); } } if (splash != 0L) { splash->finish(mainWindow); delete splash; } args->clear(); } return app.exec(); } kftpgrabber-0.8.99~svn1214766/src/kftptransferfile.cpp0000644000175000017500000003177011276037142022257 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftptransferfile.h" #include "widgets/systemtray.h" #include "kftpsession.h" #include "statistics.h" #include "engine/thread.h" #include "misc/config.h" #include #include #include #include #include #include using namespace KFTPEngine; using namespace KFTPSession; namespace KFTPQueue { TransferFile::TransferFile(QObject *parent) : Transfer(parent, Transfer::File), m_updateTimer(0), m_dfTimer(0) { } bool TransferFile::assignSessions(Session *source, Session *destination) { if (!Transfer::assignSessions(source, destination)) return false; // Connect signals if (m_srcConnection) { connect(m_srcConnection->getClient()->eventHandler(), SIGNAL(engineEvent(KFTPEngine::Event*)), this, SLOT(slotEngineEvent(KFTPEngine::Event*))); connect(m_srcConnection, SIGNAL(aborting()), this, SLOT(slotSessionAborting())); connect(m_srcConnection, SIGNAL(connectionLost(KFTPSession::Connection*)), this, SLOT(slotConnectionLost(KFTPSession::Connection*))); } if (m_dstConnection) { connect(m_dstConnection->getClient()->eventHandler(), SIGNAL(engineEvent(KFTPEngine::Event*)), this, SLOT(slotEngineEvent(KFTPEngine::Event*))); connect(m_dstConnection, SIGNAL(aborting()), this, SLOT(slotSessionAborting())); connect(m_dstConnection, SIGNAL(connectionLost(KFTPSession::Connection*)), this, SLOT(slotConnectionLost(KFTPSession::Connection*))); } return true; } void TransferFile::execute() { // Failed transfers aren't allowed to be executed until they are readded to // the queue and the Failed status is changed to Stopped. if (getStatus() == Failed) return; // Assign sessions if they are missing if (!connectionsReady() && !assignSessions(m_srcSession, m_dstSession)) return; if ((m_dstConnection && !m_dstConnection->isConnected()) || (m_srcConnection && !m_srcConnection->isConnected())) { m_status = Connecting; return; } // We are running now m_status = Running; m_completed = 0; m_resumed = 0; // Init timer to follow the update if (!m_updateTimer) { m_updateTimer = new QTimer(this); connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(slotTimerUpdate())); m_updateTimer->start(1000); } // Should we check for free space ? if (KFTPCore::Config::diskCheckSpace() && !m_dfTimer) { m_dfTimer = new QTimer(this); connect(m_dfTimer, SIGNAL(timeout()), this, SLOT(slotTimerDiskFree())); m_dfTimer->start(KFTPCore::Config::diskCheckInterval() * 1000); } emit transferStart(m_id); switch(m_transferType) { case Download: { m_srcConnection->getClient()->get(m_sourceUrl, m_destUrl); break; } case Upload: { m_dstConnection->getClient()->put(m_sourceUrl, m_destUrl); break; } case FXP: { // Start the timer to extrapolate transfer rate m_elapsedTime.start(); m_srcConnection->getClient()->siteToSite(m_dstConnection->getClient(), m_sourceUrl, m_destUrl); break; } } } void TransferFile::slotConnectionLost(KFTPSession::Connection *connection) { if (!isRunning()) return; if (m_status != Connecting) { // Semi-reset the current transfer addCompleted(-m_completed); m_resumed = 0; m_completed = 0; m_aborting = false; m_size = m_actualSize; setSpeed(0); // Wait for the connection to become available m_status = Connecting; connection->reconnect(); } else { connection->reconnect(); } } void TransferFile::slotEngineEvent(KFTPEngine::Event *event) { if (!isRunning()) return; switch (event->type()) { case Event::EventTransferComplete: { // *************************************************************************** // ************************ EventTransferComplete **************************** // *************************************************************************** // Calculate transfer rate for last transfer, and save to site's statistics if (getTransferType() == FXP) { if (m_elapsedTime.elapsed() > 10000) { double speed = (m_size - m_resumed) / (double) m_elapsedTime.elapsed(); Statistics::self()->getSite(m_sourceUrl)->setLastFxpSpeed(speed * 1024); } } // Update the completed size if the transfer was faster than the update timer addCompleted(m_size - m_completed); m_updateTimer->stop(); m_updateTimer->QObject::disconnect(); if (m_openAfterTransfer && m_transferType == Download) { // Set status to stopped, so the view gets reloaded m_status = Stopped; Manager::self()->openAfterTransfer(this); } else { showTransCompleteBalloon(); } m_deleteMe = true; addActualSize(-m_size); resetTransfer(); emit transferComplete(m_id); KFTPQueue::Manager::self()->doEmitUpdate(); break; } case Event::EventResumeOffset: { // *************************************************************************** // ************************** EventResumeOffset ****************************** // *************************************************************************** m_resumed = event->getParameter(0).toULongLong(); addCompleted(m_resumed); break; } case Event::EventError: { // *************************************************************************** // ****************************** EventError ********************************* // *************************************************************************** ErrorCode error = static_cast(event->getParameter(0).toInt()); switch (error) { case ConnectFailed: { FailedTransfer::fail(this, i18n("Connection to the server has failed.")); break; } case LoginFailed: { FailedTransfer::fail(this, i18n("Login to the server has failed.")); break; } case FileNotFound: { FailedTransfer::fail(this, i18n("Source file cannot be found.")); break; } case PermissionDenied: { FailedTransfer::fail(this, i18n("Permission was denied.")); break; } case FileOpenFailed: { FailedTransfer::fail(this, i18n("Unable to open local file for read or write operations.")); break; } case OperationFailed: { FailedTransfer::fail(this, i18n("Transfer failed for some reason.")); break; } default: break; } break; } case Event::EventFileExists: { // *************************************************************************** // *************************** EventFileExists ******************************* // *************************************************************************** DirectoryListing list = event->getParameter(0).value(); FileExistsWakeupEvent *event = Manager::self()->fileExistsAction(this, list.list()); if (event) remoteConnection()->getClient()->wakeup(event); break; } default: break; } } void TransferFile::wakeup(KFTPEngine::FileExistsWakeupEvent *event) { if (event) remoteConnection()->getClient()->wakeup(event); } void TransferFile::slotTimerUpdate() { // Update the current stats if (!m_srcSession && !m_dstSession) { m_updateTimer->stop(); m_updateTimer->QObject::disconnect(); return; } if (m_status == Running) { // Get speed from connection, or use FXP extrapolation. if (getTransferType() == FXP) { double lastFxpSpeed = Statistics::self()->getSite(m_sourceUrl)->lastFxpSpeed(); if (lastFxpSpeed != 0.0) { setSpeed(lastFxpSpeed); if (m_completed < m_size) addCompleted(getSpeed()); } } else { Socket *socket = remoteConnection()->getClient()->socket(); if (socket->getTransferBytes() > m_completed - m_resumed) addCompleted(socket->getTransferBytes() - (m_completed - m_resumed)); setSpeed(socket->getTransferSpeed()); } } update(); } void TransferFile::slotTimerDiskFree() { // Check for disk usage if (KFTPCore::Config::diskCheckSpace()) { KDiskFreeSpace *df = KDiskFreeSpace::findUsageInfo((getDestUrl().path())); connect(df, SIGNAL(foundMountPoint(const QString&, unsigned long, unsigned long, unsigned long)), this, SLOT(slotDiskFree(const QString&, unsigned long, unsigned long, unsigned long))); } } void TransferFile::slotDiskFree(const QString &mountPoint, unsigned long, unsigned long, unsigned long kBAvail) { if (KFTPCore::Config::diskCheckSpace()) { // Is there enough free space ? if (kBAvail < (unsigned long) KFTPCore::Config::diskMinFreeSpace()) { QString transAbortStr = i18n("Transfer of the following files has been aborted because there is not enough free space left on '%1':",mountPoint); transAbortStr += "
"; transAbortStr += getSourceUrl().fileName(); transAbortStr += ""; KFTPWidgets::SystemTray::self()->showMessage(i18n("Information"), transAbortStr); // Abort the transfer abort(); } } } void TransferFile::resetTransfer() { // Unlock the sessions (they should be unlocked automaticly when the transferComplete signal // is emitted, but when a transfer is a child transfer, the next transfer may need the session // sooner). Also sessions should be unlocked when transfer aborts. if (getStatus() != Waiting) { // Disconnect signals if (m_srcConnection) { m_srcConnection->getClient()->eventHandler()->QObject::disconnect(this, SLOT(slotEngineEvent(KFTPEngine::Event*))); m_srcConnection->QObject::disconnect(this, SLOT(slotSessionAborting())); m_srcConnection->QObject::disconnect(this, SLOT(slotConnectionLost(KFTPSession::Connection*))); m_srcConnection->release(); } if (m_dstConnection) { m_dstConnection->getClient()->eventHandler()->QObject::disconnect(this, SLOT(slotEngineEvent(KFTPEngine::Event*))); m_dstConnection->QObject::disconnect(this, SLOT(slotSessionAborting())); m_dstConnection->QObject::disconnect(this, SLOT(slotConnectionLost(KFTPSession::Connection*))); m_dstConnection->release(); } } Transfer::resetTransfer(); } void TransferFile::slotSessionAborting() { if (!m_aborting) abort(); } void TransferFile::abort() { if (!isRunning()) return; Transfer::abort(); if (getStatus() == Waiting) { if (m_srcSession) m_srcSession->QObject::disconnect(this, SLOT(slotConnectionAvailable())); if (m_dstSession) m_dstSession->QObject::disconnect(this, SLOT(slotConnectionAvailable())); } if (m_updateTimer) { m_updateTimer->stop(); m_updateTimer->QObject::disconnect(); delete m_updateTimer; m_updateTimer = 0L; } if (m_dfTimer) { m_dfTimer->stop(); m_dfTimer->QObject::disconnect(); delete m_dfTimer; m_dfTimer = 0L; } // Abort any transfers if (m_srcConnection) m_srcConnection->abort(); if (m_dstConnection) m_dstConnection->abort(); // Update everything resetTransfer(); if (!hasParentTransfer()) update(); if (hasParentObject() && parentObject()->isAborting()) disconnect(parent()); } } #include "kftptransferfile.moc" kftpgrabber-0.8.99~svn1214766/src/directoryscanner.h0000644000175000017500000000735711276037142021735 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef DIRECTORYSCANNER_H #define DIRECTORYSCANNER_H #include #include namespace KFTPQueue { class Transfer; class Manager; } namespace KFTPEngine { class DirectoryTree; } /** * This class can be used to scan a local directory using a separate * thread and create any needed child transfers. * * @author Jernej Kos */ class DirectoryScanner : public QObject { Q_OBJECT friend class KFTPQueue::Manager; public: /** * Class constructor. * * @param transfer The transfer to scan */ DirectoryScanner(KFTPQueue::Transfer *transfer); /** * Aborts the scanning process. */ void abort(); private: /** * The actual thread that does the scanning. */ class ScannerThread : public QThread { public: /** * Class constructor. */ ScannerThread(QObject *parent, KFTPQueue::Transfer *item); /** * Aborts this scanning thread. */ void abort(); /** * Returns the directory tree that has resulted from the scan. */ KFTPEngine::DirectoryTree *tree() const { return m_tree; } protected: /** * Thread entry point. */ void run(); private: QObject *m_parent; KFTPEngine::DirectoryTree *m_tree; KFTPQueue::Transfer *m_item; bool m_abort; /** * A method to recursively scan a given folder. */ void scanFolder(const QString &path, KFTPEngine::DirectoryTree *tree); }; /** * A helper method for creating transfer objects out of directory structure. */ void addScannedDirectory(KFTPEngine::DirectoryTree *tree, KFTPQueue::Transfer *parent); ScannerThread *m_thread; KFTPQueue::Transfer *m_transfer; bool m_abort; protected slots: void threadFinished(); signals: /** * This signal is emitted when scanning complets. This object is automaticly * destroyed immediately after the signal returns! */ void completed(); }; #endif kftpgrabber-0.8.99~svn1214766/src/checksumverifier.cpp0000644000175000017500000002305311276037142022237 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2005 by the KFTPGrabber developers * Copyright (C) 2003-2005 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "checksumverifier.h" #include #include #include #include #include #include namespace KFTPCore { ChecksumVerifierThread::ChecksumVerifierThread(ChecksumVerifier *verifier) : QThread(), m_verifier(verifier) { } void ChecksumVerifierThread::run() { switch (m_verifier->m_type) { case ChecksumVerifier::CheckMd5: break; case ChecksumVerifier::CheckSfv: checkSFV(m_verifier->m_filename); break; } } void ChecksumVerifierThread::checkSFV(const QString &sfvfile, const QString &fileToCheck) { QString fileDir = KUrl(sfvfile).directory(false); QDir fileSystem; QFile file(sfvfile); if (!file.open(QIODevice::ReadOnly)) { // Dispatch the event that we have failed the verification ChecksumVerifierThreadEvent *e = new ChecksumVerifierThreadEvent(2); qApp->postEvent(m_verifier, e); return; } QList > fileList; while (!file.atEnd()) { QString line(file.readLine(1024)); line = line.trimmed(); // Check if the line is a comment or a blank line (<3 chars) if (line[0] == ';' || line.length() < 3) continue; // filename.r00 C46D96FF QString fileName = line.section(' ', 0, 0); QString checksum = line.section(' ', 1, 1); checksum = checksum.toLower(); if (checksum.length() != 8) { // Dispatch the event that we have failed the verification ChecksumVerifierThreadEvent *e = new ChecksumVerifierThreadEvent(2); qApp->postEvent(m_verifier, e); file.close(); return; } if (fileToCheck != QString::null && fileName != fileToCheck) continue; fileList.append(QPair(fileName, checksum)); } file.close(); // Dispatch the event that we have the list ChecksumVerifierThreadEvent *e = new ChecksumVerifierThreadEvent(fileList); qApp->postEvent(m_verifier, e); // Check the obtained checksums int done = 0; for (QList >::iterator i = fileList.begin(); i != fileList.end(); ++i) { if (!fileSystem.exists(fileDir + (*i).first)) { ChecksumVerifierThreadEvent *e = new ChecksumVerifierThreadEvent((*i).first, ChecksumVerifier::NotFound); qApp->postEvent(m_verifier, e); e = new ChecksumVerifierThreadEvent(3, (++done * 100) / fileList.count()); qApp->postEvent(m_verifier, e); continue; } long l_fileCRC = getFileCRC(QString(fileDir + (*i).first).toAscii()); QString fileCRC; fileCRC.sprintf("%08lX", l_fileCRC); fileCRC = fileCRC.toLower(); ChecksumVerifierThreadEvent *e = new ChecksumVerifierThreadEvent((*i).first, fileCRC == (*i).second ? ChecksumVerifier::Ok : ChecksumVerifier::Error); qApp->postEvent(m_verifier, e); e = new ChecksumVerifierThreadEvent(3, (++done * 100) / fileList.count()); qApp->postEvent(m_verifier, e); } } inline long ChecksumVerifierThread::UpdateCRC(register unsigned long CRC, register char *buffer, register long count) { unsigned long CRCTABLE[] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; if (buffer && count) { do { CRC = ((CRC >> 8) & 0xFFFFFF) ^ CRCTABLE[(unsigned char)((CRC & 0xff) ^ *buffer++)]; } while (--count); } return CRC; } long ChecksumVerifierThread::getFileCRC(const char *filename) { register unsigned long crc = 0xffffffff; FILE *f; long totalread = 0; long localread; /* * Note: different buffer sizes may result in noticable * different performance depending on system, so feel * free to modify. */ #define BUFFERSIZE 65536*16 char buffer[BUFFERSIZE]; if ((f = fopen(filename, "rb")) != NULL) { do { if ((localread = fread(buffer, 1, BUFFERSIZE, f))) { crc = UpdateCRC(crc, buffer, localread); totalread = totalread + localread; } } while (localread > 0); fclose(f); crc = crc ^ 0xffffffff; } else { return -1; } return crc; #undef BUFFERSIZE } ChecksumVerifier::ChecksumVerifier(const QString &filename, Type type) : QObject(), m_filename(filename), m_type(type), m_thread(0) { } ChecksumVerifier::~ChecksumVerifier() { if (m_thread) { m_thread->terminate(); m_thread->wait(); delete m_thread; } } void ChecksumVerifier::verify() { m_thread = new ChecksumVerifierThread(this); m_thread->start(); } void ChecksumVerifier::customEvent(QEvent *e) { if (e->type() == CV_THR_EVENT_ID) { ChecksumVerifierThreadEvent *ev = static_cast(e); switch (ev->m_type) { case 0: emit fileDone(ev->m_filename, ev->m_result); break; case 1: emit fileList(ev->m_list); break; case 2: emit error(); break; case 3: emit progress(ev->m_progress); break; } } } } #include "checksumverifier.moc" kftpgrabber-0.8.99~svn1214766/src/kftptransferdir.cpp0000644000175000017500000001302711276037142022111 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "kftptransferdir.h" #include "kftpqueue.h" #include "kftpsession.h" #include "queuegroup.h" #include using namespace KFTPEngine; using namespace KFTPSession; namespace KFTPQueue { TransferDir::TransferDir(QObject *parent) : Transfer(parent, Transfer::Directory), m_scanned(false), m_group(new QueueGroup(this)), m_srcScanner(0), m_executionMode(Default) { // Connect to some group signals connect(m_group, SIGNAL(interrupted()), this, SLOT(slotGroupInterrupted())); connect(m_group, SIGNAL(done()), this, SLOT(slotGroupDone())); } void TransferDir::execute() { // Assign sessions if they are missing if (!connectionsReady() && !assignSessions(m_srcSession, m_dstSession)) return; if ((m_dstConnection && !m_dstConnection->isConnected()) || (m_srcConnection && !m_srcConnection->isConnected())) { // If not yet connected, wait for a connection m_status = Connecting; return; } switch (m_executionMode) { case Ignore: { // We should just deinitialize connections and return deinitializeConnections(); break; } case ScanOnly: case ScanWithExecute: { // We should initiate a scan if (m_srcSession) { m_srcSession->scanDirectory(this, m_srcConnection); m_scanned = true; connect(m_srcSession, SIGNAL(dirScanDone()), this, SLOT(slotDirScanDone())); } else { m_srcScanner = new DirectoryScanner(this); connect(m_srcScanner, SIGNAL(completed()), this, SLOT(slotDirScanDone())); } // Switch execution modes if (m_executionMode == ScanWithExecute) m_executionMode = Default; else m_executionMode = Ignore; break; } default: { // We should just execute the transfer if (!m_scanned && !hasParentTransfer() && m_children.count() == 0) { m_executionMode = ScanWithExecute; return execute(); } m_status = Running; // If the directory is empty, create it anyway if (m_children.count() == 0) { if (m_destUrl.isLocalFile()) { KStandardDirs::makeDir(m_destUrl.path()); } else { m_dstSession->getClient()->mkdir(m_destUrl); } } // We no longer need the connections, release them deinitializeConnections(); // Reset and start the group m_group->reset(); m_group->executeNextTransfer(); break; } } } void TransferDir::scan() { if (isLocked() || isRunning()) return; m_executionMode = ScanOnly; execute(); } void TransferDir::abort() { if (isLocked()) { // The transfer is locked because a scan is in progress if (m_srcSession) { disconnect(m_srcSession, SIGNAL(dirScanDone()), this, SLOT(slotDirScanDone())); m_srcSession->abort(); } else if (m_srcScanner) { disconnect(m_srcScanner, SIGNAL(completed()), this, SLOT(slotDirScanDone())); m_srcScanner->abort(); } } // If not running, just return if (!isRunning()) return; Transfer::abort(); // Signal abort to all child transfers if (!m_deleteMe) { foreach (QueueObject *i, m_children) { if (i->isRunning() && !i->isAborting()) i->abort(); } } resetTransfer(); update(); } void TransferDir::slotGroupDone() { // There are no more transfers, so we are finished showTransCompleteBalloon(); m_deleteMe = true; resetTransfer(); emit transferComplete(m_id); KFTPQueue::Manager::self()->doEmitUpdate(); } void TransferDir::slotGroupInterrupted() { if (!m_aborting) abort(); } void TransferDir::slotDirScanDone() { if (m_srcSession) disconnect(m_srcSession, SIGNAL(dirScanDone()), this, SLOT(slotDirScanDone())); else disconnect(m_srcScanner, SIGNAL(completed()), this, SLOT(slotDirScanDone())); // Reexecute the transfer delayedExecute(); } } #include "kftptransferdir.moc" kftpgrabber-0.8.99~svn1214766/src/engine/0000755000175000017500000000000011276037142017437 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/src/engine/speedlimiter.cpp0000644000175000017500000001423611276037142022637 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "speedlimiter.h" #include "misc/config.h" #include using namespace KFTPCore; namespace KFTPEngine { static const int tickDelay = 250; static int bucketSize = 1000 / tickDelay; class SpeedLimiterPrivate { public: SpeedLimiter instance; }; K_GLOBAL_STATIC(SpeedLimiterPrivate, speedLimiterPrivate) SpeedLimiter *SpeedLimiter::self() { return &speedLimiterPrivate->instance; } SpeedLimiter::SpeedLimiter() : m_timer(new QTimer(this)) { // Reset limits and token debts m_limits[0] = 0; m_limits[1] = 0; m_tokenDebt[0] = 0; m_tokenDebt[1] = 0; connect(m_timer, SIGNAL(timeout()), this, SLOT(synchronize())); connect(this, SIGNAL(activateTimer(int)), m_timer, SLOT(start(int))); // Subscribe to config updates and update the limits connect(Config::self(), SIGNAL(configChanged()), this, SLOT(updateLimits())); updateLimits(); } SpeedLimiter::~SpeedLimiter() { } void SpeedLimiter::updateLimits() { setLimit(SpeedLimiter::Download, Config::downloadSpeedLimit() * 1024); setLimit(SpeedLimiter::Upload, Config::uploadSpeedLimit() * 1024); } void SpeedLimiter::setLimit(Type type, int limit) { m_limits[type] = limit; } void SpeedLimiter::append(SpeedLimiterItem *item, Type type) { m_objects[type].append(item); int limit = m_limits[type]; if (limit > 0) { int tokens = limit * tickDelay / 1000; tokens /= m_objects[type].count(); if (m_tokenDebt[type] > 0) { if (tokens >= m_tokenDebt[type]) { tokens -= m_tokenDebt[type]; m_tokenDebt[type] = 0; } else { tokens = 0; } } item->m_availableBytes = tokens; } else { item->m_availableBytes = -1; } // Fire the timer if not running if (!m_timer->isActive()) emit activateTimer(tickDelay); } void SpeedLimiter::remove(SpeedLimiterItem *item) { remove(item, Download); remove(item, Upload); } void SpeedLimiter::remove(SpeedLimiterItem *item, Type type) { if (m_objects[type].contains(item)) { int tokens = m_limits[type] * tickDelay / 1000; tokens /= m_objects[type].count(); if (item->m_availableBytes < tokens) m_tokenDebt[type] += tokens - item->m_availableBytes; m_objects[type].removeAll(item); } item->m_availableBytes = -1; } void SpeedLimiter::synchronize() { QList pendingWakeup; for (int i = 0; i < 2; i++) { m_tokenDebt[i] = 0; int limit = m_limits[i]; if (!limit) { // There is no limit, reset all items foreach (SpeedLimiterItem *item, m_objects[i]) { item->m_availableBytes = -1; } continue; } // If there are no objects, just skip it if (m_objects[i].isEmpty()) continue; int tokens = limit * tickDelay / 1000; if (!tokens) tokens = 1; int maxTokens = tokens * bucketSize; // Get amount of tokens for each object int tokensPerObject = tokens / m_objects[i].count(); if (!tokensPerObject) tokensPerObject = 1; tokens = 0; QList unsaturatedObjects; foreach (SpeedLimiterItem *item, m_objects[i]) { if (item->m_availableBytes == -1) { item->m_availableBytes = tokensPerObject; unsaturatedObjects.append(item); } else { item->m_availableBytes += tokensPerObject; if (item->m_availableBytes > maxTokens) { tokens += item->m_availableBytes - maxTokens; item->m_availableBytes = maxTokens; } else { unsaturatedObjects.append(item); } } } // Assign any left-overs to unsaturated sources while (tokens && !unsaturatedObjects.isEmpty()) { tokensPerObject = tokens / unsaturatedObjects.count(); if (!tokensPerObject) break; tokens = 0; foreach (SpeedLimiterItem *item, unsaturatedObjects) { item->m_availableBytes += tokensPerObject; if (item->m_availableBytes > maxTokens) { tokens += item->m_availableBytes - maxTokens; item->m_availableBytes = maxTokens; unsaturatedObjects.removeAll(item); } } } } if (m_objects[0].isEmpty() && m_objects[1].isEmpty()) m_timer->stop(); } SpeedLimiterItem::SpeedLimiterItem() : m_availableBytes(-1) { } void SpeedLimiterItem::updateUsage(int bytes) { // Ignore if there are no limits if (m_availableBytes == -1) return; if (bytes > m_availableBytes) m_availableBytes = 0; else m_availableBytes -= bytes; } } #include "speedlimiter.moc" kftpgrabber-0.8.99~svn1214766/src/engine/sftpsocket.cpp0000644000175000017500000011531011276037142022331 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "sftpsocket.h" #include "cache.h" #include "misc/config.h" #include #include #include #include #include #include #include #include namespace KFTPEngine { SftpSocket::SftpSocket(Thread *thread) : QTcpSocket(), Socket(thread, "sftp"), SpeedLimiterItem(), m_sshSession(0), m_sftpSession(0), m_login(false), m_transferHandle(0), m_transferBuffer(0), m_transferBufferSize(0) { // Control socket signals connect(this, SIGNAL(connected()), this, SLOT(slotConnected())); connect(this, SIGNAL(disconnected()), this, SLOT(slotDisconnected())); connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotError())); } SftpSocket::~SftpSocket() { } int addPermInt(int &x, int n, int add) { if (x >= n) { x -= n; return add; } else { return 0; } } int SftpSocket::intToPosix(int permissions) { int posix = 0; QString str = QString::number(permissions); int user = str.mid(0, 1).toInt(); int group = str.mid(1, 1).toInt(); int other = str.mid(2, 1).toInt(); posix |= addPermInt(user, 4, S_IRUSR); posix |= addPermInt(user, 2, S_IWUSR); posix |= addPermInt(user, 1, S_IXUSR); posix |= addPermInt(group, 4, S_IRGRP); posix |= addPermInt(group, 2, S_IWGRP); posix |= addPermInt(group, 1, S_IXGRP); posix |= addPermInt(other, 4, S_IROTH); posix |= addPermInt(other, 2, S_IWOTH); posix |= addPermInt(other, 1, S_IXOTH); return posix; } // ******************************************************************************************* // ***************************************** CONNECT ***************************************** // ******************************************************************************************* class SftpCommandConnect : public Commands::Base { public: enum State { None, ConnectComplete, LoginComplete }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(SftpCommandConnect, SftpSocket, CmdConnect) LIBSSH2_SESSION *session; static KUrl url; void process() { url = socket()->getCurrentUrl(); session = socket()->sshSession(); switch (currentState) { case None: { session = libssh2_session_init(); if (!session) { socket()->emitEvent(Event::EventMessage, i18n("Unable to establish SSH connection.")); socket()->emitError(ConnectFailed, i18n("Unknown error.")); socket()->protoAbort(); return; } socket()->m_sshSession = session; // Set blocking mode for libssh2 libssh2_session_set_blocking(session, 0); // Start handshake int rc; while ((rc = libssh2_session_startup(session, socket()->socketDescriptor())) == LIBSSH2_ERROR_EAGAIN) ; if (rc) { socket()->emitEvent(Event::EventMessage, i18n("Unable to establish SSH connection (error code %1.)", QString::number(rc))); socket()->emitError(ConnectFailed, i18n("SSH handshake has failed (error code %1.)", QString::number(rc))); socket()->protoAbort(); return; } // Get fingerprint hash and request authentication if (!socket()->getConfig("auth.ignore_fingerprint")) { const char *fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_MD5); QByteArray qFingerprint = QByteArray(fingerprint, 16); if (!KFTPCore::Config::self()->certificateStore()->verifyFingerprint(url, qFingerprint)) { PeerVerifyWakeupEvent *response = static_cast(socket()->emitEventAndWait(Event::EventPeerVerify, qFingerprint)); if (!response || !response->peerOk) { socket()->emitEvent(Event::EventMessage, i18n("Peer verification has failed.")); socket()->emitError(ConnectFailed, i18n("Identity of the peer cannot be established.")); socket()->protoAbort(); return; } } } currentState = ConnectComplete; } case ConnectComplete: { int rc; if (socket()->getConfig("auth.pubkey")) { // Public key authentication - try without password first QString password = socket()->getConfig("auth.privkey_password"); for (;;) { while ((rc = libssh2_userauth_publickey_fromfile(session, (char*) url.user().toAscii().data(), (char*) socket()->getConfig("auth.pubkey_path").toAscii().data(), (char*) socket()->getConfig("auth.privkey_path").toAscii().data(), (char*) password.toAscii().data())) == LIBSSH2_ERROR_EAGAIN) ; if (rc && password.isEmpty()) { PubkeyWakeupEvent *response = static_cast(socket()->emitEventAndWait(Event::EventPubkeyPassword)); if (response) password = response->password; if (password.isEmpty()) break; continue; } break; } if (rc) { socket()->emitEvent(Event::EventMessage, i18n("Public key authentication has failed.")); socket()->emitError(LoginFailed, i18n("Unable to decrypt the public key or public key has been rejected by server.")); socket()->protoAbort(); return; } // Save privkey password to socket settings so it can be reused by secondary connections socket()->setConfig("auth.privkey_password", password); socket()->emitEvent(Event::EventMessage, i18n("Public key authentication succeeded.")); } else if (url.hasPass()) { // First let's try simple password authentication while ((rc = libssh2_userauth_password(session, (char*) url.user().toAscii().data(), (char*) url.pass().toAscii().data())) == LIBSSH2_ERROR_EAGAIN) ; if (rc) { // Password authentication has failed, let's try keyboard-interactive while ((rc = libssh2_userauth_keyboard_interactive(session, (char*) url.user().toAscii().data(), &keyboardInteractiveCallback)) == LIBSSH2_ERROR_EAGAIN) ; if (rc) { socket()->emitEvent(Event::EventMessage, i18n("Authentication has failed.")); socket()->emitError(LoginFailed, i18n("The specified login credentials were rejected by the server.")); socket()->protoAbort(); return; } } socket()->emitEvent(Event::EventMessage, i18n("Authentication succeeded.")); } else { socket()->emitEvent(Event::EventMessage, i18n("No authentication methods available.")); socket()->emitError(LoginFailed, i18n("No authentication methods available.")); socket()->protoAbort(); return; } currentState = LoginComplete; } case LoginComplete: { LIBSSH2_SFTP *sftpSession; do { sftpSession = libssh2_sftp_init(session); if (!sftpSession && libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) { socket()->emitEvent(Event::EventMessage, i18n("Unable to initialize SFTP channel.")); socket()->emitError(LoginFailed, i18n("SFTP initialization has failed.")); socket()->protoAbort(); } } while (!sftpSession); socket()->m_sftpSession = sftpSession; // Get the current directory char cwd[1024]; while (libssh2_sftp_realpath(sftpSession, "./", cwd, sizeof(cwd)) == LIBSSH2_ERROR_EAGAIN) ; socket()->setDefaultDirectory(socket()->remoteEncoding()->decode(cwd)); socket()->setCurrentDirectory(socket()->remoteEncoding()->decode(cwd)); socket()->emitEvent(Event::EventMessage, i18n("Connected.")); socket()->emitEvent(Event::EventConnect); socket()->m_login = true; socket()->resetCommandClass(); break; } } } static LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(keyboardInteractiveCallback) { Q_UNUSED(name) Q_UNUSED(name_len) Q_UNUSED(instruction) Q_UNUSED(instruction_len) Q_UNUSED(abstract) for (int i = 0; i < num_prompts; i++) { if (!prompts[i].echo) { responses[i].text = (char*) url.pass().toAscii().data(); responses[i].length = url.pass().length(); } } } }; KUrl SftpCommandConnect::url = KUrl(); void SftpSocket::protoConnect(const KUrl &url) { emitEvent(Event::EventState, i18n("Connecting...")); emitEvent(Event::EventMessage, i18n("Connecting to %1:%2...", url.host(), url.port())); if (!getConfig("encoding").isEmpty()) changeEncoding(getConfig("encoding")); // Start the connect procedure setCurrentUrl(url); connectToHost(url.host(), url.port()); } void SftpSocket::slotConnected() { emitEvent(Event::EventState, i18n("Logging in...")); emitEvent(Event::EventMessage, i18n("Connected with server, stand by for authentication...")); activateCommandClass(SftpCommandConnect); } void SftpSocket::slotError() { emitEvent(Event::EventMessage, i18n("Failed to connect (%1.)", errorString())); emitError(ConnectFailed, errorString()); resetCommandClass(FailedSilently); } // ******************************************************************************************* // **************************************** DISCONNECT *************************************** // ******************************************************************************************* void SftpSocket::protoDisconnect() { if (!m_sshSession) return; Socket::protoDisconnect(); if (m_sftpSession) { libssh2_sftp_shutdown(m_sftpSession); m_sftpSession = 0; } libssh2_session_disconnect(m_sshSession, "Disconnected."); libssh2_session_free(m_sshSession); m_sshSession = 0; QTcpSocket::disconnectFromHost(); m_login = false; } void SftpSocket::protoAbort() { Socket::protoAbort(); if (getCurrentCommand() != Commands::CmdNone) { // Abort current command if (getCurrentCommand() == Commands::CmdConnect) protoDisconnect(); if (m_cmdData) resetCommandClass(UserAbort); emitEvent(Event::EventMessage, i18n("Aborted.")); } } void SftpSocket::slotDisconnected() { protoDisconnect(); } // ******************************************************************************************* // ******************************************* LIST ****************************************** // ******************************************************************************************* class SftpCommandList : public Commands::Base { public: enum State { None }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(SftpCommandList, SftpSocket, CmdList) void process() { // Check the directory listing cache DirectoryListing cached = Cache::self()->findCached(socket(), socket()->getCurrentDirectory()); if (cached.isValid()) { socket()->emitEvent(Event::EventMessage, i18n("Using cached directory listing.")); if (socket()->isChained()) { // We don't emit an event, because this list has been called from another // command. Just save the listing. socket()->m_lastDirectoryListing = cached; } else socket()->emitEvent(Event::EventDirectoryListing, cached); socket()->resetCommandClass(); return; } socket()->m_lastDirectoryListing = DirectoryListing(socket()->getCurrentDirectory()); char directory[1024] = {0,}; strcpy(directory, socket()->remoteEncoding()->encode(socket()->getCurrentDirectory()).data()); LIBSSH2_SESSION *sshSession = socket()->sshSession(); LIBSSH2_SFTP *sftpSession = socket()->sftpSession(); LIBSSH2_SFTP_HANDLE *dir; do { dir = libssh2_sftp_opendir(sftpSession, directory); if (!dir && libssh2_session_last_errno(sshSession) != LIBSSH2_ERROR_EAGAIN) { if (socket()->errorReporting()) { socket()->emitError(ListFailed); socket()->resetCommandClass(Failed); } else { socket()->resetCommandClass(); } return; } } while (!dir); // Read the specified directory for (;;) { int rc; char filename[512]; LIBSSH2_SFTP_ATTRIBUTES attrs; DirectoryEntry entry; while ((rc = libssh2_sftp_readdir(dir, filename, sizeof(filename), &attrs)) == LIBSSH2_ERROR_EAGAIN) ; if (rc > 0) { entry.setFilename(filename); if (entry.filename() != "." && entry.filename() != "..") { entry.setFilename(socket()->remoteEncoding()->decode(filename)); if (attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { entry.setPermissions(attrs.permissions); } if (attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID) { entry.setOwner(QString::number(attrs.uid)); entry.setGroup(QString::number(attrs.gid)); } if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) { entry.setSize(attrs.filesize); } if (attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { entry.setTime(attrs.mtime); } if (attrs.permissions & S_IFDIR) entry.setType('d'); else entry.setType('f'); socket()->m_lastDirectoryListing.addEntry(entry); } } else { break; } } while (libssh2_sftp_closedir(dir) == LIBSSH2_ERROR_EAGAIN) ; // Cache the directory listing Cache::self()->addDirectory(socket(), socket()->m_lastDirectoryListing); if (!socket()->isChained()) socket()->emitEvent(Event::EventDirectoryListing, socket()->m_lastDirectoryListing); socket()->resetCommandClass(); } }; void SftpSocket::protoList(const KUrl &path) { emitEvent(Event::EventState, i18n("Fetching directory listing...")); emitEvent(Event::EventMessage, i18n("Fetching directory listing...")); // Set the directory that should be listed setCurrentDirectory(path.path()); activateCommandClass(SftpCommandList); } // ******************************************************************************************* // ******************************************* GET ******************************************* // ******************************************************************************************* class SftpCommandGet : public Commands::Base { public: enum State { None, WaitStat, DestChecked, WaitTransfer }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(SftpCommandGet, SftpSocket, CmdGet) KUrl sourceFile; KUrl destinationFile; filesize_t resumeOffset; time_t modificationTime; QTimer pollTimer; void cleanup() { socket()->getTransferFile()->close(); socket()->disconnect(&pollTimer, SIGNAL(timeout()), socket(), SLOT(slotDataTryRead())); LIBSSH2_SFTP_HANDLE *rfile = socket()->m_transferHandle; if (rfile) while (libssh2_sftp_close(rfile) == LIBSSH2_ERROR_EAGAIN) ; free(socket()->m_transferBuffer); socket()->m_transferBuffer = 0; SpeedLimiter::self()->remove(socket()); } void process() { switch (currentState) { case None: { // Stat source file modificationTime = 0; resumeOffset = 0; sourceFile.setPath(socket()->getConfig("params.get.source")); destinationFile.setPath(socket()->getConfig("params.get.destination")); currentState = WaitStat; socket()->protoStat(sourceFile); break; } case WaitStat: { socket()->emitEvent(Event::EventState, i18n("Transferring...")); if (socket()->getStatResponse().filename().isEmpty()) { markClean(); socket()->emitError(FileNotFound); socket()->resetCommandClass(Failed); return; } modificationTime = socket()->getStatResponse().time(); if (QDir::root().exists(destinationFile.path())) { DirectoryListing list; list.addEntry(socket()->getStatResponse()); currentState = DestChecked; socket()->emitEvent(Event::EventFileExists, list); return; } else { KStandardDirs::makeDir(destinationFile.directory()); } } case DestChecked: { if (isWakeup()) { // We have been waken up because a decision has been made FileExistsWakeupEvent *event = static_cast(m_wakeupEvent); switch (event->action) { case FileExistsWakeupEvent::Rename: { // Change the destination filename, otherwise it is the same as overwrite destinationFile.setPath(event->newFileName); } case FileExistsWakeupEvent::Overwrite: { socket()->getTransferFile()->setFileName(destinationFile.path()); socket()->getTransferFile()->open(QIODevice::WriteOnly | QIODevice::Truncate); break; } case FileExistsWakeupEvent::Resume: { socket()->getTransferFile()->setFileName(destinationFile.path()); socket()->getTransferFile()->open(QIODevice::WriteOnly | QIODevice::Append); // Signal resume resumeOffset = socket()->getTransferFile()->size(); socket()->emitEvent(Event::EventResumeOffset, resumeOffset); break; } case FileExistsWakeupEvent::Skip: { // Transfer should be aborted markClean(); socket()->emitEvent(Event::EventTransferComplete); socket()->resetCommandClass(); return; } } } else { // The file doesn't exist so we are free to overwrite socket()->getTransferFile()->setFileName(destinationFile.path()); socket()->getTransferFile()->open(QIODevice::WriteOnly | QIODevice::Truncate); } // Start the file transfer char path[1024] = {0,}; strcpy(path, socket()->remoteEncoding()->encode(sourceFile.path()).data()); LIBSSH2_SESSION *sshSession = socket()->sshSession(); LIBSSH2_SFTP *sftpSession = socket()->sftpSession(); LIBSSH2_SFTP_HANDLE *rfile; do { rfile = libssh2_sftp_open(sftpSession, path, LIBSSH2_FXF_READ, 0); if (!rfile && libssh2_session_last_errno(sshSession) != LIBSSH2_ERROR_EAGAIN) { markClean(); socket()->getTransferFile()->close(); socket()->resetCommandClass(Failed); return; } } while (!rfile); if (resumeOffset > 0) libssh2_sftp_seek(rfile, resumeOffset); // Initialize the transfer buffer socket()->m_transferBufferSize = 4096; socket()->m_transferBuffer = (char*) malloc(socket()->m_transferBufferSize); socket()->m_transferBytes = 0; socket()->m_transferHandle = rfile; socket()->m_speedLastTime = time(0); socket()->m_speedLastBytes = 0; SpeedLimiter::self()->append(socket(), SpeedLimiter::Download); // Connect to socket read notifications socket()->connect(&pollTimer, SIGNAL(timeout()), socket(), SLOT(slotDataTryRead())); pollTimer.start(0); currentState = WaitTransfer; break; } case WaitTransfer: { // Transfer has been completed markClean(); socket()->getTransferFile()->close(); socket()->disconnect(&pollTimer, SIGNAL(timeout()), socket(), SLOT(slotDataTryRead())); if (modificationTime != 0) { // Use the modification time we got from stating utimbuf tmp; tmp.actime = time(0); tmp.modtime = modificationTime; utime(destinationFile.path().toAscii(), &tmp); } LIBSSH2_SFTP_HANDLE *rfile = socket()->m_transferHandle; while (libssh2_sftp_close(rfile) == LIBSSH2_ERROR_EAGAIN) ; free(socket()->m_transferBuffer); socket()->m_transferBuffer = 0; SpeedLimiter::self()->remove(socket()); socket()->emitEvent(Event::EventTransferComplete); socket()->emitEvent(Event::EventReloadNeeded); socket()->resetCommandClass(); break; } } } }; void SftpSocket::variableBufferUpdate(int size) { if (size > m_transferBufferSize - 64) { if (m_transferBufferSize + 512 <= 32768) { m_transferBufferSize += 512; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); } } else if (size < m_transferBufferSize - 65) { if (m_transferBufferSize - 512 >= 4096) { m_transferBufferSize -= 512; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); } } } void SftpSocket::slotDataTryRead() { if (!m_transferHandle) return; bool updateVariableBuffer = true; // Enforce speed limits if (allowedBytes() > -1) { m_transferBufferSize = allowedBytes(); if (m_transferBufferSize > 32768) m_transferBufferSize = 32768; else if (m_transferBufferSize == 0) return; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); updateVariableBuffer = false; } else if (m_transferBufferSize == 0) { m_transferBufferSize = 4096; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); } int readBytes = 0; do { readBytes = libssh2_sftp_read(m_transferHandle, m_transferBuffer, m_transferBufferSize); } while (readBytes == LIBSSH2_ERROR_EAGAIN); if (readBytes == 0) { // Transfer has been completed nextCommand(); return; } else if (readBytes < 0) { // An error has ocurred while reading, transfer is aborted emitEvent(Event::EventMessage, i18n("Transfer has failed.")); resetCommandClass(Failed); return; } else { updateUsage(readBytes); m_transferFile.write(m_transferBuffer, readBytes); m_transferBytes += readBytes; } if (updateVariableBuffer) variableBufferUpdate(readBytes); } void SftpSocket::protoGet(const KUrl &source, const KUrl &destination) { emitEvent(Event::EventState, i18n("Transferring...")); emitEvent(Event::EventMessage, i18n("Downloading file '%1'...",source.fileName())); // Set the source and destination setConfig("params.get.source", source.path()); setConfig("params.get.destination", destination.path()); activateCommandClass(SftpCommandGet); } // ******************************************************************************************* // ******************************************* PUT ******************************************* // ******************************************************************************************* class SftpCommandPut : public Commands::Base { public: enum State { None, WaitStat, DestChecked, WaitTransfer }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(SftpCommandPut, SftpSocket, CmdPut) KUrl sourceFile; KUrl destinationFile; filesize_t resumeOffset; time_t modificationTime; QTimer pollTimer; void cleanup() { socket()->getTransferFile()->close(); socket()->disconnect(&pollTimer, SIGNAL(timeout()), socket(), SLOT(slotDataTryWrite())); LIBSSH2_SFTP_HANDLE *rfile = socket()->m_transferHandle; if (rfile) while (libssh2_sftp_close(rfile) == LIBSSH2_ERROR_EAGAIN) ; free(socket()->m_transferBuffer); socket()->m_transferBuffer = 0; SpeedLimiter::self()->remove(socket()); } void process() { switch (currentState) { case None: { // Stat source file resumeOffset = 0; modificationTime = 0; sourceFile.setPath(socket()->getConfig("params.get.source")); destinationFile.setPath(socket()->getConfig("params.get.destination")); if (!QDir::root().exists(sourceFile.path())) { markClean(); socket()->emitError(FileNotFound); socket()->resetCommandClass(Failed); return; } else { modificationTime = QFileInfo(sourceFile.path()).lastModified().toTime_t(); } currentState = WaitStat; socket()->protoStat(destinationFile); break; } case WaitStat: { socket()->emitEvent(Event::EventState, i18n("Transferring...")); if (!socket()->getStatResponse().filename().isEmpty()) { DirectoryListing list; list.addEntry(socket()->getStatResponse()); currentState = DestChecked; socket()->emitEvent(Event::EventFileExists, list); return; } else { // Create destination directories socket()->setErrorReporting(false); QString destinationDir = destinationFile.directory(); QString fullPath; for (register int i = 1; i <= destinationDir.count('/'); i++) { fullPath += "/" + destinationDir.section('/', i, i); // Create the directory socket()->protoMkdir(fullPath); } } } case DestChecked: { if (isWakeup()) { // We have been waken up because a decision has been made FileExistsWakeupEvent *event = static_cast(m_wakeupEvent); switch (event->action) { case FileExistsWakeupEvent::Rename: { // Change the destination filename, otherwise it is the same as overwrite destinationFile.setPath(event->newFileName); } case FileExistsWakeupEvent::Overwrite: { socket()->getTransferFile()->setFileName(sourceFile.path()); socket()->getTransferFile()->open(QIODevice::ReadOnly); break; } case FileExistsWakeupEvent::Resume: { resumeOffset = socket()->getStatResponse().size(); socket()->getTransferFile()->setFileName(sourceFile.path()); socket()->getTransferFile()->open(QIODevice::ReadOnly); socket()->getTransferFile()->seek(resumeOffset); // Signal resume socket()->emitEvent(Event::EventResumeOffset, resumeOffset); break; } case FileExistsWakeupEvent::Skip: { // Transfer should be aborted markClean(); socket()->emitEvent(Event::EventTransferComplete); socket()->resetCommandClass(); return; } } } else { // The file doesn't exist so we are free to overwrite socket()->getTransferFile()->setFileName(sourceFile.path()); socket()->getTransferFile()->open(QIODevice::ReadOnly); } // Start the file transfer char path[1024] = {0,}; strcpy(path, socket()->remoteEncoding()->encode(destinationFile.path()).data()); int flags = resumeOffset > 0 ? LIBSSH2_FXF_WRITE | LIBSSH2_FXF_APPEND : LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC; LIBSSH2_SESSION *sshSession = socket()->sshSession(); LIBSSH2_SFTP *sftpSession = socket()->sftpSession(); LIBSSH2_SFTP_HANDLE *rfile; do { rfile = libssh2_sftp_open(sftpSession, path, flags, LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH); if (!rfile && libssh2_session_last_errno(sshSession) != LIBSSH2_ERROR_EAGAIN) { markClean(); socket()->getTransferFile()->close(); socket()->resetCommandClass(Failed); return; } } while (!rfile); if (resumeOffset > 0) libssh2_sftp_seek(rfile, resumeOffset); // Initialize the transfer buffer socket()->m_transferBufferSize = 4096; socket()->m_transferBuffer = (char*) malloc(socket()->m_transferBufferSize); socket()->m_transferBytes = 0; socket()->m_transferHandle = rfile; socket()->m_speedLastTime = time(0); socket()->m_speedLastBytes = 0; SpeedLimiter::self()->append(socket(), SpeedLimiter::Upload); // Connect to socket read notifications socket()->connect(&pollTimer, SIGNAL(timeout()), socket(), SLOT(slotDataTryWrite())); pollTimer.start(0); currentState = WaitTransfer; break; } case WaitTransfer: { // Transfer has been completed markClean(); socket()->getTransferFile()->close(); socket()->disconnect(&pollTimer, SIGNAL(timeout()), socket(), SLOT(slotDataTryWrite())); LIBSSH2_SFTP_HANDLE *rfile = socket()->m_transferHandle; if (modificationTime != 0) { // Use the modification time we got from stating LIBSSH2_SFTP_ATTRIBUTES attrs; attrs.mtime = modificationTime; attrs.flags = LIBSSH2_SFTP_ATTR_ACMODTIME; while (libssh2_sftp_fsetstat(rfile, &attrs) == LIBSSH2_ERROR_EAGAIN) ; } while (libssh2_sftp_close(rfile) == LIBSSH2_ERROR_EAGAIN) ; free(socket()->m_transferBuffer); socket()->m_transferBuffer = 0; SpeedLimiter::self()->remove(socket()); socket()->emitEvent(Event::EventTransferComplete); socket()->emitEvent(Event::EventReloadNeeded); socket()->resetCommandClass(); break; } } } }; void SftpSocket::slotDataTryWrite() { if (!m_transferHandle) return; bool updateVariableBuffer = true; // Enforce speed limits if (allowedBytes() > -1) { m_transferBufferSize = allowedBytes(); if (m_transferBufferSize > 32768) m_transferBufferSize = 32768; else if (m_transferBufferSize == 0) return; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); updateVariableBuffer = false; } else if (m_transferBufferSize == 0) { m_transferBufferSize = 4096; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); } if (!getTransferFile()->isOpen()) return; // If there is nothing to upload, just close the connection right away if (getTransferFile()->size() == 0) { nextCommand(); return; } qint64 tmpOffset = getTransferFile()->pos(); qint64 readSize = getTransferFile()->read(m_transferBuffer, m_transferBufferSize); int writtenBytes = 0; do { writtenBytes = libssh2_sftp_write(m_transferHandle, m_transferBuffer, readSize); } while (writtenBytes == LIBSSH2_ERROR_EAGAIN); if (writtenBytes < 0) { // An error has ocurred while writing, transfer is aborted emitEvent(Event::EventMessage, i18n("Transfer has failed.")); resetCommandClass(Failed); return; } else if (writtenBytes < readSize) { getTransferFile()->seek(tmpOffset + writtenBytes); } m_transferBytes += writtenBytes; updateUsage(writtenBytes); if (getTransferFile()->atEnd()) { // We have reached the end of file, so we should terminate the connection nextCommand(); return; } if (updateVariableBuffer) variableBufferUpdate(writtenBytes); } void SftpSocket::protoPut(const KUrl &source, const KUrl &destination) { emitEvent(Event::EventState, i18n("Transferring...")); emitEvent(Event::EventMessage, i18n("Uploading file '%1'...",source.fileName())); // Set the source and destination setConfig("params.get.source", source.path()); setConfig("params.get.destination", destination.path()); activateCommandClass(SftpCommandPut); } // ******************************************************************************************* // **************************************** REMOVE ******************************************* // ******************************************************************************************* void SftpSocket::protoRemove(const KUrl &path) { emitEvent(Event::EventState, i18n("Removing...")); // Remove a file or directory int result = 0; if (getConfig("params.remove.directory")) while ((result = libssh2_sftp_rmdir(m_sftpSession, remoteEncoding()->encode(path.path()).data())) == LIBSSH2_ERROR_EAGAIN) ; else while ((result = libssh2_sftp_unlink(m_sftpSession, remoteEncoding()->encode(path.path()).data())) == LIBSSH2_ERROR_EAGAIN) ; if (result < 0) { resetCommandClass(Failed); } else { // Invalidate cached parent entry (if any) Cache::self()->invalidateEntry(this, path.directory()); emitEvent(Event::EventReloadNeeded); resetCommandClass(); } } // ******************************************************************************************* // **************************************** RENAME ******************************************* // ******************************************************************************************* void SftpSocket::protoRename(const KUrl &source, const KUrl &destination) { emitEvent(Event::EventState, i18n("Renaming...")); int result = 0; while ((result = libssh2_sftp_rename(m_sftpSession, remoteEncoding()->encode(source.path()).data(), remoteEncoding()->encode(destination.path()).data()) == LIBSSH2_ERROR_EAGAIN)) ; if (result < 0) { resetCommandClass(Failed); } else { // Invalidate cached parent entry (if any) Cache::self()->invalidateEntry(this, source.directory()); Cache::self()->invalidateEntry(this, destination.directory()); emitEvent(Event::EventReloadNeeded); resetCommandClass(); } } // ******************************************************************************************* // **************************************** CHMOD ******************************************** // ******************************************************************************************* void SftpSocket::protoChmodSingle(const KUrl &path, int mode) { emitEvent(Event::EventState, i18n("Changing mode...")); LIBSSH2_SFTP_ATTRIBUTES attrs; attrs.permissions = intToPosix(mode); attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; while (libssh2_sftp_setstat(m_sftpSession, remoteEncoding()->encode(path.path()).data(), &attrs) == LIBSSH2_ERROR_EAGAIN) ; // Invalidate cached parent entry (if any) Cache::self()->invalidateEntry(this, path.directory()); emitEvent(Event::EventReloadNeeded); resetCommandClass(); } // ******************************************************************************************* // **************************************** MKDIR ******************************************** // ******************************************************************************************* void SftpSocket::protoMkdir(const KUrl &path) { int result = 0; while ((result = libssh2_sftp_mkdir(m_sftpSession, remoteEncoding()->encode(path.path()).data(), 0755)) == LIBSSH2_ERROR_EAGAIN) ; if (result < 0) { if (errorReporting(true)) resetCommandClass(Failed); } else { // Invalidate cached parent entry (if any) Cache::self()->invalidateEntry(this, path.directory()); if (errorReporting(true)) { emitEvent(Event::EventReloadNeeded); resetCommandClass(); } } } } #include "sftpsocket.moc" kftpgrabber-0.8.99~svn1214766/src/engine/settings.cpp0000644000175000017500000000412311276037142022003 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "settings.h" namespace KFTPEngine { Settings::Settings() { } void Settings::initConfig() { m_config.clear(); // Fill in some default values setConfig("feat.epsv", true); setConfig("feat.eprt", true); setConfig("feat.pasv", true); setConfig("feat.size", true); setConfig("ssl.prot_mode", 2); setConfig("ssl.ignore_errors", false); setConfig("keepalive.enabled", true); setConfig("keepalive.timeout", 60); } } kftpgrabber-0.8.99~svn1214766/src/engine/event.cpp0000644000175000017500000000501111276037142021261 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "event.h" #include "thread.h" namespace KFTPEngine { Event::Event(Type type, QList params) : QEvent((QEvent::Type) 65123), m_type(type), m_params(params) { } Event::~Event() { } EventHandler::EventHandler(Thread *thread) : QObject(), m_thread(thread) { } void EventHandler::customEvent(QEvent *e) { if (e->type() == 65123) { Event *ev = static_cast(e); emit engineEvent(ev); switch (ev->type()) { case Event::EventConnect: emit connected(); break; case Event::EventDisconnect: emit disconnected(); break; case Event::EventResponse: case Event::EventMultiline: { emit gotResponse(ev->getParameter(0).toString()); break; } case Event::EventRaw: emit gotRawResponse(ev->getParameter(0).toString()); break; default: break; } } } } #include "event.moc" kftpgrabber-0.8.99~svn1214766/src/engine/directorylisting.h0000644000175000017500000001112111276037142023202 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPNETWORKDIRECTORYLISTING_H #define KFTPNETWORKDIRECTORYLISTING_H #include #include #include #include #include #include typedef qulonglong filesize_t; namespace KFTPEngine { class DirectoryEntry { public: DirectoryEntry(); void setFilename(const QString &filename) { m_filename = filename; } void setOwner(const QString &owner) { m_owner = owner; } void setGroup(const QString &group) { m_group = group; } void setLink(const QString &link) { m_link = link; } void setPermissions(int permissions) { m_permissions = permissions; } void setSize(filesize_t size) { m_size = size; } void setType(char type) { m_type = type; } void setTime(time_t time) { m_time = time; } QString filename() const { return m_filename; } QString owner() const { return m_owner; } QString group() const { return m_group; } QString link() const { return m_link; } int permissions() const { return m_permissions; } filesize_t size() const { return m_size; } char type() const { return m_type; } time_t time() const { return m_time; } QString timeAsString(); bool isDirectory() const { return m_type == 'd'; } bool isFile() const { return m_type == 'f'; } bool isDevice() const { return m_type == 'c' || m_type == 'b'; } bool isSymlink() const { return !m_link.isEmpty(); } KIO::UDSEntry toUdsEntry() const; struct tm timeStruct; bool operator<(const DirectoryEntry &entry) const; private: QString m_filename; QString m_owner; QString m_group; QString m_link; int m_permissions; filesize_t m_size; char m_type; time_t m_time; }; class DirectoryTree { public: typedef QList::ConstIterator FileIterator; typedef QList::ConstIterator DirIterator; DirectoryTree() {} DirectoryTree(DirectoryEntry entry); ~DirectoryTree(); void addFile(DirectoryEntry entry); DirectoryTree *addDirectory(DirectoryEntry entry); DirectoryEntry info() { return m_entry; } QList *files() { return &m_files; } QList *directories() { return &m_directories; } private: DirectoryEntry m_entry; QList m_files; QList m_directories; }; /** * @author Jernej Kos */ class DirectoryListing { public: DirectoryListing(const KUrl &path = KUrl()); ~DirectoryListing(); void addEntry(DirectoryEntry entry); void updateEntry(const QString &filename, filesize_t size); QList list() { return m_list; } void setValid(bool value) { m_valid = value; } bool isValid() { return m_valid; } private: bool m_valid; KUrl m_path; QList m_list; }; } Q_DECLARE_METATYPE(KFTPEngine::DirectoryListing) Q_DECLARE_METATYPE(KFTPEngine::DirectoryTree*) #endif kftpgrabber-0.8.99~svn1214766/src/engine/settings.h0000644000175000017500000000566411276037142021463 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPENGINESETTINGS_H #define KFTPENGINESETTINGS_H #include #include namespace KFTPEngine { /** * This class holds and per-thread configuration settings. * * @author Jernej Kos */ class Settings { public: /** * Class constructor. */ Settings(); /** * Set an internal config value. * * @param key Key * @param value Value */ void setConfig(const QString &key, const QVariant &value) { m_config[key] = value; } /** * Get an internal config value as string. * * @param key Key * @return The key's value or an empty string if the key doesn't exist */ QString getConfig(const QString &key) const { return m_config[key].toString(); } /** * Get an internal config value. * * @param key Key * @param default Default value to use instead * @return The key's value or the default value if not found */ template T getConfig(const QString &key, const T &def = T()) const { return m_config.contains(key) ? m_config[key].value() : def; } /** * This method resets and initializes the configuration map. */ void initConfig(); private: QMap m_config; }; } #endif kftpgrabber-0.8.99~svn1214766/src/engine/connectionretry.cpp0000644000175000017500000000752611276037142023402 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "connectionretry.h" #include "socket.h" #include "thread.h" #include "event.h" #include namespace KFTPEngine { ConnectionRetry::ConnectionRetry(Socket *socket) : QObject(), m_socket(socket), m_delay(socket->getConfig("retry_delay")), m_max(socket->getConfig("max_retries")), m_iteration(0) { m_timer = new QTimer(this); connect(m_timer, SIGNAL(timeout()), this, SLOT(slotShouldRetry())); connect(m_socket->thread()->eventHandler(), SIGNAL(engineEvent(KFTPEngine::Event*)), this, SLOT(slotEngineEvent(KFTPEngine::Event*))); } void ConnectionRetry::startRetry() { if ((m_iteration++ >= m_max && m_max != 0) || m_delay < 1) { abortRetry(); return; } m_socket->setCurrentCommand(Commands::CmdConnectRetry); m_socket->emitEvent(Event::EventMessage, i18np("Waiting 1 second before reconnect...", "Waiting %1 seconds before reconnect...",m_delay)); m_socket->emitEvent(Event::EventState, i18n("Waiting...")); m_timer->setSingleShot(true); m_timer->start(1000 * m_delay); } void ConnectionRetry::slotShouldRetry() { m_socket->setCurrentCommand(Commands::CmdNone); if (m_max > 0) m_socket->emitEvent(Event::EventMessage, i18n("Retrying connection (%1/%2)...",m_iteration,m_max)); else m_socket->emitEvent(Event::EventMessage, i18n("Retrying connection...",m_iteration,m_max)); // Reconnect Thread *thread = m_socket->thread(); thread->connect(m_socket->getCurrentUrl()); } void ConnectionRetry::abortRetry() { m_timer->stop(); // Disable retry so we avoid infinite loops m_socket->setConfig("retry", 0); m_socket->setCurrentCommand(Commands::CmdNone); m_socket->emitEvent(Event::EventMessage, i18n("Retry aborted.")); m_socket->emitEvent(Event::EventState, i18n("Idle.")); m_socket->emitEvent(Event::EventReady); m_socket->emitError(ConnectFailed); // This object should be automagicly removed QObject::deleteLater(); } void ConnectionRetry::slotEngineEvent(KFTPEngine::Event *event) { if (event->type() == Event::EventConnect) { m_socket->emitEvent(Event::EventRetrySuccess); // This object should be automagicly removed QObject::deleteLater(); } } } #include "connectionretry.moc" kftpgrabber-0.8.99~svn1214766/src/engine/commands.cpp0000644000175000017500000000437011276037142021750 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "commands.h" namespace KFTPEngine { namespace Commands { Base::Base(Socket *socket, Type command) : m_command(command), m_socket(socket), m_wakeupEvent(0), m_processing(false), m_autoDestruct(false), m_clean(false) { } void Base::setProcessing(bool value) { if (value) m_processing++; else m_processing--; } void Base::autoDestruct(ResetCode code) { m_autoDestruct = true; m_resetCode = code; } void Base::wakeup(WakeupEvent *event) { // The default implementation just calls process() m_wakeupEvent = event; process(); m_wakeupEvent = 0; } } } kftpgrabber-0.8.99~svn1214766/src/engine/thread.cpp0000644000175000017500000002375311276037142021424 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "thread.h" #include "ftpsocket.h" #include "sftpsocket.h" #include "settings.h" #include #include namespace KFTPEngine { CommandQueue::Event::Event(Commands::Type type) : QEvent((QEvent::Type) 65234), m_type(type) { } CommandQueue::CommandQueue(Thread *thread) : QObject(), m_thread(thread) { } void CommandQueue::customEvent(QEvent *event) { Event *e = static_cast(event); Socket *socket = m_thread->socket(); if (!socket->isBusy()) { socket->setCurrentCommand(e->command()); switch (e->command()) { case Commands::CmdConnect: { KUrl url = e->parameter(0).value(); m_thread->setCurrentProtocol(url); m_thread->socket()->setCurrentCommand(e->command()); m_thread->socket()->protoConnect(url); break; } case Commands::CmdDisconnect: { socket->protoDisconnect(); break; } case Commands::CmdList: { socket->protoList(e->parameter(0).value()); break; } case Commands::CmdScan: { socket->protoScan(e->parameter(0).value()); break; } case Commands::CmdGet: { socket->protoGet(e->parameter(0).value(), e->parameter(1).value()); break; } case Commands::CmdPut: { socket->protoPut(e->parameter(0).value(), e->parameter(1).value()); break; } case Commands::CmdDelete: { socket->protoDelete(e->parameter(0).value()); break; } case Commands::CmdRename: { socket->protoRename(e->parameter(0).value(), e->parameter(1).value()); break; } case Commands::CmdChmod: { socket->protoChmod(e->parameter(0).value(), e->parameter(1).toULongLong(), e->parameter(2).toBool()); break; } case Commands::CmdMkdir: { socket->protoMkdir(e->parameter(0).value()); break; } case Commands::CmdRaw: { socket->protoRaw(e->parameter(0).toString()); break; } case Commands::CmdFxp: { socket->protoSiteToSite(e->parameter(0).value(), e->parameter(1).value(), e->parameter(2).value()); break; } default: break; } } switch (e->command()) { case Commands::CmdWakeup: { socket->wakeup(e->parameter(0).value()); break; } case Commands::CmdAbort: { socket->protoAbort(); break; } default: break; } } Thread::Thread() : QThread(), m_eventHandler(new EventHandler(this)), m_socket(0), m_exit(false), m_commandsDeferred(0), m_immediateWakeup(false) { m_startupSem.release(1); m_startupSem.acquire(); // Auto start the thread start(); m_startupSem.acquire(); } Thread::~Thread() { delete m_eventHandler; } void Thread::shutdown() { m_commandsDeferred = 0; m_exit = true; QAbstractEventDispatcher::instance(this)->interrupt(); // Start a timer to prevent the thread from hanging QTimer::singleShot(5000, this, SLOT(shutdownWithTerminate())); } void Thread::shutdownWithTerminate() { terminate(); deleteLater(); } void Thread::run() { m_commandQueue = new CommandQueue(this); m_settings = new Settings(); setCurrentProtocol("ftp"); m_startupSem.release(); // Enter the event loop QEventLoop eventLoop; while (!m_exit) { if (m_commandsDeferred) eventLoop.processEvents(QEventLoop::ProcessEventsFlag(QEventLoop::DeferredDeletion)); else eventLoop.processEvents(QEventLoop::WaitForMoreEvents | QEventLoop::ProcessEventsFlag(QEventLoop::DeferredDeletion)); if (m_commandsDeferred) { m_socket->nextCommand(); m_commandsDeferred--; } } // Cleanup before exiting delete m_settings; delete m_commandQueue; foreach (Socket *socket, m_sockets) { delete socket; } // Schedule our deletion deleteLater(); } void Thread::deferCommandExec() { m_commandsDeferred++; QAbstractEventDispatcher::instance(this)->interrupt(); } void Thread::setCurrentProtocol(const QString &protocol) { if (m_socket && m_socket->protocolName() == protocol) return; if (!m_sockets.contains(protocol)) { if (protocol == "ftp") m_socket = new FtpSocket(this); else if (protocol == "sftp") m_socket = new SftpSocket(this); else Q_ASSERT(false); m_sockets.insert(protocol, m_socket); } else { m_socket = m_sockets[protocol]; } } void Thread::setCurrentProtocol(const KUrl &url) { setCurrentProtocol(url.protocol()); } void Thread::notifyCommandQueue(CommandQueue::Event *event, int priority) { if (m_commandQueue) QCoreApplication::postEvent(m_commandQueue, event, priority); } void Thread::wakeup(WakeupEvent *e) { if (m_immediateWakeup) { m_imWakeupEvent = e; m_immediateWakeup = false; m_imWakeupCond.wakeOne(); } else { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdWakeup); event->addParameter(QVariant::fromValue(e)); notifyCommandQueue(event); } } void Thread::abort() { if (m_immediateWakeup) { m_imWakeupEvent = 0; m_immediateWakeup = false; m_imWakeupCond.wakeOne(); } notifyCommandQueue(new CommandQueue::Event(Commands::CmdAbort), Qt::HighEventPriority * 100); } void Thread::emitEvent(Event::Type type, QList params) { if (m_eventHandler) QCoreApplication::postEvent(m_eventHandler, new Event(type, params)); } WakeupEvent *Thread::waitForWakeup() { WakeupEvent *event; m_imWakeupMutex.lock(); m_immediateWakeup = true; m_imWakeupCond.wait(&m_imWakeupMutex); event = m_imWakeupEvent; m_imWakeupEvent = 0; m_imWakeupMutex.unlock(); return event; } void Thread::connect(const KUrl &url) { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdConnect); event->addParameter(url); notifyCommandQueue(event); } void Thread::disconnect() { notifyCommandQueue(new CommandQueue::Event(Commands::CmdDisconnect)); } void Thread::list(const KUrl &url) { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdList); event->addParameter(url); notifyCommandQueue(event); } void Thread::scan(const KUrl &url) { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdScan); event->addParameter(url); notifyCommandQueue(event); } void Thread::get(const KUrl &source, const KUrl &destination) { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdGet); event->addParameter(source); event->addParameter(destination); notifyCommandQueue(event); } void Thread::put(const KUrl &source, const KUrl &destination) { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdPut); event->addParameter(source); event->addParameter(destination); notifyCommandQueue(event); } void Thread::remove(const KUrl &url) { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdDelete); event->addParameter(url); notifyCommandQueue(event); } void Thread::rename(const KUrl &source, const KUrl &destination) { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdRename); event->addParameter(source); event->addParameter(destination); notifyCommandQueue(event); } void Thread::chmod(const KUrl &url, int mode, bool recursive) { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdChmod); event->addParameter(url); event->addParameter(mode); event->addParameter(recursive); notifyCommandQueue(event); } void Thread::mkdir(const KUrl &url) { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdMkdir); event->addParameter(url); notifyCommandQueue(event); } void Thread::raw(const QString &raw) { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdRaw); event->addParameter(raw); notifyCommandQueue(event); } void Thread::siteToSite(Thread *thread, const KUrl &source, const KUrl &destination) { CommandQueue::Event *event = new CommandQueue::Event(Commands::CmdFxp); event->addParameter(QVariant::fromValue(thread->socket())); event->addParameter(source); event->addParameter(destination); notifyCommandQueue(event); } } kftpgrabber-0.8.99~svn1214766/src/engine/socket.h0000644000175000017500000004337211276037142021111 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPENGINESOCKET_H #define KFTPENGINESOCKET_H #include #include #include #include #include #include #include "settings.h" #include "commands.h" namespace KFTPEngine { class ConnectionRetry; /** * A representation of a socket address. */ struct SocketAddress { QHostAddress ip; quint16 port; }; enum SocketFeatures { SF_FXP_TRANSFER = 1, SF_RAW_COMMAND = 2 }; /** * The socket class provides an abstract class for all implemented protocols. It * provides basic methods and also some remote operations (recursive scan, * recursive removal). * * @author Jernej Kos */ class Socket { friend class Thread; friend class FtpCommandStat; public: /** * Constructs a new socket. * * @param thread The thread that created this socket * @param protocol The protocol name */ Socket(Thread *thread, const QString &protocol); virtual ~Socket(); /** * Set an internal config value. * * @param key Key * @param value Value */ void setConfig(const QString &key, const QVariant &value) { m_settings->setConfig(key, value); } /** * Get an internal config value as string. * * @param key Key * @return The key's value or an empty string if the key doesn't exist */ QString getConfig(const QString &key) const { return m_settings->getConfig(key); } /** * Get an internal config value. * * @param key Key * @param default Default value to use instead * @return The key's value or the default value if not found */ template T getConfig(const QString &key, const T &def = T()) const { return m_settings->getConfig(key, def); } /** * This method should trigger the connection process. * * @param url Remote url to connect to */ virtual void protoConnect(const KUrl &url) = 0; /** * This method should disconnect from the remote host. */ virtual void protoDisconnect(); /** * This method should abort any ongoing action. */ virtual void protoAbort(); /** * This method should download a remote file and save it localy. * * @param source The source url * @param destination The destination url */ virtual void protoGet(const KUrl &source, const KUrl &destination) = 0; /** * This method should upload a local file and save it remotely. * * @param source The source url * @param destination The destination url */ virtual void protoPut(const KUrl &source, const KUrl &destination) = 0; /** * Each protocol should implement this method. It should remove just one * single entry. A config variable "params.remove.directory" will be set * to 1 if the entry to remove is a directory and to 0 if it should expect * a file. * * @warning You should NOT use this method directly! Use @ref protoDelete * instead! * @param path The path to the entry to remove */ virtual void protoRemove(const KUrl &path) = 0; /** * This method should rename/move a remote file. * * @param source The source file path * @param destination The destination file path */ virtual void protoRename(const KUrl &source, const KUrl &destination) = 0; /** * This method should change file's mode. * * * @warning You should NOT use this method directly! Use @ref protoChmod * instead! * @param path The file's path * @param mode The new file mode */ virtual void protoChmodSingle(const KUrl &path, int mode) = 0; /** * This method should create a new remote directory. * * @param path Path of the newly created remote directory */ virtual void protoMkdir(const KUrl &path) = 0; /** * This method should fetch the remote directory listing for a specified * directory. Note that this method could be called as a chained command, * so it MUST NOT emit an EventDirectoryListing event if isChained returns * true! In this case it should save the directory listing to the * m_lastDirectoryListing member variable. * * @param path The path to list */ virtual void protoList(const KUrl &path) = 0; /** * This method should fetch the information about the given path. It is * usualy called as a chained command. * * @param path The path to stat */ virtual void protoStat(const KUrl &path); /** * This method should send a raw command in case the protocol supports it * (the SF_RAW_COMMAND is among features). * * @param command The command to send */ virtual void protoRaw(const QString&) {} /** * This method should initiate a site to site transfer in case the protocol * supports it (the SF_FXP_TRANSFER is among features). * * @param socket The destination socket * @param source The source url * @param destination The destination url */ virtual void protoSiteToSite(Socket*, const KUrl&, const KUrl&) {} /** * Send a packet to keep the connection alive. */ virtual void protoKeepAlive() {} /** * Recursively scan a directory and emit a DirectoryTree that can be used to * create new transfers for addition to the queue. * * @param path The path to recursively scan */ void protoScan(const KUrl &path); /** * Identify if the remote path is a file or a directory and recursively remove * it if so. The difference between this command and @ref protoRemove is, that * protoRemove removes just one entry, and doesn't identify file type. * * @param path The path to remove */ void protoDelete(const KUrl &path); /** * Change file or directory mode. Also supports recursive mode changes. * * @param path The file's path * @param mode The new file mode * @param recursive Should the mode be recursively changed */ void protoChmod(const KUrl &path, int mode, bool recursive); /** * Returns this socket's parent thread. * * @return Socket's parent thread */ Thread *thread() { return m_thread; } /** * Returns the protocol name of this socket. * * @return This socket's protocol name */ QString protocolName() { return m_protocol; } /** * This method should return the socket's features by or-ing the values in * SocketFeatures enum. * * @return Socket's features */ virtual int features() = 0; /** * This method should return true if this socket is connected. * * @return True if the socket has successfully connected */ virtual bool isConnected() = 0; /** * This method should return true if the connection is encrypted by some method. * * @return True if the connection is encrypted */ virtual bool isEncrypted() = 0; /** * Returns true if the socket is currently busy performing an action. * * @return True if the socket is busy */ virtual bool isBusy() { return m_currentCommand != Commands::CmdNone; } /** * Emit an engine error code. * * @param code The error code * @param param1 Optional string parameter */ void emitError(ErrorCode code, const QString ¶m1 = 0); /** * Emit an engine event. * * @param type Event type * @param param1 Optional string parameter * @param param2 Optional string parameter */ void emitEvent(Event::Type type, const QString ¶m1 = 0, const QString ¶m2 = 0); /** * Emit an engine event containing a directory listing. * * @param type Event type * @param param1 The DirectoryListing parameter */ void emitEvent(Event::Type type, DirectoryListing param1); /** * Emit an engine event containing a directory tree. * * @param type Event type * @param param1 The DirectoryTree parameter */ void emitEvent(Event::Type type, DirectoryTree *param1); /** * Emit an engine event containing a custom QVariant. * * @param type Event type * @param param1 The custom variant */ void emitEvent(Event::Type type, const QVariant ¶m1); /** * Emits an engine event containing a custom QVariant and blocks * until a response is received. * * @warning See Thread::waitForWakeup warning before using this method! * @param type Event type * @param param1 The custom variant * @return The WakeupEvent that responded to this call */ WakeupEvent *emitEventAndWait(Event::Type type, const QVariant ¶m1 = QVariant()); /** * This method will set the socket's remote encoding which will be used when * converting filenames into UTF-8 and back. * * @param encoding A valid encoding name */ virtual void changeEncoding(const QString &encoding); /** * Retrieve the KRemoteEncoding object for this socket set to the appropriate * encoding. * * @return The KRemoteEncoding object */ KRemoteEncoding *remoteEncoding() { return m_remoteEncoding; } /** * Sets the current directory path. * * @param path The current directory path */ void setCurrentDirectory(const QString &path) { m_currentDirectory = path; } /** * Get the current directory path. * * @return The current directory path. */ virtual QString getCurrentDirectory() { return m_currentDirectory; } /** * Sets the default directory path (like a remote home directory). * * @param path The default directory path */ void setDefaultDirectory(const QString &path) { m_defaultDirectory = path; } /** * Get the default directory path. * * @return The default directory path */ virtual QString getDefaultDirectory() { return m_defaultDirectory; } /** * Sets the url this socket is connected to. * * @param url The url this socket is connected to */ void setCurrentUrl(const KUrl &url) { m_currentUrl = url; } /** * Get the url this socket is connected to. * * @return The url this socket is currently connected to */ KUrl getCurrentUrl() { return m_currentUrl; } /** * Sets the command the socket is currently executing. * * @param type Command type */ void setCurrentCommand(Commands::Type type) { m_currentCommand = type; } /** * Get the current socket command. * * @return The current socket command */ Commands::Type getCurrentCommand(); /** * Get the toplevel socket command in the command chain. * * @return The toplevel socket command */ Commands::Type getToplevelCommand(); /** * Get the command that executed the current command. Note that this * is valid only if the current command is chained. Otherwise this * method returns Commands::CmdNone. * * @return The previous command */ Commands::Type getPreviousCommand(); /** * Get the last directory listing made by protoList. * * @return The last directory listing */ DirectoryListing getLastDirectoryListing() { return m_lastDirectoryListing; } /** * Get the last stat response made by protoStat. * * @return The last stat response */ DirectoryEntry getStatResponse() { return m_lastStatResponse; } /** * Get the number of bytes transfered from the beginning of the transfer. * * @return The number of bytes transfered */ filesize_t getTransferBytes() { return m_transferBytes; } /** * Get the current transfer speed. * * @return The current transfer speed. */ filesize_t getTransferSpeed(); /** * Wakeup the last command processor with a specific wakeup event. This * is used for async two-way communication between the engine and the * GUI (wakeup event is a reply from the GUI). * * By default this method just passes the event to the currently active * command processor. * * @param event The wakeup event that should be passed to the command class */ virtual void wakeup(WakeupEvent *event); /** * Reset the current command class, possibly invoking the calling chained * command class or completing the operation. * * @param code The result code */ virtual void resetCommandClass(ResetCode code = Ok); /** * Add a command class to the command chain so that it will be executed next. * * @param cmd The command class to add */ void addToCommandChain(Commands::Base *cmd) { m_commandChain.append(cmd); } /** * Execute the next command. */ void nextCommand(); /** * Schedule the execution of the next command in the next thread loop. */ void nextCommandAsync(); /** * Returns true if the current command has been chained from another command class. * * @return True if the current command has been chained */ bool isChained() const { return m_commandChain.count() > 0; } /** * Set the error reporting on or off. This variable is then used by some * command classes do determine if they should emit errors and reset with * failure or if they should just silently ignore the error and reset * the command class with an Ok code. * * @param value Error reporting value */ void setErrorReporting(bool value) { m_errorReporting = value; } /** * Get the current error reporting setting. This only makes sense if the * class is chained - otherwise this allways returns true. * * @param ignoreChaining Set to true to always return the current setting * @return The current error reporting setting */ bool errorReporting(bool ignoreChaining = false) const; /** * This method can be used to pass values from one chained command to the * other. Usually a result of some action should be saved here. * * @param value Chained command return value */ void setReturnValue(const QVariant &value) { setConfig("__returnvalue", value); } /** * Returns the return value that was set last. */ template T returnValue() const { return getConfig("__returnvalue"); } protected: /** * Call this method when a long wait period has started or ended. If the wait * isn't nulled before the timeout is reached the current action will be aborted * and the socket will be disconnected. * * @param start True if the wait period should start, false if it should end */ void timeoutWait(bool start); /** * Reset the timeout counter. Call this once in a while during long wait periods * to notify the engine that the socket is still responsive. */ void timeoutPing(); /** * Check if we should timeout. This method might cause a disconnect if the timeout * value is reached. */ void timeoutCheck(); /** * Enable the issue of keepalive packets. */ void keepaliveStart(); /** * Check if we should transmit a new keepalive packet. */ void keepaliveCheck(); protected: KRemoteEncoding *m_remoteEncoding; Commands::Base *m_cmdData; QStack m_commandChain; Settings *m_settings; Thread *m_thread; DirectoryListing m_lastDirectoryListing; DirectoryEntry m_lastStatResponse; filesize_t m_transferBytes; time_t m_speedLastTime; filesize_t m_speedLastBytes; QTime m_timeoutCounter; QTime m_keepaliveCounter; private: QString m_currentDirectory; QString m_defaultDirectory; KUrl m_currentUrl; QString m_protocol; Commands::Type m_currentCommand; bool m_errorReporting; QPointer m_connectionRetry; }; } Q_DECLARE_METATYPE(KFTPEngine::Socket*) #endif kftpgrabber-0.8.99~svn1214766/src/engine/otpgenerator.h0000644000175000017500000000560711276037142022331 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPENGINEOTPGENERATOR_H #define KFTPENGINEOTPGENERATOR_H #include namespace KFTPEngine { /** * One-Time Password generator required by some servers for authentication. Based * on code from otpCalc by Anthony D. Urso. * * @author Jernej Kos * @author Anthony D. Urso */ class OtpGenerator { public: /** * Supported hash algorithms. */ enum Algorithm { None, AlgoMD4, AlgoMD5, AlgoRMD160, AlgoSHA1 }; /** * Class constructor. * * @param challenge Server's challenge * @param password User's password */ OtpGenerator(const QString &challenge, const QString &password); /** * Generates a response to the provided challenge. */ QString response(); private: QString m_seed; QString m_password; Algorithm m_algorithm; int m_seq; void genDigest(char *msg, unsigned int len); void genDigestMD(int type, char *msg, unsigned int len); void genDigestRS(int type, char *msg, unsigned int len); static unsigned short extract(char *s, int start, int len); unsigned char parity(unsigned char *msg); unsigned char *sixWords(unsigned char *msg, char *response); }; } #endif kftpgrabber-0.8.99~svn1214766/src/engine/speedlimiter.h0000644000175000017500000000767111276037142022311 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPENGINESPEEDLIMITER_H #define KFTPENGINESPEEDLIMITER_H #include #include #include namespace KFTPEngine { class SpeedLimiterPrivate; class SpeedLimiterItem; /** * This class is used by Socket implementations to enforce speed limits for * uploads or downloads. It implements a variant of Token Bucket algorithm. * * @author Jernej Kos */ class SpeedLimiter : public QObject { Q_OBJECT friend class SpeedLimiterPrivate; public: /** * Possible limit types. */ enum Type { Download = 0, Upload = 1 }; /** * Returns the global speed limiter instance. */ static SpeedLimiter *self(); /** * Set a limit rate. * * @param type Limit type * @param limit Rate */ void setLimit(Type type, int limit); /** * Appends an item to be managed by the speed limiter. * * @param item Item instance * @param type Limit type */ void append(SpeedLimiterItem *item, Type type); /** * Removes an item from the speed limiter. * * @param item Item instance */ void remove(SpeedLimiterItem *item); /** * Removes an item from the speed limiter. * * @param item Item instance * @param type Limit type */ void remove(SpeedLimiterItem *item, Type type); protected: /** * Class constructor. */ SpeedLimiter(); /** * Class destructor. */ ~SpeedLimiter(); private: QTimer *m_timer; int m_limits[2]; QList m_objects[2]; int m_tokenDebt[2]; private slots: void updateLimits(); void synchronize(); signals: void activateTimer(int msec); }; /** * This class represents an item managed by the speed limiter. This is * usually a socket. * * @author Jernej Kos */ class SpeedLimiterItem { friend class SpeedLimiter; public: /** * Class constructor. */ SpeedLimiterItem(); /** * Returns the number of bytes allowed for consumption. */ int allowedBytes() const { return m_availableBytes; } protected: /** * Updates object's byte usage. */ void updateUsage(int bytes); private: int m_availableBytes; }; } #endif kftpgrabber-0.8.99~svn1214766/src/engine/otpgenerator.cpp0000644000175000017500000005315211276037142022662 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "otpgenerator.h" #include #include /* OpenSSL includes */ #include #include #include #include namespace KFTPEngine { OtpGenerator::OtpGenerator(const QString &challenge, const QString &password) : m_algorithm(None) { m_password = password; // Parse the string and set the alg (looks like this: otp-md5 498 gr4542) QString alg = challenge.section(' ', 0, 0); if (alg == "otp-md4" || alg == "s/key") m_algorithm = AlgoMD4; else if (alg == "otp-md5") m_algorithm = AlgoMD5; else if (alg == "otp-rmd160") m_algorithm = AlgoRMD160; else if (alg == "otp-sha1") m_algorithm = AlgoSHA1; // Extract the actual challenge m_seq = challenge.section(' ', 1, 1).toInt(); m_seed = challenge.section(' ', 2, 2).trimmed().toLower(); } void OtpGenerator::genDigest(char *msg, unsigned int len) { switch (m_algorithm) { case AlgoMD4: genDigestMD(4, msg, len); break; case AlgoMD5: genDigestMD(5, msg, len); break; case AlgoRMD160: genDigestRS(0, msg, len); break; case AlgoSHA1: genDigestRS(1, msg, len); break; default: return; } } QString OtpGenerator::response() { if (m_algorithm == None) return QString::null; unsigned char results[9]; char *tmp = (char*) malloc(m_seed.length() + m_password.length()); strcpy(tmp, QString(m_seed + m_password).toAscii().data()); genDigest(tmp, strlen(tmp)); memcpy(results, tmp, 8); free(tmp); for (unsigned short i = 0; i < m_seq; i++) { genDigest((char*) results, 8); } results[8] = parity(results); char *response = (char*) malloc(31); sixWords(results, response); return QString(response); } void OtpGenerator::genDigestMD(int type, char *msg, unsigned int len) { unsigned char digest[16]; unsigned short i; if (type == 4) MD4((const unsigned char*)msg, len, digest); else if (type == 5) MD5((const unsigned char*)msg, len, digest); for(i = 0; i < 8; i++) digest[i] ^= digest[i+8]; memcpy(msg, digest, 8); } void OtpGenerator::genDigestRS(int type, char *msg, unsigned int len) { unsigned char digest[20]; unsigned short i; if (type == 0) RIPEMD160((const unsigned char*)msg, len, digest); else if (type == 1) SHA1((const unsigned char*)msg, len, digest); for(i = 0; i < 8; i++) digest[i] ^= digest[i+8]; for(i = 0; i < 4; i++) digest[i] ^= digest[i+16]; memcpy(msg, digest, 8); } unsigned short OtpGenerator::extract(char *s, int start, int len) { unsigned char cl; unsigned char cc; unsigned char cr; unsigned int x; cl = s[start / 8]; cc = s[start / 8 + 1]; cr = s[start / 8 + 2]; x = ((int) (cl << 8 | cc) << 8 | cr); x = x >> (24 - (len + (start % 8))); x = (x & (0xffff >> (16 - len))); return (unsigned short)x; } unsigned char OtpGenerator::parity(unsigned char *msg) { unsigned short parity, i; parity = 0; for (i = 0; i < 64; i += 2) { parity += extract((char*)msg, i, 2); } return (unsigned char)parity << 6; } unsigned char *OtpGenerator::sixWords(unsigned char *msg, char *response) { static const char *words[2048] = { "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD", "AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN", "ANA", "AND", "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK", "ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", "AVE", "AWE", "AWK", "AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM", "BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN", "BET", "BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB", "BOG", "BON", "BOO", "BOP", "BOW", "BOY", "BUB", "BUD", "BUG", "BUM", "BUN", "BUS", "BUT", "BUY", "BY", "BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT", "CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW", "COY", "CRY", "CUB", "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN", "DAR", "DAY", "DEE", "DEL", "DEN", "DES", "DEW", "DID", "DIE", "DIG", "DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB", "DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG", "EGO", "ELI", "ELK", "ELM", "ELY", "EM", "END", "EST", "ETC", "EVA", "EVE", "EWE", "EYE", "FAD", "FAN", "FAR", "FAT", "FAY", "FED", "FEE", "FEW", "FIB", "FIG", "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR", "FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM", "GAP", "GAS", "GAY", "GEE", "GEL", "GEM", "GET", "GIG", "GIL", "GIN", "GO", "GOT", "GUM", "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", "HAD", "HAL", "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM", "HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS", "HIT", "HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", "HOW", "HUB", "HUE", "HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", "IF", "IKE", "ILL", "INK", "INN", "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT", "ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", "JAY", "JET", "JIG", "JIM", "JO", "JOB", "JOE", "JOG", "JOT", "JOY", "JUG", "JUT", "KAY", "KEG", "KEN", "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB", "LAC", "LAD", "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE", "LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP", "LIT", "LO", "LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", "LUG", "LYE", "MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", "MAT", "MAW", "MAY", "ME", "MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT", "MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD", "MUG", "MUM", "MY", "NAB", "NAG", "NAN", "NAP", "NAT", "NAY", "NE", "NED", "NEE", "NET", "NEW", "NIB", "NIL", "NIP", "NIT", "NO", "NOB", "NOD", "NON", "NOR", "NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF", "OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL", "OK", "OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT", "OUR", "OUT", "OVA", "OW", "OWE", "OWL", "OWN", "OX", "PA", "PAD", "PAL", "PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG", "PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN", "PIT", "PLY", "PO", "POD", "POE", "POP", "POT", "POW", "PRO", "PRY", "PUB", "PUG", "PUN", "PUP", "PUT", "QUO", "RAG", "RAM", "RAN", "RAP", "RAT", "RAW", "RAY", "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM", "RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB", "RUE", "RUG", "RUM", "RUN", "RYE", "SAC", "SAD", "SAG", "SAL", "SAM", "SAN", "SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", "SET", "SEW", "SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY", "SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", "SPA", "SPY", "SUB", "SUD", "SUE", "SUM", "SUN", "SUP", "TAB", "TAD", "TAG", "TAN", "TAP", "TAR", "TEA", "TED", "TEE", "TEN", "THE", "THY", "TIC", "TIE", "TIM", "TIN", "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP", "TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", "UN", "UP", "US", "USE", "VAN", "VAT", "VET", "VIE", "WAD", "WAG", "WAR", "WAS", "WAY", "WE", "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT", "WOK", "WON", "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE", "YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", "ABUT", "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS", "ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA", "AIDE", "AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", "ALIA", "ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA", "AMEN", "AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", "ANEW", "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", "AREA", "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS", "ATOM", "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", "AVOW", "AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", "BAIL", "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM", "BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE", "BARK", "BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE", "BATH", "BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", "BEAT", "BEAU", "BECK", "BEEF", "BEEN", "BEER", "BEET", "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN", "BERT", "BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", "BIEN", "BILE", "BILK", "BILL", "BIND", "BING", "BIRD", "BITE", "BITS", "BLAB", "BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT", "BLOW", "BLUE", "BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK", "BODE", "BODY", "BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT", "BOMB", "BONA", "BOND", "BONE", "BONG", "BONN", "BONY", "BOOK", "BOOM", "BOON", "BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS", "BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN", "BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", "BUFF", "BULB", "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", "BURL", "BURN", "BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", "BUSY", "BYTE", "CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF", "CALL", "CALM", "CAME", "CANE", "CANT", "CARD", "CARE", "CARL", "CARR", "CART", "CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL", "CELL", "CENT", "CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF", "CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG", "CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY", "CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", "COCK", "COCO", "CODA", "CODE", "CODY", "COED", "COIL", "COIN", "COKE", "COLA", "COLD", "COLT", "COMA", "COMB", "COME", "COOK", "COOL", "COON", "COOT", "CORD", "CORE", "CORK", "CORN", "COST", "COVE", "COWL", "CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB", "CROW", "CRUD", "CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY", "CURB", "CURD", "CURE", "CURL", "CURT", "CUTS", "DADE", "DALE", "DAME", "DANA", "DANE", "DANG", "DANK", "DARE", "DARK", "DARN", "DART", "DASH", "DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS", "DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", "DEEM", "DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", "DIAL", "DICE", "DIED", "DIET", "DIME", "DINE", "DING", "DINT", "DIRE", "DIRT", "DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES", "DOLE", "DOLL", "DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA", "DOSE", "DOTE", "DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG", "DRAM", "DRAW", "DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK", "DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK", "DUSK", "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST", "EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", "EDNA", "EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", "EMMA", "ENDS", "ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", "FACE", "FACT", "FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL", "FAME", "FANG", "FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT", "FEED", "FEEL", "FEET", "FELL", "FELT", "FEND", "FERN", "FEST", "FEUD", "FIEF", "FIGS", "FILE", "FILL", "FILM", "FIND", "FINE", "FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE", "FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW", "FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", "FOGY", "FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", "FOOT", "FORD", "FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", "FOUR", "FOWL", "FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY", "FROG", "FROM", "FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY", "FUSE", "FUSS", "GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA", "GALE", "GALL", "GALT", "GAME", "GANG", "GARB", "GARY", "GASH", "GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE", "GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT", "GINA", "GIRD", "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", "GLIB", "GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", "GOAL", "GOAT", "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", "GOOD", "GOOF", "GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB", "GRAD", "GRAY", "GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN", "GRIT", "GROW", "GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH", "GUST", "GWEN", "GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR", "HALE", "HALF", "HALL", "HALO", "HALT", "HAND", "HANG", "HANK", "HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", "HATE", "HATH", "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", "HEAT", "HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", "HELM", "HERB", "HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", "HICK", "HIDE", "HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT", "HIRE", "HISS", "HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE", "HOLM", "HOLT", "HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK", "HOOT", "HORN", "HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL", "HOYT", "HUCK", "HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK", "HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE", "HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", "INTO", "IONS", "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", "ITCH", "ITEM", "IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", "JAVA", "JEAN", "JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL", "JILT", "JIVE", "JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", "JOIN", "JOKE", "JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY", "JUJU", "JUKE", "JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST", "JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE", "KEEL", "KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS", "KICK", "KILL", "KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", "KNIT", "KNOB", "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", "KURT", "KYLE", "LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", "LAIR", "LAKE", "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", "LARK", "LASS", "LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS", "LAYS", "LEAD", "LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER", "LEFT", "LEND", "LENS", "LENT", "LEON", "LESK", "LESS", "LEST", "LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU", "LIFE", "LIFT", "LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB", "LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST", "LIVE", "LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", "LOIS", "LOLA", "LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", "LORE", "LOSE", "LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK", "LUCY", "LUGE", "LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE", "LURK", "LUSH", "LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE", "MADE", "MAGI", "MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI", "MALL", "MALT", "MANA", "MANN", "MANY", "MARC", "MARE", "MARK", "MARS", "MART", "MARY", "MASH", "MASK", "MASS", "MAST", "MATE", "MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", "MEET", "MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", "MESS", "MICE", "MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", "MIMI", "MIND", "MINE", "MINI", "MINK", "MINT", "MIRE", "MISS", "MIST", "MITE", "MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD", "MOLE", "MOLL", "MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON", "MOOR", "MOOT", "MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH", "MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK", "MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL", "NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", "NEAT", "NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", "NEST", "NEWS", "NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", "NINE", "NOAH", "NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON", "NORM", "NOSE", "NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB", "OATH", "OBEY", "OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY", "OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE", "ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS", "OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY", "OWNS", "QUAD", "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", "RAGE", "RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", "RASH", "RATE", "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", "RECK", "REED", "REEF", "REEK", "REEL", "REID", "REIN", "RENA", "REND", "RENT", "REST", "RICE", "RICH", "RICK", "RIDE", "RIFT", "RILL", "RIME", "RING", "RINK", "RISE", "RISK", "RITE", "ROAD", "ROAM", "ROAR", "ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME", "ROOD", "ROOF", "ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS", "ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY", "RUDE", "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", "RUSH", "RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", "SAID", "SAIL", "SALE", "SALK", "SALT", "SAME", "SAND", "SANE", "SANG", "SANK", "SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR", "SCAT", "SCOT", "SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK", "SEEM", "SEEN", "SEES", "SELF", "SELL", "SEND", "SENT", "SETS", "SEWN", "SHAG", "SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN", "SHOD", "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE", "SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE", "SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", "SKID", "SKIM", "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", "SLED", "SLEW", "SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", "SLOW", "SLUG", "SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB", "SNOW", "SNUB", "SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA", "SOFT", "SOIL", "SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE", "SORT", "SOUL", "SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR", "STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN", "SUCH", "SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF", "SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", "TACK", "TACT", "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", "TASK", "TATE", "TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", "TEEN", "TEET", "TELL", "TEND", "TENT", "TERM", "TERN", "TESS", "TEST", "THAN", "THAT", "THEE", "THEM", "THEN", "THEY", "THIN", "THIS", "THUD", "THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER", "TILE", "TILL", "TILT", "TIME", "TINA", "TINE", "TINT", "TINY", "TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG", "TONY", "TOOK", "TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR", "TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", "TRIM", "TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", "TUCK", "TUFT", "TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", "TWIG", "TWIN", "TWIT", "ULAN", "UNIT", "URGE", "USED", "USER", "USES", "UTAH", "VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST", "VEAL", "VEDA", "VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY", "VETO", "VICE", "VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE", "WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK", "WALL", "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", "WARM", "WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", "WAYS", "WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", "WELD", "WELL", "WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", "WHAT", "WHEE", "WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE", "WILD", "WILL", "WIND", "WINE", "WING", "WINK", "WINO", "WIRE", "WISE", "WISH", "WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD", "WORE", "WORK", "WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", "YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR", "YELL", "YOGA", "YOKE" }; snprintf(response, 31, "%s %s %s %s %s %s", words[extract((char*)msg, 0, 11)], words[extract((char*)msg, 11, 11)], words[extract((char*)msg, 22, 11)], words[extract((char*)msg, 33, 11)], words[extract((char*)msg, 44, 11)], words[extract((char*)msg, 55, 11)]); return (unsigned char*) response; } } kftpgrabber-0.8.99~svn1214766/src/engine/ftpdirectoryparser.h0000644000175000017500000000634211276037142023550 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPENGINEFTPDIRECTORYPARSER_H #define KFTPENGINEFTPDIRECTORYPARSER_H #include #include "directorylisting.h" namespace KFTPEngine { class FtpSocket; class DToken; class DLine; /** * This class can parse multiple directory formats. Some code portions have * been taken from a windows FTP client "FileZilla by Tim Kosse" - the * logic is mostly the same, the code has just been ported so it is more Qt * and so it integrates nicely with the rest of the engine. * * @author Jernej Kos * @author Tim Kosse */ class FtpDirectoryParser { public: FtpDirectoryParser(FtpSocket *socket); void addData(const char *data, int len); void addDataLine(const QString &line); bool parseLine(const QString &line, DirectoryEntry &entry); DirectoryListing getListing() { return m_listing; } private: FtpSocket *m_socket; QString m_buffer; DirectoryListing m_listing; QMap m_monthNameMap; bool parseMlsd(const QString &line, DirectoryEntry &entry); bool parseUnix(DLine *line, DirectoryEntry &entry); bool parseDos(DLine *line, DirectoryEntry &entry); bool parseVms(DLine *line, DirectoryEntry &entry); bool parseUnixDateTime(DLine *line, int &index, DirectoryEntry &entry); bool parseShortDate(DToken &token, DirectoryEntry &entry); bool parseTime(DToken &token, DirectoryEntry &entry); bool parseComplexFileSize(DToken &token, filesize_t &size); bool parseUnixPermissions(const QString &permissions, DirectoryEntry &entry); }; } #endif kftpgrabber-0.8.99~svn1214766/src/engine/thread.h0000644000175000017500000001632211276037142021063 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPENGINETHREAD_H #define KFTPENGINETHREAD_H #include #include #include #include #include #include #include "event.h" #include "directorylisting.h" #include "commands.h" #include "socket.h" namespace KFTPEngine { class Settings; /** * The command queue handles any incoming requests for execution of * individual commands on sockets. * * @author Jernej Kos */ class CommandQueue : public QObject { public: /** * This event should be used to notify this class of newly * created pending commands. */ class Event : public QEvent { public: /** * Class constructor. * * @param type Command type */ Event(Commands::Type type); /** * Returns the event command type. */ Commands::Type command() { return m_type; } /** * Adds a new command parameter. */ void addParameter(QVariant parameter) { m_parameters.append(parameter); } /** * Returns a specified parameter. */ QVariant parameter(int index) { return m_parameters[index]; } private: Commands::Type m_type; QList m_parameters; }; /** * Class constructor. */ CommandQueue(Thread *thread); protected: /** * This method gets called when an event is delivered to * the command queue. */ void customEvent(QEvent *event); private: Thread *m_thread; }; /** * This class represents a socket thread. It serves as a command queue to * the underlying socket implementation and also as an abstraction layer * to support multiple protocols. * * @author Jernej Kos */ class Thread : public QThread { Q_OBJECT friend class CommandQueue; friend class EventHandler; friend class Socket; public: /** * Class constructor. */ Thread(); /** * Class destructor. */ ~Thread(); /** * Returns the event handler for this thread. Should be used to connect * to any signals this thread may emit. * * @return A pointer to the EventHandler object */ EventHandler *eventHandler() const { return m_eventHandler; } /** * Returns the underlying socket object. * * @return A pointer to the Socket object */ Socket *socket() const { return m_socket; } /** * Returns the settings object. */ Settings *settings() const { return m_settings; } /** * Schedules a wakeup event to be passed on to the underlying socket. * * @param e The wakeup event to pass on */ void wakeup(WakeupEvent *e); /** * Requests the thread to shutdown. */ void shutdown(); void abort(); void connect(const KUrl &url); void disconnect(); void list(const KUrl &url); void scan(const KUrl &url); void get(const KUrl &source, const KUrl &destination); void put(const KUrl &source, const KUrl &destination); void remove(const KUrl &url); void rename(const KUrl &source, const KUrl &destination); void chmod(const KUrl &url, int mode, bool recursive = false); void mkdir(const KUrl &url); void raw(const QString &raw); void siteToSite(Thread *thread, const KUrl &source, const KUrl &destination); protected: /** * Thread entry point. */ void run(); /** * Emits an event to the outside world. */ void emitEvent(Event::Type type, QList params); /** * Blocks the execution of this thread until a wakeup event is received. This * method should only be used for things like peer certificate verification * where user input is requested in place and methods cannot be deferred. Other * than that this method should NOT be used. * * @warning Such an event MUST be replied to by the main thread. Failure to * do so will permanently lock this thread! * * @return A valid WakeupEvent instance or NULL if an abort ocurred */ WakeupEvent *waitForWakeup(); /** * Sets the protocol implementation to be used by the current thread. It * has to be set before the connect method is called, and MUST be called * from within this thread. * * @param protocol Wanted protocol name */ void setCurrentProtocol(const QString &protocol); /** * @overload * This overloaded method is provided for convenience. * * @param url Url from which to extract the protocol */ void setCurrentProtocol(const KUrl &url); /** * Delivers the specified command event to the command queue. * * @param event Command event * @param priority Event priority */ void notifyCommandQueue(CommandQueue::Event *event, int priority = Qt::NormalEventPriority); /** * Requests a deferred execution of the next command in the * socket's command chain. * * This method should only be called from inside this thread! */ void deferCommandExec(); protected slots: /** * Terminates the thread and schedules its deletion. */ void shutdownWithTerminate(); protected: EventHandler *m_eventHandler; Socket *m_socket; Settings *m_settings; QHash m_sockets; CommandQueue *m_commandQueue; QSemaphore m_startupSem; bool m_exit; int m_commandsDeferred; QMutex m_imWakeupMutex; QWaitCondition m_imWakeupCond; WakeupEvent *m_imWakeupEvent; bool m_immediateWakeup; }; } #endif kftpgrabber-0.8.99~svn1214766/src/engine/sftpsocket.h0000644000175000017500000000676211276037142022010 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPENGINESFTPSOCKET_H #define KFTPENGINESFTPSOCKET_H #include #include #include #include #include #include "socket.h" #include "speedlimiter.h" namespace KFTPEngine { /** * @author Jernej Kos */ class SftpSocket : public QTcpSocket, public Socket, public SpeedLimiterItem { Q_OBJECT friend class SftpCommandConnect; friend class SftpCommandList; friend class SftpCommandGet; friend class SftpCommandPut; public: SftpSocket(Thread *thread); ~SftpSocket(); void protoConnect(const KUrl &url); void protoDisconnect(); void protoAbort(); void protoGet(const KUrl &source, const KUrl &destination); void protoPut(const KUrl &source, const KUrl &destination); void protoRemove(const KUrl &path); void protoRename(const KUrl &source, const KUrl &destination); void protoChmodSingle(const KUrl &path, int mode); void protoMkdir(const KUrl &path); void protoList(const KUrl &path); int features() { return 0; } bool isConnected() { return m_login; } bool isEncrypted() { return true; } LIBSSH2_SESSION *sshSession() { return m_sshSession; } LIBSSH2_SFTP *sftpSession() { return m_sftpSession; } QFile *getTransferFile() { return &m_transferFile; } protected: QString posixToString(int permissions); int intToPosix(int permissions); void variableBufferUpdate(int size); private: LIBSSH2_SESSION *m_sshSession; LIBSSH2_SFTP *m_sftpSession; bool m_login; LIBSSH2_SFTP_HANDLE *m_transferHandle; QFile m_transferFile; char *m_transferBuffer; int m_transferBufferSize; private slots: void slotDisconnected(); void slotConnected(); void slotError(); void slotDataTryRead(); void slotDataTryWrite(); }; } #endif kftpgrabber-0.8.99~svn1214766/src/engine/ftpsocket.h0000644000175000017500000001260411276037142021615 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPENGINEFTPSOCKET_H #define KFTPENGINEFTPSOCKET_H #include #include #include #include #include #include #include "speedlimiter.h" #include "socket.h" namespace KFTPEngine { class FtpDirectoryParser; /** * A simple wrapper that returns QSslSocket objects instead of * standard QTcpSockets. * * @author Jernej Kos */ class SslServer : public QTcpServer { public: /** * Class constructor. */ SslServer(); /** * @overload * Reimplemented from QTcpServer. */ QSslSocket *nextPendingConnection(); protected: /** * @overload * Reimplemented from QTcpServer. */ void incomingConnection(int socketDescriptor); private: QSslSocket *m_socket; }; /** * @author Jernej Kos */ class FtpSocket : public QSslSocket, public Socket, public SpeedLimiterItem { Q_OBJECT friend class Commands::Base; friend class FtpCommandConnect; friend class FtpCommandNegotiateData; friend class FtpCommandList; public: FtpSocket(Thread *thread); ~FtpSocket(); void protoConnect(const KUrl &url); void protoDisconnect(); void protoAbort(); void protoGet(const KUrl &source, const KUrl &destination); void protoPut(const KUrl &source, const KUrl &destination); void protoRemove(const KUrl &path); void protoRename(const KUrl &source, const KUrl &destination); void protoChmodSingle(const KUrl &path, int mode); void protoMkdir(const KUrl &path); void protoList(const KUrl &path); void protoRaw(const QString &raw); void protoSiteToSite(Socket *socket, const KUrl &source, const KUrl &destination); void protoKeepAlive(); void changeWorkingDirectory(const QString &path, bool shouldCreate = false); int features() { return SF_FXP_TRANSFER | SF_RAW_COMMAND; } bool isConnected() { return m_login; } bool isEncrypted() { return isConnected() && getConfig("ssl", false); } bool isResponse(const QString &code); QString getResponse() { return m_response; } bool isMultiline() { return !m_multiLineCode.isEmpty(); } void sendCommand(const QString &command); void resetCommandClass(ResetCode code = Ok); void setupPassiveTransferSocket(const QString &host, int port); SocketAddress setupActiveTransferSocket(); QFile *getTransferFile() { return &m_transferFile; } void checkTransferEnd(); void checkTransferStart(); void resetTransferStart() { m_transferStart = 0; } protected: void parseLine(const QString &line); void variableBufferUpdate(int size); void closeDataTransferSocket(); void initializeTransferSocket(); void transferCompleted(); private: bool m_login; QString m_buffer; QString m_multiLineCode; QString m_response; QSslSocket *m_transferSocket; SslServer *m_serverSocket; FtpDirectoryParser *m_directoryParser; char m_controlBuffer[1024]; QFile m_transferFile; char *m_transferBuffer; int m_transferBufferSize; int m_transferStart; int m_transferEnd; QTimer *m_keepaliveTimer; protected slots: /** * This method checks for timeouts and acts if needed. */ void timerUpdate(); void slotDisconnected(); void slotConnected(); void slotControlTryRead(); void slotError(); void slotSslErrors(const QList &errors); void slotSslNegotiated(); void slotDataAccept(); void slotDataConnected(); void slotDataSslNegotiated(); void slotDataDisconnected(); void slotDataError(QAbstractSocket::SocketError error); void slotDataTryRead(); void slotDataTryWrite(); }; } Q_DECLARE_METATYPE(QSslError) #endif kftpgrabber-0.8.99~svn1214766/src/engine/cache.h0000644000175000017500000001253411276037142020660 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPENGINECACHE_H #define KFTPENGINECACHE_H #include #include #include "directorylisting.h" namespace KFTPEngine { class Socket; class CachePrivate; /** * This class provides a cache of paths and directory listings to be used for * faster operations. * * @author Jernej Kos */ class Cache { friend class CachePrivate; public: static Cache *self(); /** * Cache a directory listing. * * @param url The listing url (including host information) * @param listing The directory listing to cache */ void addDirectory(KUrl &url, DirectoryListing listing); /** * Cache a directory listing, extracting the host information from the * socket and using the current directory path. * * @param socket The socket to extract the host info from * @param listing The directory listing to cache */ void addDirectory(Socket *socket, DirectoryListing listing); /** * Updates a single directory entry. * * @param socket The socket to extract the host info from * @param path Entry location * @param filesize New file size */ void updateDirectoryEntry(Socket *socket, KUrl &path, filesize_t filesize); /** * Cache path information. * * @param url The url (including host information) * @param target Actual target directory */ void addPath(KUrl &url, const QString &target); /** * Cache path information, extracting the host information from the * socket and using the current directory path. * * @param socket The socket to extract the host info from * @param target Actual target directory */ void addPath(Socket *socket, const QString &target); /** * Invalidate a cached entry. * * @param url Url of the entry */ void invalidateEntry(KUrl &url); /** * Invalidate a cached entry. * * @param socket The socket to extract the host info from * @param path Path of the entry */ void invalidateEntry(Socket *socket, const QString &path); /** * Invalidate a cached path. * * @param url Url of the entry */ void invalidatePath(KUrl &url); /** * Invalidate a cached path. * * @param socket The socket to extract the host info from * @param path Path of the entry */ void invalidatePath(Socket *socket, const QString &path); /** * Retrieve a cached directory listing. * * @param url Url of the entry * @return A valid DirectoryListing if found, an empty DirectoryListing otherwise */ DirectoryListing findCached(KUrl &url); /** * Retrieve a cached directory listing. * * @param socket The socket to extract the host info from * @param path Path of the entry * @return A valid DirectoryListing if found, an empty DirectoryListing otherwise */ DirectoryListing findCached(Socket *socket, const QString &path); /** * Retrieve a cached path. * * @param url Url of the entry * @return A target path if found, QString::null otherwise */ QString findCachedPath(KUrl &url); /** * Retrieve a cached path. * * @param socket The socket to extract the host info from * @param path Path of the entry * @return A target path if found, QString::null otherwise */ QString findCachedPath(Socket *socket, const QString &path); protected: /** * Class constructor. */ Cache(); /** * Class destructor. */ ~Cache(); private: QMap m_listingCache; QMap m_pathCache; }; } #endif kftpgrabber-0.8.99~svn1214766/src/engine/ftpsocket.cpp0000644000175000017500000026241711276037142022161 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "ftpsocket.h" #include "thread.h" #include "ftpdirectoryparser.h" #include "cache.h" #include "speedlimiter.h" #include "otpgenerator.h" #include "misc/config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include Q_DECLARE_METATYPE(QSslCertificate) Q_DECLARE_METATYPE(QSslKey) namespace KFTPEngine { SslServer::SslServer() : QTcpServer() { } QSslSocket *SslServer::nextPendingConnection() { return m_socket; } void SslServer::incomingConnection(int socketDescriptor) { m_socket = new QSslSocket(); m_socket->setSocketDescriptor(socketDescriptor); } FtpSocket::FtpSocket(Thread *thread) : QSslSocket(), Socket(thread, "ftp"), SpeedLimiterItem(), m_login(false), m_transferSocket(0), m_serverSocket(0), m_directoryParser(0) { m_keepaliveTimer = new QTimer(this); connect(m_keepaliveTimer, SIGNAL(timeout()), this, SLOT(timerUpdate())); m_keepaliveTimer->start(1000); // Control socket signals connect(this, SIGNAL(readyRead()), this, SLOT(slotControlTryRead())); connect(this, SIGNAL(connected()), this, SLOT(slotConnected())); connect(this, SIGNAL(disconnected()), this, SLOT(slotDisconnected())); connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotError())); connect(this, SIGNAL(sslErrors(const QList&)), this, SLOT(slotSslErrors(const QList&))); connect(this, SIGNAL(encrypted()), this, SLOT(slotSslNegotiated())); } FtpSocket::~FtpSocket() { protoDisconnect(); } void FtpSocket::timerUpdate() { timeoutCheck(); keepaliveCheck(); } void FtpSocket::slotDisconnected() { protoDisconnect(); } void FtpSocket::slotControlTryRead() { QString tmpStr; qint64 size = read(m_controlBuffer, sizeof(m_controlBuffer) - 1); if (size == 0) return; for (int i = 0; i < size; i++) if (m_controlBuffer[i] == 0) m_controlBuffer[i] = '!'; memset(m_controlBuffer + size, 0, sizeof(m_controlBuffer) - size); m_buffer.append(m_controlBuffer); // Parse any lines we might have int pos; while ((pos = m_buffer.indexOf('\n')) > -1) { QString line = m_buffer.mid(0, pos); line = m_remoteEncoding->decode(line.toAscii()); parseLine(line); // Remove what we just parsed m_buffer.remove(0, pos + 1); } if (bytesAvailable()) slotControlTryRead(); } void FtpSocket::parseLine(const QString &line) { // Is this the end of multiline response ? if (!m_multiLineCode.isEmpty() && line.left(4) == m_multiLineCode) { m_multiLineCode = ""; emitEvent(Event::EventResponse, line); } else if (line.length() >= 4 && line[3] == '-' && m_multiLineCode.isEmpty()) { m_multiLineCode = line.left(3) + " "; emitEvent(Event::EventMultiline, line); } else if (!m_multiLineCode.isEmpty()) { emitEvent(Event::EventMultiline, line); } else { // Normal response emitEvent(Event::EventResponse, line); } timeoutWait(false); // Parse our response m_response = line; nextCommand(); } bool FtpSocket::isResponse(const QString &code) { QString ref; if (isMultiline()) ref = m_multiLineCode; else ref = m_response; return ref.left(code.length()) == code; } void FtpSocket::sendCommand(const QString &command) { emitEvent(Event::EventCommand, command); QByteArray buffer = m_remoteEncoding->encode(command) + "\r\n"; write(buffer.data(), buffer.length()); timeoutWait(true); } void FtpSocket::resetCommandClass(ResetCode code) { timeoutWait(false); if (m_transferSocket && code != Ok) { // Invalidate the socket closeDataTransferSocket(); // Close the file that failed transfer if (getTransferFile()->isOpen()) { getTransferFile()->close(); if (getCurrentCommand() == Commands::CmdGet && getTransferFile()->size() == 0) getTransferFile()->remove(); } } if (m_serverSocket && code != Ok) { m_serverSocket->deleteLater(); m_serverSocket = 0; } Socket::resetCommandClass(code); } // ******************************************************************************************* // ***************************************** CONNECT ***************************************** // ******************************************************************************************* class FtpCommandConnect : public Commands::Base { public: enum State { None, SentAuthTls, WaitEncryption, SentUser, SentPass, SentPbsz, SentProt, DoingSyst, DoingFeat, SentPwd }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandConnect, FtpSocket, CmdNone) void process() { switch (currentState) { case None: { if (!socket()->isMultiline()) { if (socket()->isResponse("2")) { // Negotiate a SSL connection if configured if (socket()->getConfig("ssl.use_tls")) { currentState = SentAuthTls; socket()->sendCommand("AUTH TLS"); } else { // Send username currentState = SentUser; socket()->sendCommand("USER " + socket()->getCurrentUrl().user()); } } else { socket()->emitEvent(Event::EventMessage, i18n("Connection has failed.")); socket()->protoAbort(); socket()->emitError(ConnectFailed, i18n("Server said: %1", socket()->getResponse())); } } break; } case SentAuthTls: { if (socket()->isResponse("2")) { socket()->startClientEncryption(); currentState = WaitEncryption; } else { socket()->emitEvent(Event::EventMessage, i18n("SSL negotiation request failed. Login aborted.")); socket()->resetCommandClass(Failed); socket()->protoAbort(); } break; } case WaitEncryption: { // Encryption has been successfully negotiated, send the username currentState = SentUser; socket()->sendCommand("USER " + socket()->getCurrentUrl().user()); break; } case SentUser: { if (socket()->isResponse("331")) { // Send password if (socket()->isResponse("331 Response to otp-")) { // OTP: 331 Response to otp-md5 41 or4828 ext required for foo. QString tmp = socket()->getResponse(); tmp = tmp.section(' ', 3, 5); OtpGenerator otp(tmp, socket()->getCurrentUrl().pass()); currentState = SentPass; socket()->sendCommand("PASS " + otp.response()); } else { socket()->sendCommand("PASS " + socket()->getCurrentUrl().pass()); currentState = SentPass; } } else if (socket()->isResponse("230")) { // Some servers imediately send the 230 response for anonymous accounts if (!socket()->isMultiline()) { if (socket()->getConfig("ssl")) { currentState = SentPbsz; socket()->sendCommand("PBSZ 0"); } else { // Do SYST socket()->sendCommand("SYST"); currentState = DoingSyst; } } } else { socket()->emitEvent(Event::EventMessage, i18n("Login has failed.")); socket()->protoAbort(); socket()->emitError(LoginFailed, i18n("The specified login credentials were rejected by the server.")); } break; } case SentPass: { if (socket()->isResponse("230")) { if (!socket()->isMultiline()) { if (socket()->getConfig("ssl")) { currentState = SentPbsz; socket()->sendCommand("PBSZ 0"); } else { // Do SYST socket()->sendCommand("SYST"); currentState = DoingSyst; } } } else { socket()->emitEvent(Event::EventMessage, i18n("Login has failed.")); socket()->protoAbort(); socket()->emitError(LoginFailed, i18n("The specified login credentials were rejected by the server.")); } break; } case SentPbsz: { currentState = SentProt; QString prot = "PROT "; if (socket()->getConfig("ssl.prot_mode") == 0) prot.append('P'); else prot.append('C'); socket()->sendCommand(prot); break; } case SentProt: { if (socket()->isResponse("5")) { // Fallback to unencrypted data channel socket()->setConfig("ssl.prot_mode", 2); } currentState = DoingSyst; socket()->sendCommand("SYST"); break; } case DoingSyst: { socket()->sendCommand("FEAT"); currentState = DoingFeat; break; } case DoingFeat: { if (socket()->isMultiline()) { parseFeat(); } else { socket()->sendCommand("PWD"); currentState = SentPwd; } break; } case SentPwd: { // Parse the current working directory if (socket()->isResponse("2")) { // 257 "/home/default/path" QString tmp = socket()->getResponse(); int first = tmp.indexOf('"') + 1; tmp = tmp.mid(first, tmp.lastIndexOf('"') - first); socket()->setDefaultDirectory(tmp); socket()->setCurrentDirectory(tmp); } // Enable transmission of keepalive events socket()->keepaliveStart(); currentState = None; socket()->emitEvent(Event::EventMessage, i18n("Connected.")); socket()->emitEvent(Event::EventConnect); socket()->m_login = true; socket()->resetCommandClass(); break; } } } void parseFeat() { QString feat = socket()->getResponse().trimmed().toUpper(); if (feat.left(3).toInt() > 0 && feat[3] == '-') feat.remove(0, 4); if (feat.left(4) == "MDTM") { // Server has MDTM (MoDification TiMe) support socket()->setConfig("feat.mdtm", true); } else if (feat.left(4) == "PRET") { // Server is a distributed ftp server and requires PRET for transfers socket()->setConfig("feat.pret", true); } else if (feat.left(4) == "MLSD") { // Server supports machine-friendly directory listings socket()->setConfig("feat.mlsd", true); } else if (feat.left(4) == "REST") { // Server supports resume operations socket()->setConfig("feat.rest", true); } else if (feat.left(4) == "SSCN") { // Server supports SSCN for secure site-to-site transfers socket()->setConfig("feat.sscn", true); socket()->setConfig("feat.cpsv", false); } else if (feat.left(4) == "CPSV" && !socket()->getConfig("feat.sscn")) { // Server supports CPSV for secure site-to-site transfers socket()->setConfig("feat.cpsv", true); } } }; void FtpSocket::protoConnect(const KUrl &url) { emitEvent(Event::EventState, i18n("Connecting...")); emitEvent(Event::EventMessage, i18n("Connecting to %1:%2...",url.host(),url.port())); if (!getConfig("encoding").isEmpty()) changeEncoding(getConfig("encoding")); // Start the connect procedure setCurrentUrl(url); setProxy(KSocketFactory::proxyForConnection(url.protocol(), url.host())); connectToHost(url.host(), url.port()); } void FtpSocket::slotConnected() { timeoutWait(true); // Set acceptable SSL protocols and set certificate store QSslSocket::setProtocol(QSsl::AnyProtocol); QSslSocket::setCaCertificates(KFTPCore::Config::self()->certificateStore()->trustedCertificates()); // Configure peer certificate and private key (if set) if (!getConfig("ssl.certificate").isNull()) { QSslSocket::setLocalCertificate(getConfig("ssl.certificate")); QSslSocket::setPrivateKey(getConfig("ssl.private_key")); } emitEvent(Event::EventState, i18n("Logging in...")); emitEvent(Event::EventMessage, i18n("Connected with server, waiting for welcome message...")); setupCommandClass(FtpCommandConnect); if (getConfig("ssl.use_implicit")) startClientEncryption(); } void FtpSocket::slotError() { emitEvent(Event::EventMessage, i18n("Failed to connect (%1.)", errorString())); emitError(ConnectFailed, errorString()); resetCommandClass(FailedSilently); } void FtpSocket::slotSslNegotiated() { QSslCipher cipher = sessionCipher(); emitEvent(Event::EventMessage, i18n("SSL negotiation successful. Connection is secured with %1 bit cipher %2.", cipher.usedBits(), cipher.name())); setConfig("ssl", true); // Proceed with the next command if (!getConfig("ssl.use_implicit")) nextCommandAsync(); } void FtpSocket::slotSslErrors(const QList &errors) { if (getConfig("ssl.ignore_errors")) { ignoreSslErrors(); return; } // Request immediate action from the user QVariantList elist; foreach (QSslError error, errors) { elist << QVariant::fromValue(QSslError(error.error(), peerCertificate())); } PeerVerifyWakeupEvent *response = static_cast(emitEventAndWait(Event::EventPeerVerify, elist)); if (response && response->peerOk) { // Certificate was deemed acceptable, so ignore errors and continue ignoreSslErrors(); } else { // Negotiation has failed, disconnect will ocurr emitEvent(Event::EventMessage, i18n("SSL negotiation failed. Connection aborted.")); resetCommandClass(Failed); protoAbort(); } } // ******************************************************************************************* // **************************************** DISCONNECT *************************************** // ******************************************************************************************* void FtpSocket::protoDisconnect() { Socket::protoDisconnect(); // Terminate the connection m_login = false; blockSignals(true); disconnectFromHost(); blockSignals(false); } void FtpSocket::protoAbort() { Socket::protoAbort(); if (getCurrentCommand() != Commands::CmdNone) { // Abort current command if (getCurrentCommand() == Commands::CmdConnect) protoDisconnect(); if (m_cmdData) resetCommandClass(UserAbort); emitEvent(Event::EventMessage, i18n("Aborted.")); } } // ******************************************************************************************* // ********************************* NEGOTIATE DATA CONNECTION ******************************* // ******************************************************************************************* class FtpCommandNegotiateData : public Commands::Base { public: enum State { None, SentSscnOff, SentType, SentProt, SentPret, NegotiateActive, NegotiatePasv, NegotiateEpsv, HaveConnection, SentRest, SentDataCmd, WaitTransfer }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandNegotiateData, FtpSocket, CmdNone) void process() { switch (currentState) { case None: { if (socket()->getConfig("sscn.activated")) { // First disable SSCN currentState = SentSscnOff; socket()->sendCommand("SSCN OFF"); return; } } case SentSscnOff: { if (currentState == SentSscnOff) socket()->setConfig("sscn.activated", false); // Change type currentState = SentType; socket()->resetTransferStart(); QString type = "TYPE "; type.append(socket()->getConfig("params.data_type", 'I')); socket()->sendCommand(type); break; } case SentType: { if (socket()->getConfig("ssl") && socket()->getConfig("ssl.prot_mode") == 1) { currentState = SentProt; if (socket()->getPreviousCommand() == Commands::CmdList) socket()->sendCommand("PROT P"); else socket()->sendCommand("PROT C"); } else if (socket()->getConfig("feat.pret")) { currentState = SentPret; socket()->sendCommand("PRET " + socket()->getConfig("params.data_command")); } else { negotiateDataConnection(); } break; } case SentProt: { if (socket()->getConfig("feat.pret")) { currentState = SentPret; socket()->sendCommand("PRET " + socket()->getConfig("params.data_command")); } else { negotiateDataConnection(); } break; } case SentPret: { // PRET failed because of filesystem problems, abort right away! if (socket()->isResponse("530")) { socket()->emitError(PermissionDenied); socket()->resetCommandClass(Failed); return; } else if (socket()->isResponse("550")) { socket()->emitError(FileNotFound); socket()->resetCommandClass(Failed); return; } else if (socket()->isResponse("5")) { // PRET is not supported, disable for future use socket()->setConfig("feat.pret", false); } negotiateDataConnection(); break; } case NegotiateActive: negotiateActive(); break; case NegotiateEpsv: negotiateEpsv(); break; case NegotiatePasv: negotiatePasv(); break; case HaveConnection: { // We have the connection if (socket()->getConfig("params.data_rest_do")) { currentState = SentRest; socket()->sendCommand("REST " + QString::number(socket()->getConfig("params.data_rest"))); } else { currentState = SentDataCmd; socket()->sendCommand(socket()->getConfig("params.data_command")); } break; } case SentRest: { if (!socket()->isResponse("2") && !socket()->isResponse("3")) { socket()->setConfig("feat.rest", false); socket()->getTransferFile()->close(); bool ok; if (socket()->getPreviousCommand() == Commands::CmdGet) ok = socket()->getTransferFile()->open(QIODevice::WriteOnly | QIODevice::Truncate); else ok = socket()->getTransferFile()->open(QIODevice::ReadOnly); // Check if there was a problem opening the file if (!ok) { socket()->emitError(FileOpenFailed); socket()->resetCommandClass(Failed); return; } } // We have sent REST, now send the data command currentState = SentDataCmd; socket()->sendCommand(socket()->getConfig("params.data_command")); break; } case SentDataCmd: { if (!socket()->isResponse("1")) { // Some problems while executing the data command socket()->resetCommandClass(Failed); return; } if (!socket()->isMultiline()) { socket()->checkTransferStart(); currentState = WaitTransfer; } break; } case WaitTransfer: { if (!socket()->isResponse("2")) { // Transfer has failed socket()->resetCommandClass(Failed); return; } if (!socket()->isMultiline()) { // Transfer has been completed socket()->checkTransferEnd(); } break; } } } void negotiateDataConnection() { if (socket()->getConfig("feat.epsv")) { negotiateEpsv(); } else if (socket()->getConfig("feat.pasv")) { negotiatePasv(); } else { negotiateActive(); } } void negotiateEpsv() { if (currentState == NegotiateEpsv) { if (!socket()->isResponse("2")) { // Negotiation failed socket()->setConfig("feat.epsv", false); // Try the next thing negotiateDataConnection(); return; } // 229 Entering Extended Passive Mode (|||55016|) QString response = socket()->getResponse(); int leftPos = response.lastIndexOf("(|||"); int rightPos = response.lastIndexOf("|)"); int port = response.mid(leftPos + 4, rightPos - leftPos - 4).toInt(); if (!port) { // Unable to parse, try the next thing socket()->setConfig("feat.epsv", false); negotiateDataConnection(); return; } // We have the address, let's setup the transfer socket and then // we are done. currentState = HaveConnection; socket()->setupPassiveTransferSocket(QString::null, port); } else { // Just send the EPSV command currentState = NegotiateEpsv; socket()->sendCommand("EPSV"); } } void negotiatePasv() { if (currentState == NegotiatePasv) { if (!socket()->isResponse("2")) { // Negotiation failed socket()->setConfig("feat.pasv", false); // Try the next thing negotiateDataConnection(); return; } // Ok PASV command successfull - let's parse the result int ip[6]; const char *begin = strchr(socket()->getResponse().toAscii(), '('); // Some stinky servers don't respect RFC and do it on their own if (!begin) begin = strchr(socket()->getResponse().toAscii(), '='); if (!begin || (sscanf(begin, "(%d,%d,%d,%d,%d,%d)",&ip[0], &ip[1], &ip[2], &ip[3], &ip[4], &ip[5]) != 6 && sscanf(begin, "=%d,%d,%d,%d,%d,%d",&ip[0], &ip[1], &ip[2], &ip[3], &ip[4], &ip[5]) != 6)) { // Unable to parse, try the next thing socket()->setConfig("feat.pasv", false); negotiateDataConnection(); return; } // Convert to string QString host; int port; host.sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); port = ip[4] << 8 | ip[5]; // If the reported IP address is from a private IP range, this might be because the // remote server is not properly configured. So we just use the server's real IP instead // of the one we got (if the host is really local, then this should work as well). if (!socket()->getConfig("feat.pret")) { if (host.startsWith("192.168.") || host.startsWith("10.") || host.startsWith("172.16.")) host = socket()->peerAddress().toString(); } // We have the address, let's setup the transfer socket and then // we are done. currentState = HaveConnection; socket()->setupPassiveTransferSocket(host, port); } else { // Just send the PASV command currentState = NegotiatePasv; socket()->sendCommand("PASV"); } } void negotiateActive() { if (currentState == NegotiateActive) { if (!socket()->isResponse("2")) { if (socket()->getConfig("feat.eprt")) { socket()->setConfig("feat.eprt", false); } else { // Negotiation failed, reset since active is the last fallback socket()->resetCommandClass(Failed); return; } } else { currentState = HaveConnection; socket()->nextCommandAsync(); return; } } // Setup the socket and set the apropriate port command currentState = NegotiateActive; SocketAddress address = socket()->setupActiveTransferSocket(); if (!address.ip.isNull()) { if (socket()->getConfig("feat.eprt")) { int ianaFamily = address.ip.protocol() == QSslSocket::IPv4Protocol ? 1 : 2; socket()->sendCommand(QString("EPRT |%1|%2|%3").arg(ianaFamily).arg(address.ip.toString()).arg(address.port)); } else if (address.ip.protocol() == QSslSocket::IPv4Protocol) { QString format = address.ip.toString().replace(".", ","); format.append(","); format.append(QString::number((unsigned char) (address.port & 0xff00) >> 8)); format.append(","); format.append(QString::number((unsigned char) (address.port & 0xff))); socket()->sendCommand("PORT " + format); } else { socket()->emitEvent(Event::EventMessage, i18n("Incompatible address family for PORT, but EPRT not supported, aborting.")); socket()->resetCommandClass(Failed); } } } }; void FtpSocket::initializeTransferSocket() { connect(m_transferSocket, SIGNAL(connected()), this, SLOT(slotDataConnected())); connect(m_transferSocket, SIGNAL(readyRead()), this, SLOT(slotDataTryRead())); connect(m_transferSocket, SIGNAL(disconnected()), this, SLOT(slotDataDisconnected())); connect(m_transferSocket, SIGNAL(bytesWritten(qint64)), this, SLOT(slotDataTryWrite())); connect(m_transferSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotDataError(QAbstractSocket::SocketError))); // Set SSL parameters m_transferSocket->setProtocol(QSslSocket::protocol()); m_transferEnd = 0; m_transferBytes = 0; m_transferBufferSize = 4096; m_transferBuffer = (char*) malloc(m_transferBufferSize); m_speedLastTime = time(0); m_speedLastBytes = 0; // Setup the speed limiter switch (getPreviousCommand()) { case Commands::CmdGet: SpeedLimiter::self()->append(this, SpeedLimiter::Download); break; case Commands::CmdPut: SpeedLimiter::self()->append(this, SpeedLimiter::Upload); break; default: break; } } void FtpSocket::setupPassiveTransferSocket(const QString &host, int port) { // Use the host from control connection if empty QString realHost = host; if (host.isEmpty() || getConfig("pasv.use_site_ip")) realHost = peerAddress().toString(); // Let's connect emitEvent(Event::EventMessage, i18n("Establishing data connection with %1:%2...",realHost,port)); if (!m_transferSocket) m_transferSocket = new QSslSocket(); initializeTransferSocket(); m_transferSocket->connectToHost(realHost, port); } SocketAddress FtpSocket::setupActiveTransferSocket() { if (!m_serverSocket) { m_serverSocket = new SslServer(); m_serverSocket->setProxy(KSocketFactory::proxyForListening("ftp")); } connect(m_serverSocket, SIGNAL(newConnection()), this, SLOT(slotDataAccept())); if (KFTPCore::Config::activeForcePort()) { // Bind only to ports in a specified portrange bool found = false; unsigned int max = KFTPCore::Config::activeMaxPort(); unsigned int min = KFTPCore::Config::activeMinPort(); for (unsigned int port = min + rand() % (max - min + 1); port <= max; port++) { found = m_serverSocket->listen(QHostAddress::Any, port); if (found) break; m_serverSocket->close(); } if (!found) { emitEvent(Event::EventMessage, i18n("Unable to establish a listening socket.")); resetCommandClass(Failed); return SocketAddress(); } } else { if (!m_serverSocket->listen()) { emitEvent(Event::EventMessage, i18n("Unable to establish a listening socket.")); resetCommandClass(Failed); return SocketAddress(); } } QHostAddress serverAddr = m_serverSocket->serverAddress(); QHostAddress controlAddr = localAddress(); SocketAddress request; if (KFTPCore::Config::portForceIp() && !getConfig("active.no_force_ip")) { QString remoteIp = peerAddress().toString(); if (KFTPCore::Config::ignoreExternalIpForLan() && (remoteIp.startsWith("192.168.") || remoteIp.startsWith("10.") || remoteIp.startsWith("172.16."))) { request.ip = controlAddr; } else { // Force a specified IP/hostname to be used in PORT QHostInfo resolver = QHostInfo::fromName(KFTPCore::Config::portIp()); if (!resolver.addresses().isEmpty()) { request.ip = resolver.addresses().first(); } else { request.ip = controlAddr; } } } else { request.ip = controlAddr; } // Set the proper port request.port = m_serverSocket->serverPort(); emitEvent(Event::EventMessage, i18n("Waiting for data connection on port %1...",request.port)); return request; } void FtpSocket::slotDataAccept() { m_transferSocket = m_serverSocket->nextPendingConnection(); initializeTransferSocket(); // Socket has been accepted so the server is not needed anymore m_serverSocket->deleteLater(); m_serverSocket = 0; emitEvent(Event::EventMessage, i18n("Data connection established.")); checkTransferStart(); } void FtpSocket::closeDataTransferSocket() { // Free the buffer and invalidate the socket if (!m_transferBuffer) return; free(m_transferBuffer); m_transferBuffer = 0; m_transferSocket->close(); m_transferSocket->deleteLater(); m_transferSocket = 0; m_transferBytes = 0; SpeedLimiter::self()->remove(this); } void FtpSocket::transferCompleted() { // Transfer has been completed, cleanup closeDataTransferSocket(); checkTransferEnd(); } void FtpSocket::checkTransferStart() { if (++m_transferStart >= 2) { // Setup SSL data connection if (getConfig("ssl") && (getConfig("ssl.prot_mode") == 0 || (getConfig("ssl.prot_mode") == 1 && getToplevelCommand() == Commands::CmdList))) { // Connect to notification events and proceed with SSL negotiation connect(m_transferSocket, SIGNAL(encrypted()), this, SLOT(slotDataSslNegotiated())); m_transferSocket->ignoreSslErrors(); m_transferSocket->startClientEncryption(); return; } if (getToplevelCommand() == Commands::CmdPut) slotDataTryWrite(); } } void FtpSocket::slotDataSslNegotiated() { disconnect(m_transferSocket, SIGNAL(encrypted()), this, SLOT(slotDataSslNegotiated())); emitEvent(Event::EventMessage, i18n("Data channel secured with %1 bit SSL.", m_transferSocket->sessionCipher().usedBits())); if (getToplevelCommand() == Commands::CmdPut) slotDataTryWrite(); } void FtpSocket::slotDataError(QAbstractSocket::SocketError error) { if (error == QAbstractSocket::RemoteHostClosedError) return; emitEvent(Event::EventMessage, i18n("Failed to establish a data connection (%1.)", errorString())); resetCommandClass(Failed); } void FtpSocket::checkTransferEnd() { if (++m_transferEnd >= 2) { emitEvent(Event::EventMessage, i18n("Transfer completed.")); resetCommandClass(); } } void FtpSocket::slotDataConnected() { emitEvent(Event::EventMessage, i18n("Data connection established.")); checkTransferStart(); nextCommand(); } void FtpSocket::slotDataDisconnected() { emitEvent(Event::EventMessage, i18n("Data connection closed.")); transferCompleted(); } void FtpSocket::variableBufferUpdate(int size) { if (size > m_transferBufferSize - 64) { if (m_transferBufferSize + 512 <= 32768) { m_transferBufferSize += 512; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); } } else if (size < m_transferBufferSize - 65) { if (m_transferBufferSize - 512 >= 4096) { m_transferBufferSize -= 512; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); } } } void FtpSocket::slotDataTryWrite() { bool updateVariableBuffer = true; // Enforce speed limits if (allowedBytes() > -1) { m_transferBufferSize = allowedBytes(); if (m_transferBufferSize > 32768) m_transferBufferSize = 32768; else if (m_transferBufferSize == 0) return; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); updateVariableBuffer = false; } else if (m_transferBufferSize == 0) { m_transferBufferSize = 4096; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); } if (!getTransferFile()->isOpen()) return; // If there is nothing to upload, just close the connection right away if (getTransferFile()->size() == 0) { transferCompleted(); return; } qint64 tmpOffset = getTransferFile()->pos(); qint64 readSize = getTransferFile()->read(m_transferBuffer, m_transferBufferSize); qint64 size = m_transferSocket->write(m_transferBuffer, readSize); if (size < 0) { getTransferFile()->seek(tmpOffset); return; } else if (size < readSize) { getTransferFile()->seek(tmpOffset + size); } m_transferBytes += size; updateUsage(size); timeoutPing(); if (getTransferFile()->atEnd()) { // We have reached the end of file, so we should terminate the connection transferCompleted(); return; } if (updateVariableBuffer) variableBufferUpdate(size); } void FtpSocket::slotDataTryRead() { bool updateVariableBuffer = true; // Enforce speed limits if (allowedBytes() > -1) { m_transferBufferSize = allowedBytes(); if (m_transferBufferSize > 32768) m_transferBufferSize = 32768; else if (m_transferBufferSize == 0) return; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); updateVariableBuffer = false; } else if (m_transferBufferSize == 0) { m_transferBufferSize = 4096; m_transferBuffer = (char*) realloc(m_transferBuffer, m_transferBufferSize); } qint64 size = m_transferSocket->read(m_transferBuffer, m_transferBufferSize); if (size <= 0) { transferCompleted(); return; } updateUsage(size); timeoutPing(); switch (getPreviousCommand()) { case Commands::CmdList: { // Feed the data to the directory listing parser if (m_directoryParser) m_directoryParser->addData(m_transferBuffer, size); break; } case Commands::CmdGet: { // Write to file getTransferFile()->write(m_transferBuffer, size); m_transferBytes += size; break; } default: { qDebug("WARNING: slotDataReadActivity called for an invalid command (%d)!", getPreviousCommand()); return; } } if (updateVariableBuffer) variableBufferUpdate(size); } // ******************************************************************************************* // ******************************************* LIST ****************************************** // ******************************************************************************************* class FtpCommandList : public Commands::Base { public: enum State { None, SentCwd, SentStat, WaitList }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandList, FtpSocket, CmdList) QString path; void process() { switch (currentState) { case None: { path = socket()->getConfig("params.list.path"); if (socket()->isChained()) socket()->m_lastDirectoryListing = DirectoryListing(); // Change working directory currentState = SentCwd; socket()->changeWorkingDirectory(path); break; } case SentCwd: { if (!socket()->returnValue()) { // Change working directory has failed and we have to be silent (=error reporting is off) socket()->resetCommandClass(); return; } // Check the directory listing cache DirectoryListing cached = Cache::self()->findCached(socket(), socket()->getCurrentDirectory()); if (cached.isValid()) { socket()->emitEvent(Event::EventMessage, i18n("Using cached directory listing.")); if (socket()->isChained()) { // We don't emit an event, because this list has been called from another // command. Just save the listing. socket()->m_lastDirectoryListing = cached; } else socket()->emitEvent(Event::EventDirectoryListing, cached); socket()->resetCommandClass(); return; } socket()->m_directoryParser = new FtpDirectoryParser(socket()); // Support for faster stat directory listings over the control connection if (socket()->getConfig("feat.stat")) { currentState = SentStat; socket()->sendCommand("STAT ."); return; } // First we have to initialize the data connection, another class will // do this for us, so we just add it to the command chain socket()->setConfig("params.data_rest_do", 0); socket()->setConfig("params.data_type", 'A'); if (socket()->getConfig("feat.mlsd")) socket()->setConfig("params.data_command", "MLSD"); else socket()->setConfig("params.data_command", "LIST -a"); currentState = WaitList; chainCommandClass(FtpCommandNegotiateData); break; } case SentStat: { if (!socket()->isResponse("2")) { // The server doesn't support STAT, disable it and fallback socket()->setConfig("feat.stat", false); socket()->setConfig("params.data_rest_do", 0); socket()->setConfig("params.data_type", 'A'); if (socket()->getConfig("feat.mlsd")) socket()->setConfig("params.data_command", "MLSD"); else socket()->setConfig("params.data_command", "LIST -a"); currentState = WaitList; chainCommandClass(FtpCommandNegotiateData); return; } else if (socket()->isMultiline()) { // Some servers put the response code into the multiline reply QString response = socket()->getResponse(); if (response.left(3) == "211") response = response.mid(4); socket()->m_directoryParser->addDataLine(response); return; } // If we are done, just go on and emit the listing } case WaitList: { // List has been received if (socket()->isChained()) { // We don't emit an event, because this list has been called from another // command. Just save the listing. socket()->m_lastDirectoryListing = socket()->m_directoryParser->getListing(); } else { socket()->emitEvent(Event::EventDirectoryListing, socket()->m_directoryParser->getListing()); } // Cache the directory listing Cache::self()->addDirectory(socket(), socket()->m_directoryParser->getListing()); delete socket()->m_directoryParser; socket()->m_directoryParser = 0; socket()->resetCommandClass(); break; } } } }; void FtpSocket::protoList(const KUrl &path) { emitEvent(Event::EventState, i18n("Fetching directory listing...")); emitEvent(Event::EventMessage, i18n("Fetching directory listing...")); // Set the directory that should be listed setConfig("params.list.path", path.path()); activateCommandClass(FtpCommandList); } // ******************************************************************************************* // ******************************************* GET ******************************************* // ******************************************************************************************* class FtpCommandGet : public Commands::Base { public: enum State { None, SentCwd, SentMdtm, StatDone, DestChecked, WaitTransfer }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandGet, FtpSocket, CmdGet) KUrl sourceFile; KUrl destinationFile; time_t modificationTime; void process() { switch (currentState) { case None: { modificationTime = 0; sourceFile.setPath(socket()->getConfig("params.get.source")); destinationFile.setPath(socket()->getConfig("params.get.destination")); // Attempt to CWD to the parent directory currentState = SentCwd; socket()->changeWorkingDirectory(sourceFile.directory()); break; } case SentCwd: { // Send MDTM if (socket()->getConfig("feat.mdtm")) { currentState = SentMdtm; socket()->sendCommand("MDTM " + sourceFile.path()); break; } else { // Don't break so we will get on to checking for file existance } } case SentMdtm: { if (currentState == SentMdtm) { if (socket()->isResponse("550")) { // The file probably doesn't exist, just ignore it } else if (!socket()->isResponse("213")) { socket()->setConfig("feat.mdtm", false); } else { // Parse MDTM response struct tm dt = {0,0,0,0,0,0,0,0,0,0,0}; QString tmp(socket()->getResponse()); tmp.remove(0, 4); dt.tm_year = tmp.left(4).toInt() - 1900; dt.tm_mon = tmp.mid(4, 2).toInt() - 1; dt.tm_mday = tmp.mid(6, 2).toInt(); dt.tm_hour = tmp.mid(8, 2).toInt(); dt.tm_min = tmp.mid(10, 2).toInt(); dt.tm_sec = tmp.mid(12, 2).toInt(); modificationTime = mktime(&dt); } } // Check if the local file exists and stat the remote file if so if (QDir::root().exists(destinationFile.path())) { socket()->protoStat(sourceFile); currentState = StatDone; return; } else { KStandardDirs::makeDir(destinationFile.directory()); // Don't break so we will get on to initiating the data connection } } case StatDone: { if (currentState == StatDone) { DirectoryListing list; list.addEntry(socket()->getStatResponse()); currentState = DestChecked; socket()->emitEvent(Event::EventFileExists, list); return; } } case DestChecked: { socket()->setConfig("params.data_rest_do", 0); if (isWakeup()) { // We have been waken up because a decision has been made FileExistsWakeupEvent *event = static_cast(m_wakeupEvent); if (!socket()->getConfig("feat.rest") && event->action == FileExistsWakeupEvent::Resume) event->action = FileExistsWakeupEvent::Overwrite; switch (event->action) { case FileExistsWakeupEvent::Rename: { // Change the destination filename, otherwise it is the same as overwrite destinationFile.setPath(event->newFileName); } case FileExistsWakeupEvent::Overwrite: { socket()->getTransferFile()->setFileName(destinationFile.path()); socket()->getTransferFile()->open(QIODevice::WriteOnly | QIODevice::Truncate); if (socket()->getConfig("feat.rest")) { socket()->setConfig("params.data_rest_do", true); socket()->setConfig("params.data_rest", 0); } break; } case FileExistsWakeupEvent::Resume: { socket()->getTransferFile()->setFileName(destinationFile.path()); socket()->getTransferFile()->open(QIODevice::WriteOnly | QIODevice::Append); // Signal resume socket()->emitEvent(Event::EventResumeOffset, socket()->getTransferFile()->size()); socket()->setConfig("params.data_rest_do", true); socket()->setConfig("params.data_rest", (filesize_t) socket()->getTransferFile()->size()); break; } case FileExistsWakeupEvent::Skip: { // Transfer should be aborted socket()->emitEvent(Event::EventTransferComplete); socket()->resetCommandClass(); return; } } } else { // The file doesn't exist so we are free to overwrite socket()->getTransferFile()->setFileName(destinationFile.path()); socket()->getTransferFile()->open(QIODevice::WriteOnly | QIODevice::Truncate); } // Check if there was a problem opening the file if (!socket()->getTransferFile()->isOpen()) { socket()->emitError(FileOpenFailed); socket()->resetCommandClass(Failed); return; } // First we have to initialize the data connection, another class will // do this for us, so we just add it to the command chain socket()->setConfig("params.data_type", KFTPCore::Config::self()->ftpMode(sourceFile.path())); socket()->setConfig("params.data_command", "RETR " + sourceFile.fileName()); currentState = WaitTransfer; chainCommandClass(FtpCommandNegotiateData); break; } case WaitTransfer: { // Transfer has been completed socket()->getTransferFile()->close(); if (modificationTime != 0) { // Use the modification time we got from MDTM utimbuf tmp; tmp.actime = time(0); tmp.modtime = modificationTime; utime(destinationFile.path().toAscii(), &tmp); } socket()->emitEvent(Event::EventTransferComplete); socket()->emitEvent(Event::EventReloadNeeded); socket()->resetCommandClass(); break; } } } }; void FtpSocket::protoGet(const KUrl &source, const KUrl &destination) { emitEvent(Event::EventState, i18n("Transferring...")); emitEvent(Event::EventMessage, i18n("Downloading file '%1'...",source.fileName())); // Set the source and destination setConfig("params.get.source", source.path()); setConfig("params.get.destination", destination.path()); activateCommandClass(FtpCommandGet); } // ******************************************************************************************* // ******************************************* CWD ******************************************* // ******************************************************************************************* class FtpCommandCwd : public Commands::Base { public: enum State { None, SentCwd, SentPwd, SentMkd, SentCwdEnd }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandCwd, FtpSocket, CmdNone) QString targetDirectory; QString currentPathPart; QString cached; int currentPart; int numParts; bool shouldCreate; void process() { switch (currentState) { case None: { socket()->setReturnValue(true); targetDirectory = socket()->getConfig("params.cwd.path"); // If we are already there, no need to CWD if (socket()->getCurrentDirectory() == targetDirectory) { socket()->resetCommandClass(); return; } cached = Cache::self()->findCachedPath(socket(), targetDirectory); if (!cached.isEmpty()) { if (socket()->getCurrentDirectory() == cached) { // We are already there socket()->resetCommandClass(); return; } } // First check the toplevel directory and if it exists we are done currentState = SentCwd; currentPart = 0; numParts = targetDirectory.count('/'); shouldCreate = socket()->getConfig("params.cwd.create"); socket()->sendCommand("CWD " + targetDirectory); break; } case SentCwd: { if (socket()->isMultiline()) return; if (socket()->isResponse("250") && currentPart == 0) { if (!cached.isEmpty()) { socket()->setCurrentDirectory(cached); socket()->resetCommandClass(); } else { // Directory exists, check where we are currentState = SentPwd; socket()->sendCommand("PWD"); } } else { // Changing the working directory has failed if (shouldCreate) { currentPathPart = targetDirectory.section('/', 0, ++currentPart); currentState = SentMkd; socket()->sendCommand("MKD " + currentPathPart); } else if (socket()->errorReporting()) { socket()->emitError(socket()->getPreviousCommand() == Commands::CmdList ? ListFailed : FileNotFound); socket()->resetCommandClass(Failed); } else { socket()->setReturnValue(false); socket()->resetCommandClass(); } } break; } case SentPwd: { // Parse the current working directory if (socket()->isResponse("2")) { QString tmp = socket()->getResponse(); int first = tmp.indexOf('"') + 1; tmp = tmp.mid(first, tmp.lastIndexOf('"') - first); // Set the current directory and cache it socket()->setCurrentDirectory(tmp); Cache::self()->addPath(socket(), tmp); socket()->resetCommandClass(); } else if (socket()->errorReporting()) { socket()->emitError(socket()->getPreviousCommand() == Commands::CmdList ? ListFailed : FileNotFound); socket()->resetCommandClass(Failed); } else { socket()->setReturnValue(false); socket()->resetCommandClass(); } break; } case SentMkd: { // Invalidate parent cache if (socket()->isResponse("2")) { Cache::self()->invalidateEntry(socket(), KUrl(currentPathPart).directory()); } if (currentPart == numParts) { // We are done, since all directories have been created currentState = SentCwdEnd; socket()->sendCommand("CWD " + targetDirectory); } else { currentPathPart = targetDirectory.section('/', 0, ++currentPart); currentState = SentMkd; socket()->sendCommand("MKD " + currentPathPart); } break; } case SentCwdEnd: { if (socket()->isMultiline()) return; // See where we are and set current working directory currentState = SentPwd; socket()->sendCommand("PWD"); break; } } } }; void FtpSocket::changeWorkingDirectory(const QString &path, bool shouldCreate) { // Set the path to cwd to setConfig("params.cwd.path", path); setConfig("params.cwd.create", shouldCreate); activateCommandClass(FtpCommandCwd); } // ******************************************************************************************* // ******************************************* PUT ******************************************* // ******************************************************************************************* class FtpCommandPut : public Commands::Base { public: enum State { None, WaitCwd, SentSize, StatDone, DestChecked, WaitTransfer }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandPut, FtpSocket, CmdPut) KUrl sourceFile; KUrl destinationFile; bool fetchedSize; filesize_t destinationSize; void cleanup() { // Unclean upload termination, be sure to erase the cached stat infos Cache::self()->invalidateEntry(socket(), destinationFile.directory()); } void process() { switch (currentState) { case None: { sourceFile.setPath(socket()->getConfig("params.get.source")); destinationFile.setPath(socket()->getConfig("params.get.destination")); fetchedSize = false; // Check if the local file exists if (!QDir::root().exists(sourceFile.path())) { socket()->emitError(FileNotFound); socket()->resetCommandClass(Failed); return; } // Change to the current working directory, creating any directories that are // still missing currentState = WaitCwd; socket()->changeWorkingDirectory(destinationFile.directory(), true); break; } case WaitCwd: { // Check if the remote file exists if (socket()->getConfig("feat.size")) { currentState = SentSize; socket()->sendCommand("SIZE " + destinationFile.path()); } else { // SIZE is not available, try stat directly currentState = StatDone; socket()->protoStat(destinationFile); } break; } case SentSize: { if (socket()->isResponse("213")) { destinationSize = socket()->getResponse().mid(4).toULongLong(); fetchedSize = true; // File exists, we have to stat to get more data currentState = StatDone; socket()->protoStat(destinationFile); } else if (socket()->isResponse("500") || socket()->getResponse().contains("Operation not permitted")) { // Yes, some servers don't support the SIZE command :/ socket()->setConfig("feat.size", false); currentState = StatDone; socket()->protoStat(destinationFile); } else { currentState = DestChecked; process(); } break; } case StatDone: { if (!socket()->getStatResponse().filename().isEmpty()) { if (fetchedSize) { if (socket()->getStatResponse().size() != destinationSize) { // It would seem that the size has changed, cached data is invalid Cache::self()->invalidateEntry(socket(), destinationFile.directory()); currentState = StatDone; socket()->protoStat(destinationFile); return; } } // Remote file exists, emit a request for action DirectoryListing list; list.addEntry(socket()->getStatResponse()); currentState = DestChecked; socket()->emitEvent(Event::EventFileExists, list); return; } // Don't break here } case DestChecked: { socket()->setConfig("params.data_rest_do", 0); if (isWakeup()) { // We have been waken up because a decision has been made FileExistsWakeupEvent *event = static_cast(m_wakeupEvent); if (!socket()->getConfig("feat.rest") && event->action == FileExistsWakeupEvent::Resume) event->action = FileExistsWakeupEvent::Overwrite; switch (event->action) { case FileExistsWakeupEvent::Rename: { // Change the destination filename, otherwise it is the same as overwrite destinationFile.setPath(event->newFileName); } case FileExistsWakeupEvent::Overwrite: { socket()->getTransferFile()->setFileName(sourceFile.path()); socket()->getTransferFile()->open(QIODevice::ReadOnly); if (socket()->getConfig("feat.rest")) { socket()->setConfig("params.data_rest_do", true); socket()->setConfig("params.data_rest", 0); } break; } case FileExistsWakeupEvent::Resume: { socket()->getTransferFile()->setFileName(sourceFile.path()); socket()->getTransferFile()->open(QIODevice::ReadOnly); socket()->getTransferFile()->seek(socket()->getStatResponse().size()); // Signal resume socket()->emitEvent(Event::EventResumeOffset, socket()->getStatResponse().size()); socket()->setConfig("params.data_rest_do", true); socket()->setConfig("params.data_rest", (filesize_t) socket()->getStatResponse().size()); break; } case FileExistsWakeupEvent::Skip: { // Transfer should be aborted markClean(); socket()->resetCommandClass(UserAbort); socket()->emitEvent(Event::EventTransferComplete); return; } } } else { // The file doesn't exist so we are free to overwrite socket()->getTransferFile()->setFileName(sourceFile.path()); socket()->getTransferFile()->open(QIODevice::ReadOnly); } // Check if there was a problem opening the file if (!socket()->getTransferFile()->isOpen()) { socket()->emitError(FileOpenFailed); socket()->resetCommandClass(Failed); return; } // First we have to initialize the data connection, another class will // do this for us, so we just add it to the command chain socket()->setConfig("params.data_type", KFTPCore::Config::self()->ftpMode(destinationFile.path())); socket()->setConfig("params.data_command", "STOR " + destinationFile.fileName()); currentState = WaitTransfer; chainCommandClass(FtpCommandNegotiateData); break; } case WaitTransfer: { // Transfer has been completed Cache::self()->updateDirectoryEntry(socket(), destinationFile, socket()->getTransferFile()->size()); socket()->getTransferFile()->close(); markClean(); socket()->emitEvent(Event::EventTransferComplete); socket()->emitEvent(Event::EventReloadNeeded); socket()->resetCommandClass(); break; } } } }; void FtpSocket::protoPut(const KUrl &source, const KUrl &destination) { emitEvent(Event::EventState, i18n("Transferring...")); emitEvent(Event::EventMessage, i18n("Uploading file '%1'...",source.fileName())); // Set the source and destination setConfig("params.get.source", source.path()); setConfig("params.get.destination", destination.path()); activateCommandClass(FtpCommandPut); } // ******************************************************************************************* // **************************************** REMOVE ******************************************* // ******************************************************************************************* class FtpCommandRemove : public Commands::Base { public: enum State { None, SentCwd, SentRemove }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandRemove, FtpSocket, CmdNone) QString destinationPath; QString parentDirectory; void process() { switch (currentState) { case None: { destinationPath = socket()->getConfig("params.remove.path"); parentDirectory = socket()->getConfig("params.remove.parent"); currentState = SentRemove; if (socket()->getConfig("params.remove.directory")) { if (socket()->getCurrentDirectory() != parentDirectory) { // We should change working directory to parent directory before removing currentState = SentCwd; socket()->sendCommand("CWD " + parentDirectory); } else { socket()->sendCommand("RMD " + destinationPath); } } else { socket()->sendCommand("DELE " + destinationPath); } break; } case SentCwd: { if (socket()->isMultiline()) return; if (socket()->isResponse("2")) { // CWD was successful socket()->setCurrentDirectory(parentDirectory); } currentState = SentRemove; socket()->sendCommand("RMD " + destinationPath); break; } case SentRemove: { if (socket()->isMultiline()) return; if (!socket()->isResponse("2")) { socket()->resetCommandClass(Failed); } else { // Invalidate cached parent entry (if any) Cache::self()->invalidateEntry(socket(), parentDirectory); Cache::self()->invalidatePath(socket(), destinationPath); if (!socket()->isChained()) socket()->emitEvent(Event::EventReloadNeeded); socket()->resetCommandClass(); } break; } } } }; void FtpSocket::protoRemove(const KUrl &path) { emitEvent(Event::EventState, i18n("Removing...")); // Set the file to remove setConfig("params.remove.parent", path.directory()); setConfig("params.remove.path", path.path()); activateCommandClass(FtpCommandRemove); } // ******************************************************************************************* // **************************************** RENAME ******************************************* // ******************************************************************************************* class FtpCommandRename : public Commands::Base { public: enum State { None, SentRnfr, SentRnto }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandRename, FtpSocket, CmdRename) QString sourcePath; QString destinationPath; void process() { switch (currentState) { case None: { sourcePath = socket()->getConfig("params.rename.source"); destinationPath = socket()->getConfig("params.rename.destination"); currentState = SentRnfr; socket()->sendCommand("RNFR " + sourcePath); break; } case SentRnfr: { if (socket()->isResponse("3")) { currentState = SentRnto; socket()->sendCommand("RNTO " + destinationPath); } else socket()->resetCommandClass(Failed); break; } case SentRnto: { if (socket()->isResponse("2")) { // Invalidate cached parent entry (if any) Cache::self()->invalidateEntry(socket(), KUrl(sourcePath).directory()); Cache::self()->invalidateEntry(socket(), KUrl(destinationPath).directory()); Cache::self()->invalidatePath(socket(), sourcePath); Cache::self()->invalidatePath(socket(), destinationPath); socket()->emitEvent(Event::EventReloadNeeded); socket()->resetCommandClass(); } else socket()->resetCommandClass(Failed); break; } } } }; void FtpSocket::protoRename(const KUrl &source, const KUrl &destination) { emitEvent(Event::EventState, i18n("Renaming...")); // Set rename options setConfig("params.rename.source", source.path()); setConfig("params.rename.destination", destination.path()); activateCommandClass(FtpCommandRename); } // ******************************************************************************************* // **************************************** CHMOD ******************************************** // ******************************************************************************************* class FtpCommandChmod : public Commands::Base { public: enum State { None, SentChmod }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandChmod, FtpSocket, CmdChmod) void process() { switch (currentState) { case None: { currentState = SentChmod; QString chmod; chmod.sprintf("SITE CHMOD %.3d %s", socket()->getConfig("params.chmod.mode", 0644), socket()->getConfig("params.chmod.path").toAscii().data()); socket()->sendCommand(chmod); break; } case SentChmod: { if (!socket()->isResponse("2")) socket()->resetCommandClass(Failed); else { // Invalidate cached parent entry (if any) Cache::self()->invalidateEntry(socket(), KUrl(socket()->getConfig("params.chmod.path")).directory()); socket()->emitEvent(Event::EventReloadNeeded); socket()->resetCommandClass(); } break; } } } }; void FtpSocket::protoChmodSingle(const KUrl &path, int mode) { emitEvent(Event::EventState, i18n("Changing mode...")); // Set chmod options setConfig("params.chmod.path", path.path()); setConfig("params.chmod.mode", mode); activateCommandClass(FtpCommandChmod); } // ******************************************************************************************* // **************************************** MKDIR ******************************************** // ******************************************************************************************* class FtpCommandMkdir : public Commands::Base { public: enum State { None, SentMkdir }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandMkdir, FtpSocket, CmdMkdir) void process() { switch (currentState) { case None: { currentState = SentMkdir; socket()->changeWorkingDirectory(socket()->getConfig("params.mkdir.path"), true); break; } case SentMkdir: { // Invalidate cached parent entry (if any) Cache::self()->invalidateEntry(socket(), KUrl(socket()->getCurrentDirectory()).directory()); socket()->emitEvent(Event::EventReloadNeeded); socket()->resetCommandClass(); break; } } } }; void FtpSocket::protoMkdir(const KUrl &path) { emitEvent(Event::EventState, i18n("Making directory...")); setConfig("params.mkdir.path", path.path()); activateCommandClass(FtpCommandMkdir); } // ******************************************************************************************* // ******************************************* RAW ******************************************* // ******************************************************************************************* class FtpCommandRaw : public Commands::Base { public: enum State { None, SentRaw }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandRaw, FtpSocket, CmdRaw) QString response; void process() { switch (currentState) { case None: { currentState = SentRaw; socket()->sendCommand(socket()->getConfig("params.raw.command")); break; } case SentRaw: { response.append(socket()->getResponse()); if (!socket()->isMultiline()) { socket()->emitEvent(Event::EventRaw, response); socket()->resetCommandClass(); } break; } } } }; void FtpSocket::protoRaw(const QString &raw) { setConfig("params.raw.command", raw); activateCommandClass(FtpCommandRaw); } // ******************************************************************************************* // ******************************************* FXP ******************************************* // ******************************************************************************************* class FtpCommandFxp : public Commands::Base { public: enum State { None, // Source socket SourceSentCwd, SourceSentStat, SourceDestVerified, SourceSentType, SourceSentSscn, SourceSentProt, SourceWaitType, SourceSentPret, SourceSentPasv, SourceDoRest, SourceSentRest, SourceDoRetr, SourceSentRetr, SourceWaitTransfer, SourceResetProt, // Destination socket DestSentStat, DestWaitCwd, DestDoType, DestSentType, DestSentSscn, DestSentProt, DestDoPort, DestSentPort, DestSentRest, DestDoStor, DestSentStor, DestWaitTransfer, DestResetProt }; enum ProtectionMode { ProtClear = 0, ProtPrivate = 1, ProtSSCN = 2 }; enum TransferMode { TransferPASV = 0, TransferCPSV = 1 }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandFxp, FtpSocket, CmdFxp) FtpSocket *companion; KUrl sourceFile; KUrl destinationFile; filesize_t resumeOffset; void cleanup() { // We have been interrupted, so we have to abort the companion as well if (!socket()->getConfig("params.fxp.abort")) { companion->setConfig("params.fxp.abort", true); companion->protoAbort(); } // Unclean upload termination, be sure to erase the cached stat infos if (!socket()->getConfig("params.fxp.keep_cache")) Cache::self()->invalidateEntry(socket(), destinationFile.directory()); } void process() { switch (currentState) { case None: { sourceFile.setPath(socket()->getConfig("params.fxp.source")); destinationFile.setPath(socket()->getConfig("params.fxp.destination")); socket()->setConfig("params.fxp.keep_cache", false); // Who are we ? Where shall we begin ? if (socket()->getConfig("params.fxp.companion")) { // We are the companion, so we should check the destination socket()->setConfig("params.fxp.companion", false); currentState = DestSentStat; socket()->protoStat(destinationFile); return; } else { socket()->setConfig("params.transfer.mode", TransferPASV); if (socket()->getCurrentDirectory() != sourceFile.directory()) { // Attempt to CWD to the parent directory currentState = SourceSentCwd; socket()->sendCommand("CWD " + sourceFile.directory()); return; } } } // *************************************************************************** // ***************************** Source socket ******************************* // *************************************************************************** case SourceSentCwd: { if (currentState == SourceSentCwd) { if (!socket()->isResponse("250")) { socket()->emitError(FileNotFound); socket()->resetCommandClass(Failed); return; } if (socket()->isMultiline()) return; else socket()->setCurrentDirectory(sourceFile.directory()); } // We are the source socket, let's stat currentState = SourceSentStat; socket()->protoStat(sourceFile); break; } case SourceSentStat: { if (socket()->getStatResponse().filename().isEmpty()) { socket()->emitError(FileNotFound); socket()->resetCommandClass(Failed); } else { // File exists, invoke the companion companion->setConfig("params.fxp.companion", true); companion->Socket::thread()->siteToSite(socket()->Socket::thread(), sourceFile, destinationFile); currentState = SourceDestVerified; } break; } case SourceDestVerified: { if (isWakeup()) { // We have been waken up because a decision has been made FileExistsWakeupEvent *event = static_cast(m_wakeupEvent); if (!socket()->getConfig("feat.rest") && event->action == FileExistsWakeupEvent::Resume) event->action = FileExistsWakeupEvent::Overwrite; switch (event->action) { case FileExistsWakeupEvent::Rename: { // Change the destination filename, otherwise it is the same as overwrite destinationFile.setPath(event->newFileName); } case FileExistsWakeupEvent::Overwrite: { companion->setConfig("params.fxp.rest", 0); resumeOffset = 0; break; } case FileExistsWakeupEvent::Resume: { companion->setConfig("params.fxp.rest", companion->getStatResponse().size()); resumeOffset = companion->getStatResponse().size(); break; } case FileExistsWakeupEvent::Skip: { // Transfer should be aborted companion->setConfig("params.fxp.keep_cache", true); socket()->setConfig("params.fxp.keep_cache", true); socket()->resetCommandClass(UserAbort); socket()->emitEvent(Event::EventTransferComplete); return; } } } else { companion->setConfig("params.fxp.rest", 0); resumeOffset = 0; } // Change type currentState = SourceSentType; QString type = "TYPE "; type.append(KFTPCore::Config::self()->ftpMode(sourceFile.path())); socket()->sendCommand(type); break; } case SourceSentType: { if (socket()->getConfig("ssl") && socket()->getConfig("ssl.prot_mode") != 2 && !socket()->getConfig("sscn.activated")) { if (socket()->getConfig("ssl.prot_mode") == 0) { if (socket()->getConfig("feat.sscn")) { // We support SSCN currentState = SourceSentSscn; socket()->sendCommand("SSCN ON"); companion->setConfig("params.ssl.mode", ProtPrivate); } else if (companion->getConfig("feat.sscn")) { // Companion supports SSCN currentState = SourceWaitType; companion->setConfig("params.ssl.mode", ProtSSCN); companion->nextCommandAsync(); } else if (socket()->getConfig("feat.cpsv")) { // We support CPSV currentState = SourceWaitType; socket()->setConfig("params.transfer.mode", TransferCPSV); companion->setConfig("params.ssl.mode", ProtPrivate); companion->nextCommandAsync(); } else { // Neither support SSCN, can't do SSL transfer socket()->emitEvent(Event::EventMessage, i18n("Neither server supports SSCN/CPSV but SSL data connection requested, aborting transfer.")); socket()->resetCommandClass(Failed); return; } } else { currentState = SourceSentProt; socket()->sendCommand("PROT C"); companion->setConfig("params.ssl.mode", ProtClear); } } else { currentState = SourceWaitType; companion->nextCommandAsync(); } break; } case SourceSentSscn: { if (!socket()->isResponse("2")) { socket()->resetCommandClass(Failed); } else { socket()->setConfig("sscn.activated", true); socket()->setConfig("params.fxp.changed_prot", 0); currentState = SourceWaitType; companion->nextCommandAsync(); } break; } case SourceSentProt: { if (!socket()->isResponse("2")) { socket()->resetCommandClass(Failed); } else { socket()->setConfig("params.fxp.changed_prot", 1); currentState = SourceWaitType; companion->nextCommandAsync(); } break; } case SourceWaitType: { // We are ready to invoke file transfer, do PASV if (socket()->getConfig("feat.pret")) { currentState = SourceSentPret; socket()->sendCommand("PRET RETR " + sourceFile.fileName()); } else { currentState = SourceSentPasv; switch (socket()->getConfig("params.transfer.mode")) { case TransferPASV: socket()->sendCommand("PASV"); break; case TransferCPSV: socket()->sendCommand("CPSV"); break; } } break; } case SourceSentPret: { if (!socket()->isResponse("2")) { if (socket()->isResponse("550")) { socket()->emitError(PermissionDenied); socket()->resetCommandClass(Failed); return; } else if (socket()->isResponse("530")) { socket()->emitError(FileNotFound); socket()->resetCommandClass(Failed); } socket()->setConfig("feat.pret", false); } currentState = SourceSentPasv; switch (socket()->getConfig("params.transfer.mode")) { case TransferPASV: socket()->sendCommand("PASV"); break; case TransferCPSV: socket()->sendCommand("CPSV"); break; } break; } case SourceSentPasv: { // Parse the PASV response and get it to the companion to issue PORT if (!socket()->isResponse("2")) { socket()->resetCommandClass(Failed); } else { QString tmp = socket()->getResponse(); int pos = tmp.indexOf('(') + 1; tmp = tmp.mid(pos, tmp.indexOf(')') - pos); currentState = SourceDoRest; companion->setConfig("params.fxp.ip", tmp); companion->nextCommandAsync(); } break; } case SourceDoRest: { currentState = SourceSentRest; socket()->sendCommand("REST " + QString::number(resumeOffset)); break; } case SourceSentRest: { if (!socket()->isResponse("2") && !socket()->isResponse("3")) { socket()->setConfig("feat.rest", false); companion->setConfig("params.fxp.rest", 0); } else { // Signal resume socket()->emitEvent(Event::EventResumeOffset, resumeOffset); } currentState = SourceDoRetr; companion->nextCommandAsync(); break; } case SourceDoRetr: { currentState = SourceSentRetr; socket()->sendCommand("RETR " + sourceFile.fileName()); break; } case SourceSentRetr: { if (!socket()->isResponse("1")) { socket()->resetCommandClass(Failed); } else { currentState = SourceWaitTransfer; } break; } case SourceWaitTransfer: { if (!socket()->isMultiline()) { // Transfer has been completed if (socket()->getConfig("params.fxp.changed_prot")) { currentState = SourceResetProt; QString prot = "PROT "; if (socket()->getConfig("ssl.prot_mode") == 0) prot.append('P'); else prot.append('C'); socket()->sendCommand(prot); } else { markClean(); socket()->emitEvent(Event::EventMessage, i18n("Transfer completed.")); socket()->emitEvent(Event::EventTransferComplete); socket()->resetCommandClass(); } } break; } case SourceResetProt: { markClean(); socket()->emitEvent(Event::EventMessage, i18n("Transfer completed.")); socket()->emitEvent(Event::EventTransferComplete); socket()->resetCommandClass(); break; } // *************************************************************************** // *************************** Destination socket **************************** // *************************************************************************** case DestSentStat: { if (socket()->getStatResponse().filename().isEmpty()) { // Change the working directory currentState = DestWaitCwd; socket()->changeWorkingDirectory(destinationFile.directory(), true); } else { // The file already exists, request action DirectoryListing list; list.addEntry(companion->getStatResponse()); list.addEntry(socket()->getStatResponse()); currentState = DestDoType; socket()->emitEvent(Event::EventFileExists, list); } break; } case DestWaitCwd: { // Directory has been changed/created, call back the companion currentState = DestDoType; companion->nextCommandAsync(); break; } case DestDoType: { currentState = DestSentType; QString type = "TYPE "; type.append(KFTPCore::Config::self()->ftpMode(sourceFile.path())); socket()->sendCommand(type); break; } case DestSentType: { if (socket()->getConfig("ssl")) { // Check what the source socket has instructed us to do switch (socket()->getConfig("params.ssl.mode")) { case ProtClear: { // We should use cleartext data channel if (socket()->getConfig("ssl.prot_mode") != 2) { currentState = DestSentProt; socket()->sendCommand("PROT C"); } else { currentState = DestDoPort; companion->nextCommandAsync(); } break; } case ProtPrivate: { // We should use private data channel if (socket()->getConfig("ssl.prot_mode") != 0) { currentState = DestSentProt; socket()->sendCommand("PROT P"); } else { currentState = DestDoPort; companion->nextCommandAsync(); } break; } case ProtSSCN: { // We should initialize SSCN mode if (!socket()->getConfig("sscn.activated")) { currentState = DestSentSscn; socket()->sendCommand("SSCN ON"); } else { currentState = DestDoPort; companion->nextCommandAsync(); } break; } } } else { currentState = DestDoPort; companion->nextCommandAsync(); } break; } case DestSentSscn: { if (!socket()->isResponse("2")) { socket()->resetCommandClass(Failed); } else { socket()->setConfig("sscn.activated", true); socket()->setConfig("params.fxp.changed_prot", 0); currentState = DestDoPort; companion->nextCommandAsync(); } break; } case DestSentProt: { if (!socket()->isResponse("2")) { socket()->resetCommandClass(Failed); } else { socket()->setConfig("params.fxp.changed_prot", 1); currentState = DestDoPort; companion->nextCommandAsync(); } break; } case DestDoPort: { currentState = DestSentPort; socket()->sendCommand("PORT " + socket()->getConfig("params.fxp.ip")); break; } case DestSentPort: { if (!socket()->isResponse("2")) { socket()->resetCommandClass(Failed); } else { currentState = DestSentRest; socket()->sendCommand("REST " + socket()->getConfig("params.fxp.rest")); } break; } case DestSentRest: { // We are ready for file transfer currentState = DestDoStor; companion->nextCommandAsync(); break; } case DestDoStor: { currentState = DestSentStor; socket()->sendCommand("STOR " + destinationFile.fileName()); break; } case DestSentStor: { if (!socket()->isResponse("1")) { socket()->resetCommandClass(Failed); } else { currentState = DestWaitTransfer; companion->nextCommandAsync(); } break; } case DestWaitTransfer: { if (!socket()->isMultiline()) { // Transfer has been completed if (socket()->getConfig("params.fxp.changed_prot")) { currentState = DestResetProt; QString prot = "PROT "; if (socket()->getConfig("ssl.prot_mode") == 0) prot.append('P'); else prot.append('C'); socket()->sendCommand(prot); } else { markClean(); socket()->emitEvent(Event::EventMessage, i18n("Transfer completed.")); socket()->emitEvent(Event::EventReloadNeeded); socket()->resetCommandClass(); } } break; } case DestResetProt: { markClean(); socket()->emitEvent(Event::EventMessage, i18n("Transfer completed.")); socket()->emitEvent(Event::EventReloadNeeded); socket()->resetCommandClass(); break; } } } }; void FtpSocket::protoSiteToSite(Socket *socket, const KUrl &source, const KUrl &destination) { emitEvent(Event::EventState, i18n("Transferring...")); emitEvent(Event::EventMessage, i18n("Transferring file '%1'...",source.fileName())); // Set the source and destination setConfig("params.fxp.abort", 0); setConfig("params.fxp.source", source.path()); setConfig("params.fxp.destination", destination.path()); FtpCommandFxp *fxp = new FtpCommandFxp(this); fxp->companion = static_cast(socket); m_cmdData = fxp; m_cmdData->process(); } // ******************************************************************************************* // ******************************************* NOOP ****************************************** // ******************************************************************************************* class FtpCommandKeepAlive : public Commands::Base { public: enum State { None, SentNoop }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandKeepAlive, FtpSocket, CmdKeepAlive) void process() { switch (currentState) { case None: { currentState = SentNoop; socket()->sendCommand("NOOP"); break; } case SentNoop: { socket()->resetCommandClass(); break; } } } }; void FtpSocket::protoKeepAlive() { emitEvent(Event::EventState, i18n("Transmitting keep-alive...")); setCurrentCommand(Commands::CmdKeepAlive); activateCommandClass(FtpCommandKeepAlive); } } #include "ftpsocket.moc" kftpgrabber-0.8.99~svn1214766/src/engine/directorylisting.cpp0000644000175000017500000001110011276037142023532 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "directorylisting.h" #include "misc/filter.h" #include #include #include #include #include using namespace KFTPCore::Filter; using namespace KIO; namespace KFTPEngine { DirectoryEntry::DirectoryEntry() { } KIO::UDSEntry DirectoryEntry::toUdsEntry() const { bool directory = m_type == 'd'; UDSEntry entry; entry.insert(UDSEntry::UDS_NAME, m_filename); entry.insert(UDSEntry::UDS_SIZE, m_size); entry.insert(UDSEntry::UDS_MODIFICATION_TIME, m_time); entry.insert(UDSEntry::UDS_USER, m_owner); entry.insert(UDSEntry::UDS_GROUP, m_group); entry.insert(UDSEntry::UDS_ACCESS, m_permissions); if (!m_link.isEmpty()) { entry.insert(UDSEntry::UDS_LINK_DEST, m_link); KMimeType::Ptr mime = KMimeType::findByUrl(KUrl("ftp://host/" + m_filename)); if (mime->name() == KMimeType::defaultMimeType()) { entry.insert(UDSEntry::UDS_GUESSED_MIME_TYPE, QString("inode/directory")); directory = true; } } entry.insert(UDSEntry::UDS_FILE_TYPE, directory ? S_IFDIR : S_IFREG); return entry; } QString DirectoryEntry::timeAsString() { QDateTime dt; dt.setTime_t(time()); return KGlobal::locale()->formatDateTime(dt); } bool DirectoryEntry::operator<(const DirectoryEntry &entry) const { const Action *firstAction = Filters::self()->process(*this, Action::Priority); const Action *secondAction = Filters::self()->process(entry, Action::Priority); int priorityFirst = firstAction ? firstAction->value().toInt() : 0; int prioritySecond = secondAction ? secondAction->value().toInt() : 0; if (priorityFirst == prioritySecond) { if (isDirectory() != entry.isDirectory()) return isDirectory(); return m_filename < entry.m_filename; } return priorityFirst > prioritySecond; } DirectoryTree::DirectoryTree(DirectoryEntry entry) : m_entry(entry) { } DirectoryTree::~DirectoryTree() { // Free all allocated subtrees foreach (DirectoryTree *dir, m_directories) { delete dir; } } void DirectoryTree::addFile(DirectoryEntry entry) { m_files.append(entry); } DirectoryTree *DirectoryTree::addDirectory(DirectoryEntry entry) { DirectoryTree *tree = new DirectoryTree(entry); m_directories.append(tree); return tree; } DirectoryListing::DirectoryListing(const KUrl &path) : m_valid(true), m_path(path) { } DirectoryListing::~DirectoryListing() { m_list.clear(); } void DirectoryListing::addEntry(DirectoryEntry entry) { m_list.append(entry); } void DirectoryListing::updateEntry(const QString &filename, ::filesize_t size) { QList::iterator listEnd = m_list.end(); for (QList::Iterator i = m_list.begin(); i != listEnd; i++) { if ((*i).filename() == filename) { (*i).setSize(size); return; } } // Entry not found, add one DirectoryEntry entry; entry.setFilename(filename); entry.setSize(size); addEntry(entry); } } kftpgrabber-0.8.99~svn1214766/src/engine/event.h0000644000175000017500000001423311276037142020734 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPNETWORKEVENT_H #define KFTPNETWORKEVENT_H #include #include #include #include "directorylisting.h" namespace KFTPEngine { /** * Engine reset codes. TODO description of each reset code. */ enum ResetCode { Ok, UserAbort, Failed, FailedSilently }; /** * Engine error codes. TODO: description of each error code. */ enum ErrorCode { ConnectFailed, LoginFailed, PermissionDenied, FileNotFound, OperationFailed, ListFailed, FileOpenFailed }; /** * A wakeup event is a special type event used to transfer some response from * the GUI to the engine that has been temporarly suspended. After receiving * this event, the current command handler's wakeup() method will be called * with this event as a parameter. * * @author Jernej Kos */ class WakeupEvent { public: /** * Possible wakeup event types. Each type should subclass this class to * provide any custom methods needed. */ enum Type { WakeupFileExists, WakeupPubkey, WakeupPeerVerify }; /** * Constructs a new wakeup event of specified type. * * @param type Event type */ WakeupEvent(Type type) : m_type(type) {} private: Type m_type; }; /** * A file exists wakeup event that is used to continue pending transfers. * * @author Jernej Kos */ class FileExistsWakeupEvent : public WakeupEvent { public: /** * Possible actions the engine can take. */ enum Action { Overwrite, Rename, Resume, Skip }; /** * Constructs a new file exists wakeup event with Skip action as default. */ FileExistsWakeupEvent() : WakeupEvent(WakeupFileExists), action(Skip) {} Action action; QString newFileName; }; /** * A public key password response event for SFTP connections. * * @author Jernej Kos */ class PubkeyWakeupEvent : public WakeupEvent { public: /** * Constructs a new public key wakeup event. */ PubkeyWakeupEvent() : WakeupEvent(WakeupPubkey) {} QString password; }; /** * A peer verification response event for FTPS and SFTP connections. * * @author Jernej Kos */ class PeerVerifyWakeupEvent : public WakeupEvent { public: /** * Constructs a new peer verify wakeup event. */ PeerVerifyWakeupEvent() : WakeupEvent(WakeupPeerVerify) {} bool peerOk; }; /** * This class represents an event that is passed to the EventHandler for * processing. It can have multiple EventParameters. * * @author Jernej Kos */ class Event : public QEvent { public: enum Type { EventMessage, EventCommand, EventResponse, EventMultiline, EventRaw, EventDirectoryListing, EventDisconnect, EventError, EventConnect, EventReady, EventState, EventScanComplete, EventRetrySuccess, EventReloadNeeded, // Transfer events EventTransferComplete, EventResumeOffset, // Events that require wakeup events EventFileExists, EventPubkeyPassword, EventPeerVerify }; /** * Construct a new event with a parameter list. * * @param params Parameter list */ Event(Type type, QList params); ~Event(); /** * Return the event's type. * * @return Event's type */ Type type() { return m_type; } /** * Returns the parameter with a specific index. * * @param index Parameter's index * @return A parameter as QVariant */ QVariant getParameter(int index) { return m_params[index]; } protected: Type m_type; QList m_params; }; class Thread; /** * This class handles events receieved from the thread and passes them * on to the GUI as normal Qt signals. * * @author Jernej Kos */ class EventHandler : public QObject { Q_OBJECT public: /** * Construct a new event handler. * * @param thread The thread this event handler belongs to */ EventHandler(Thread *thread); protected: void customEvent(QEvent *e); protected: Thread *m_thread; signals: void engineEvent(KFTPEngine::Event *event); void connected(); void disconnected(); void gotResponse(const QString &text); void gotRawResponse(const QString &text); }; } Q_DECLARE_METATYPE(KFTPEngine::WakeupEvent*) Q_DECLARE_METATYPE(KFTPEngine::ErrorCode) #endif kftpgrabber-0.8.99~svn1214766/src/engine/connectionretry.h0000644000175000017500000000506311276037142023041 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPENGINECONNECTIONRETRY_H #define KFTPENGINECONNECTIONRETRY_H #include #include namespace KFTPEngine { class Socket; class Event; /** * This class will retry to reconnect to the currently set URL for the * socket specified in constructor. * * @author Jernej Kos */ class ConnectionRetry : public QObject { Q_OBJECT public: /** * Constructs a new ConnectionRetry class instance. */ ConnectionRetry(Socket *socket); /** * Start the reconnect cycle. */ void startRetry(); /** * Abort the running reconnect cycle and schedule this object's * destruction. */ void abortRetry(); private: Socket *m_socket; int m_delay; int m_max; int m_iteration; QTimer *m_timer; private slots: void slotShouldRetry(); void slotEngineEvent(KFTPEngine::Event *event); }; } #endif kftpgrabber-0.8.99~svn1214766/src/engine/cache.cpp0000644000175000017500000001033411276037142021207 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "cache.h" #include "socket.h" #include namespace KFTPEngine { class CachePrivate { public: Cache instance; }; K_GLOBAL_STATIC(CachePrivate, cachePrivate) Cache *Cache::self() { return &cachePrivate->instance; } Cache::Cache() { } Cache::~Cache() { } void Cache::addDirectory(KUrl &url, DirectoryListing listing) { url.adjustPath(KUrl::RemoveTrailingSlash); m_listingCache[url] = listing; } void Cache::addDirectory(Socket *socket, DirectoryListing listing) { KUrl url = socket->getCurrentUrl(); url.setPath(socket->getCurrentDirectory()); addDirectory(url, listing); } void Cache::updateDirectoryEntry(Socket *socket, KUrl &path, filesize_t filesize) { KUrl url = socket->getCurrentUrl(); url.setPath(path.directory()); url.adjustPath(KUrl::RemoveTrailingSlash); if (m_listingCache.contains(url)) { DirectoryListing listing = m_listingCache[url]; listing.updateEntry(path.fileName(), filesize); m_listingCache.insert(url, listing); } } void Cache::addPath(KUrl &url, const QString &target) { url.adjustPath(KUrl::RemoveTrailingSlash); m_pathCache[url] = target; } void Cache::addPath(Socket *socket, const QString &target) { KUrl url = socket->getCurrentUrl(); url.setPath(socket->getCurrentDirectory()); addPath(url, target); } void Cache::invalidateEntry(KUrl &url) { url.adjustPath(KUrl::RemoveTrailingSlash); m_listingCache.remove(url); } void Cache::invalidateEntry(Socket *socket, const QString &path) { KUrl url = socket->getCurrentUrl(); url.setPath(path); invalidateEntry(url); } void Cache::invalidatePath(KUrl &url) { url.adjustPath(KUrl::RemoveTrailingSlash); m_pathCache.remove(url); } void Cache::invalidatePath(Socket *socket, const QString &path) { KUrl url = socket->getCurrentUrl(); url.setPath(path); invalidatePath(url); } DirectoryListing Cache::findCached(KUrl &url) { url.adjustPath(KUrl::RemoveTrailingSlash); if (m_listingCache.contains(url)) return m_listingCache[url]; DirectoryListing invalid; invalid.setValid(false); return invalid; } DirectoryListing Cache::findCached(Socket *socket, const QString &path) { KUrl url = socket->getCurrentUrl(); url.setPath(path); return findCached(url); } QString Cache::findCachedPath(KUrl &url) { url.adjustPath(KUrl::RemoveTrailingSlash); if (m_pathCache.contains(url)) return m_pathCache[url]; return QString::null; } QString Cache::findCachedPath(Socket *socket, const QString &path) { KUrl url = socket->getCurrentUrl(); url.setPath(path); return findCachedPath(url); } } kftpgrabber-0.8.99~svn1214766/src/engine/commands.h0000644000175000017500000001106411276037142021413 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef COMMANDS_H #define COMMANDS_H #include "event.h" #define ENGINE_STANDARD_COMMAND_CONSTRUCTOR(class, type, cmd) public: \ class(type *socket) : Commands::Base(socket, Commands::cmd), currentState(None) {} \ private: \ State currentState; \ \ type *socket() {\ return static_cast(m_socket);\ }\ public: #define ENGINE_CANCELLATION_POINT { if (isDestructable()) \ return; } #define setupCommandClass(class) if (m_cmdData) \ delete m_cmdData; \ m_cmdData = new class(this); #define chainCommandClass(class) Commands::Base *_cmd = new class(socket()); \ socket()->addToCommandChain(_cmd); \ socket()->nextCommand(); \ return; #define activateCommandClass(class) if (m_cmdData) { \ Commands::Base *_cmd = new class(this); \ addToCommandChain(_cmd); \ nextCommand(); \ } else { \ m_cmdData = new class(this); \ m_cmdData->process(); \ } namespace KFTPEngine { class Socket; namespace Commands { enum Type { CmdNone, CmdWakeup, // Actual commands CmdConnect, CmdConnectRetry, CmdDisconnect, CmdList, CmdScan, CmdGet, CmdPut, CmdDelete, CmdRename, CmdMkdir, CmdChmod, CmdRaw, CmdFxp, CmdKeepAlive, CmdAbort }; class Base { public: Base(Socket *socket, Type type); virtual ~Base() {} void setProcessing(bool value); bool isProcessing() { return m_processing > 0; } void autoDestruct(ResetCode code); bool isDestructable() { return m_autoDestruct && !isProcessing(); } ResetCode resetCode() { return m_resetCode; } bool isClean() { return m_clean; } Type command() { return m_command; } bool isWakeup() { return m_wakeupEvent != 0; } virtual void wakeup(WakeupEvent *event); virtual void process() = 0; virtual void cleanup() {} protected: void markClean() { m_clean = true; } protected: Type m_command; Socket *m_socket; WakeupEvent *m_wakeupEvent; int m_processing; bool m_autoDestruct; ResetCode m_resetCode; bool m_clean; }; } } #endif kftpgrabber-0.8.99~svn1214766/src/engine/ftpdirectoryparser.cpp0000644000175000017500000006606011276037142024106 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2004 by the KFTPGrabber developers * Copyright (C) 2003-2004 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "ftpdirectoryparser.h" #include "ftpsocket.h" #include #include #include #include namespace KFTPEngine { class DToken { public: enum TokenTypeInfo { Unknown, Yes, No }; DToken() : m_token(QString::null), m_valid(false) { } DToken(const QString &token, int start = 0) : m_token(token), m_length(token.length()), m_start(start), m_valid(true), m_numeric(Unknown), m_leftNumeric(Unknown), m_rightNumeric(Unknown) { } int getStart() { return m_start; } QString getToken() { return m_token; } int getLength() { return m_length; } QString getString(int type = 0) { switch (type) { case 0: return m_token; break; case 1: { if (!isRightNumeric() || isNumeric()) return QString::null; int pos = m_length - 1; while (m_token[pos] >= '0' && m_token[pos] <= '9') pos--; return m_token.mid(0, pos + 1); break; } case 2: { if (!isLeftNumeric() || isNumeric()) return QString::null; int len = 0; while (m_token[len] >= '0' && m_token[len] <= '9') len++; return m_token.mid(0, len); break; } } return QString::null; } int find(const char *chr, unsigned int start = 0) const { if (!chr) return -1; for (unsigned int i = start; i < m_length; i++) { for (int c = 0; chr[c]; c++) { if (m_token[i] == chr[c]) return i; } } return -1; } unsigned long long getInteger() { return m_token.toULongLong(); } unsigned long long getInteger(unsigned int start, int len) { return m_token.mid(start, len).toULongLong(); } bool isValid() { return m_valid; } bool isNumeric() { if (m_numeric == Unknown) { bool ok; (void) m_token.toInt(&ok); m_numeric = ok ? Yes : No; } return m_numeric == Yes; } bool isNumeric(unsigned int start, unsigned int len) { len = start + len < m_length ? start + len : m_length; for (unsigned int i = start; i < len; i++) { if (m_token[i] < '0' || m_token[i] > '9') return false; } return true; } bool isLeftNumeric() { if (m_leftNumeric == Unknown) { if (m_length < 2) m_leftNumeric = No; else if (m_token[0] < '0' || m_token[0] > '9') m_leftNumeric = No; else m_leftNumeric = Yes; } return m_leftNumeric == Yes; } bool isRightNumeric() { if (m_rightNumeric == Unknown) { if (m_length < 2) m_rightNumeric = No; else if (m_token[m_length - 1] < '0' || m_token[m_length - 1] > '9') m_rightNumeric = No; else m_rightNumeric = Yes; } return m_rightNumeric == Yes; } char operator[](unsigned int n) const { return m_token[n].toAscii(); } private: QString m_token; unsigned int m_length; int m_start; bool m_valid; TokenTypeInfo m_numeric; TokenTypeInfo m_leftNumeric; TokenTypeInfo m_rightNumeric; }; class DLine { public: DLine(const QString &line) : m_line(line.trimmed()), m_parsePos(0) { } bool getToken(int index, DToken &token, bool toEnd = false) { if (!toEnd) { if (m_tokens.count() > index) { token = m_tokens[index]; return true; } int start = m_parsePos; while (m_parsePos < m_line.length()) { if (m_line[m_parsePos] == ' ') { m_tokens.append(DToken(m_line.mid(start, m_parsePos - start), start)); while (m_line[m_parsePos] == ' ' && m_parsePos < m_line.length()) m_parsePos++; if (m_tokens.count() > index) { token = m_tokens[index]; return true; } start = m_parsePos; } m_parsePos++; } if (m_parsePos != start) { m_tokens.append(DToken(m_line.mid(start, m_parsePos - start), start)); } if (m_tokens.count() > index) { token = m_tokens[index]; return true; } return false; } else { if (m_endLineTokens.count() > index) { token = m_endLineTokens[index]; return true; } if (m_tokens.count() <= index && !getToken(index, token)) return false; for (int i = m_endLineTokens.count(); i <= index; i++) { m_endLineTokens.append(DToken(m_line.mid(m_tokens[i].getStart()))); } token = m_endLineTokens[index]; return true; } } private: QStringList m_stringList; QVector m_tokens; QVector m_endLineTokens; QString m_line; int m_parsePos; }; FtpDirectoryParser::FtpDirectoryParser(FtpSocket *socket) : m_socket(socket), m_listing(DirectoryListing(socket->getCurrentDirectory())) { // Populate month names as they appear in the listing m_monthNameMap["jan"] = 1; m_monthNameMap["feb"] = 2; m_monthNameMap["mar"] = 3; m_monthNameMap["apr"] = 4; m_monthNameMap["may"] = 5; m_monthNameMap["jun"] = 6; m_monthNameMap["june"] = 6; m_monthNameMap["jul"] = 7; m_monthNameMap["july"] = 7; m_monthNameMap["aug"] = 8; m_monthNameMap["sep"] = 9; m_monthNameMap["sept"] = 9; m_monthNameMap["oct"] = 10; m_monthNameMap["nov"] = 11; m_monthNameMap["dec"] = 12; m_monthNameMap["1"] = 1; m_monthNameMap["01"] = 1; m_monthNameMap["2"] = 2; m_monthNameMap["02"] = 2; m_monthNameMap["3"] = 3; m_monthNameMap["03"] = 3; m_monthNameMap["4"] = 4; m_monthNameMap["04"] = 4; m_monthNameMap["5"] = 5; m_monthNameMap["05"] = 5; m_monthNameMap["6"] = 6; m_monthNameMap["06"] = 6; m_monthNameMap["7"] = 7; m_monthNameMap["07"] = 7; m_monthNameMap["8"] = 8; m_monthNameMap["08"] = 8; m_monthNameMap["9"] = 9; m_monthNameMap["09"] = 9; m_monthNameMap["10"] = 10; m_monthNameMap["11"] = 11; m_monthNameMap["12"] = 12; } void FtpDirectoryParser::addDataLine(const QString &line) { QString tmp(line); tmp.append("\n"); addData(tmp.toAscii(), tmp.length()); } void FtpDirectoryParser::addData(const char *data, int len) { // Append new data to the buffer and check for any new lines m_buffer.append(QString::fromAscii(data, len)); int pos; while ((pos = m_buffer.indexOf('\n')) > -1) { DirectoryEntry entry; QString line = m_buffer.mid(0, pos).trimmed(); line = m_socket->remoteEncoding()->decode(line.toAscii()); if (parseLine(line, entry) && !entry.filename().isEmpty()) { if (entry.type() == '-') entry.setType('f'); m_listing.addEntry(entry); } // Remove what we just parsed m_buffer.remove(0, pos + 1); } } bool FtpDirectoryParser::parseMlsd(const QString &line, DirectoryEntry &entry) { QStringList facts = line.split(';'); QStringList::Iterator end = facts.end(); for (QStringList::Iterator i = facts.begin(); i != end; ++i) { if ((*i).contains('=')) { QString key = (*i).section('=', 0, 0).toLower(); QString value = (*i).section('=', 1, 1); if (key == "type") { if (value == "file") entry.setType('f'); else if (value == "dir") entry.setType('d'); } else if (key == "size") { entry.setSize(value.toULongLong()); } else if (key == "modify") { struct tm dt; dt.tm_year = value.left(4).toInt() - 1900; dt.tm_mon = value.mid(4, 2).toInt() - 1; dt.tm_mday = value.mid(6, 2).toInt(); dt.tm_hour = value.mid(8, 2).toInt(); dt.tm_min = value.mid(10, 2).toInt(); dt.tm_sec = value.mid(12, 2).toInt(); entry.setTime(mktime(&dt)); } else if (key == "unix.mode") { entry.setPermissions(value.toInt(0, 8)); } else if (key == "unix.uid") { entry.setOwner(value); } else if (key == "unix.gid") { entry.setGroup(value); } } else { entry.setFilename((*i).trimmed()); } } return true; } bool FtpDirectoryParser::parseUnixPermissions(const QString &permissions, DirectoryEntry &entry) { int p = 0; if (permissions[1] == 'r') p |= S_IRUSR; if (permissions[2] == 'w') p |= S_IWUSR; if (permissions[3] == 'x' || permissions[3] == 's') p |= S_IXUSR; if (permissions[4] == 'r') p |= S_IRGRP; if (permissions[5] == 'w') p |= S_IWGRP; if (permissions[6] == 'x' || permissions[6] == 's') p |= S_IXGRP; if (permissions[7] == 'r') p |= S_IROTH; if (permissions[8] == 'w') p |= S_IWOTH; if (permissions[9] == 'x' || permissions[9] == 't') p |= S_IXOTH; if (permissions[3] == 's' || permissions[3] == 'S') p |= S_ISUID; if (permissions[6] == 's' || permissions[6] == 'S') p |= S_ISGID; if (permissions[9] == 't' || permissions[9] == 'T') p |= S_ISVTX; entry.setPermissions(p); return true; } bool FtpDirectoryParser::parseLine(const QString &line, DirectoryEntry &entry) { DLine *tLine = new DLine(line); bool done = false; // Invalidate timestamp entry.setTime(-1); entry.timeStruct.tm_year = 0; entry.timeStruct.tm_mon = 0; entry.timeStruct.tm_hour = 0; entry.timeStruct.tm_mday = 0; entry.timeStruct.tm_min = 0; entry.timeStruct.tm_sec = 0; entry.timeStruct.tm_wday = 0; entry.timeStruct.tm_yday = 0; entry.timeStruct.tm_isdst = 0; // Attempt machine friendly format first, when socket supports MLSD if (m_socket->getConfig("feat.mlsd")) done = parseMlsd(line, entry); if (!done) done = parseUnix(tLine, entry); if (!done) done = parseDos(tLine, entry); if (!done) done = parseVms(tLine, entry); if (done) { // Convert datetime to UNIX epoch if (entry.time() == -1) { // Correct format for mktime entry.timeStruct.tm_year -= 1900; entry.timeStruct.tm_mon -= 1; entry.setTime(mktime(&entry.timeStruct)); } // Add symlink if any if (entry.filename().contains(" -> ")) { int pos = entry.filename().lastIndexOf(" -> "); entry.setLink(entry.filename().mid(pos + 4)); entry.setFilename(entry.filename().mid(0, pos)); } // Parse owner into group/owner if (entry.owner().contains(" ")) { int pos = entry.owner().indexOf(" "); entry.setGroup(entry.owner().mid(pos + 1)); entry.setOwner(entry.owner().mid(0, pos)); } // Remove unwanted names if (entry.filename() == "." || entry.filename() == "..") { entry.setFilename(QString::null); } } delete tLine; return done; } bool FtpDirectoryParser::parseUnix(DLine *line, DirectoryEntry &entry) { int index = 0; DToken token; if (!line->getToken(index, token)) return false; char chr = token[0]; if (chr != 'b' && chr != 'c' && chr != 'd' && chr != 'l' && chr != 'p' && chr != 's' && chr != '-') return false; QString permissions = token.getString(); entry.setType(chr); // Check for netware servers, which split the permissions into two parts bool netware = false; if (token.getLength() == 1) { if (!line->getToken(++index, token)) return false; permissions += " " + token.getString(); netware = true; } parseUnixPermissions(permissions, entry); int numOwnerGroup = 3; if (!netware) { // Filter out groupid, we don't need it if (!line->getToken(++index, token)) return false; if (!token.isNumeric()) index--; } // Repeat until numOwnerGroup is 0 since not all servers send every possible field int startindex = index; do { // Reset index index = startindex; entry.setOwner(QString::null); for (int i = 0; i < numOwnerGroup; i++) { if (!line->getToken(++index, token)) return false; if (i) entry.setOwner(entry.owner() + " "); entry.setOwner(entry.owner() + token.getString()); } if (!line->getToken(++index, token)) return false; // Check for concatenated groupname and size fields filesize_t size; if (!parseComplexFileSize(token, size)) { if (!token.isRightNumeric()) continue; entry.setSize(token.getInteger()); } else { entry.setSize(size); } // Append missing group to ownerGroup if (!token.isNumeric() && token.isRightNumeric()) { if (!entry.owner().isEmpty()) entry.setOwner(entry.owner() + " "); entry.setOwner(entry.owner() + token.getString(1)); } if (!parseUnixDateTime(line, index, entry)) continue; // Get the filename if (!line->getToken(++index, token, true)) continue; entry.setFilename(token.getString()); // Filter out cpecial chars at the end of the filenames chr = token[token.getLength() - 1]; if (chr == '/' || chr == '|' || chr == '*') entry.setFilename(entry.filename().mid(0, entry.filename().length() - 1)); return true; } while (--numOwnerGroup); return false; } bool FtpDirectoryParser::parseUnixDateTime(DLine *line, int &index, DirectoryEntry &entry) { DToken token; // Get the month date field QString dateMonth; if (!line->getToken(++index, token)) return false; // Some servers use the following date formats: // 26-05 2002, 2002-10-14, 01-jun-99 // slashes instead of dashes are also possible int pos = token.find("-/"); if (pos != -1) { int pos2 = token.find("-/", pos + 1); if (pos2 == -1) { // something like 26-05 2002 int day = token.getInteger(pos + 1, token.getLength() - pos - 1); if (day < 1 || day > 31) return false; entry.timeStruct.tm_mday = day; dateMonth = token.getString().left(pos); } else if (!parseShortDate(token, entry)) { return false; } } else { dateMonth = token.getString(); } bool bHasYearAndTime = false; if (!entry.timeStruct.tm_mday) { // Get day field if (!line->getToken(++index, token)) return false; int dateDay; // Check for non-numeric day if (!token.isNumeric() && !token.isLeftNumeric()) { if (dateMonth.right(1) == ".") dateMonth.remove(dateMonth.length() - 1, 1); bool tmp; dateDay = dateMonth.toInt(&tmp); if (!tmp) return false; dateMonth = token.getString(); } else { dateDay = token.getInteger(); if (token[token.getLength() - 1] == ',') bHasYearAndTime = true; } if (dateDay < 1 || dateDay > 31) return false; entry.timeStruct.tm_mday = dateDay; } if (!entry.timeStruct.tm_mon) { // Check month name if (dateMonth.right(1) == "," || dateMonth.right(1) == ".") dateMonth.remove(dateMonth.length() - 1, 1); dateMonth = dateMonth.toLower(); QMap::iterator iter = m_monthNameMap.find(dateMonth); if (iter == m_monthNameMap.end()) return false; entry.timeStruct.tm_mon = iter.value(); } // Get time/year field if (!line->getToken(++index, token)) return false; pos = token.find(":.-"); if (pos != -1) { // Token is a time if (!pos || pos == (token.getLength() - 1)) return false; QString str = token.getString(); bool tmp; int hour = str.left(pos).toInt(&tmp); if (!tmp) return false; int minute = str.mid(pos + 1).toInt(&tmp); if (!tmp) return false; if (hour < 0 || hour > 23) return false; if (minute < 0 || minute > 59) return false; entry.timeStruct.tm_hour = hour; entry.timeStruct.tm_min = minute; // Some servers use times only for files nweer than 6 months, int year = QDate::currentDate().year(); int now = QDate::currentDate().day() + 31 * QDate::currentDate().month(); int file = entry.timeStruct.tm_mon * 31 + entry.timeStruct.tm_mday; if (now >= file) entry.timeStruct.tm_year = year; else entry.timeStruct.tm_year = year - 1; } else if (!entry.timeStruct.tm_year) { // token is a year if (!token.isNumeric() && !token.isLeftNumeric()) return false; int year = token.getInteger(); if (year > 3000) return false; if (year < 1000) year += 1900; entry.timeStruct.tm_year = year; if (bHasYearAndTime) { if (!line->getToken(++index, token)) return false; if (token.find(":") == 2 && token.getLength() == 5 && token.isLeftNumeric() && token.isRightNumeric()) { int pos = token.find(":"); // Token is a time if (!pos || pos == (token.getLength() - 1)) return false; QString str = token.getString(); bool tmp; long hour = str.left(pos).toInt(&tmp); if (!tmp) return false; long minute = str.mid(pos + 1).toInt(&tmp); if (!tmp) return false; if (hour < 0 || hour > 23) return false; if (minute < 0 || minute > 59) return false; entry.timeStruct.tm_hour = hour; entry.timeStruct.tm_min = minute; } else { index--; } } } else { index--; } return true; } bool FtpDirectoryParser::parseShortDate(DToken &token, DirectoryEntry &entry) { if (token.getLength() < 1) return false; bool gotYear = false; bool gotMonth = false; bool gotDay = false; bool gotMonthName = false; int value = 0; int pos = token.find("-./"); if (pos < 1) return false; if (!token.isNumeric(0, pos)) { // Seems to be monthname-dd-yy // Check month name QString dateMonth = token.getString().mid(0, pos); dateMonth = dateMonth.toLower(); QMap::iterator iter = m_monthNameMap.find(dateMonth); if (iter == m_monthNameMap.end()) return false; entry.timeStruct.tm_mon = iter.value(); gotMonth = true; gotMonthName = true; } else if (pos == 4) { // Seems to be yyyy-mm-dd int year = token.getInteger(0, pos); if (year < 1900 || year > 3000) return false; entry.timeStruct.tm_year = year; gotYear = true; } else if (pos <= 2) { int value = token.getInteger(0, pos); if (token[pos] == '.') { // Maybe dd.mm.yyyy if (value < 1900 || value > 3000) return false; entry.timeStruct.tm_mday = value; gotDay = true; } else { // Detect mm-dd-yyyy or mm/dd/yyyy and // dd-mm-yyyy or dd/mm/yyyy if (value < 1) return false; if (value > 12) { if (value > 31) return false; entry.timeStruct.tm_mday = value; gotDay = true; } else { entry.timeStruct.tm_mon = value; gotMonth = true; } } } else { return false; } int pos2 = token.find("-./", pos + 1); if (pos2 == -1 || (pos2 - pos) == 1) return false; if (pos2 == (token.getLength() - 1)) return false; // If we already got the month and the second field is not numeric, // change old month into day and use new token as month if (!token.isNumeric(pos + 1, pos2 - pos - 1) && gotMonth) { if (gotMonthName) return false; if (gotDay) return false; gotDay = true; gotMonth = false; entry.timeStruct.tm_mday = entry.timeStruct.tm_mon; } if (gotYear || gotDay) { // Month field in yyyy-mm-dd or dd-mm-yyyy // Check month name QString dateMonth = token.getString().mid(pos + 1, pos2 - pos - 1); dateMonth = dateMonth.toLower(); QMap::iterator iter = m_monthNameMap.find(dateMonth); if (iter == m_monthNameMap.end()) return false; entry.timeStruct.tm_mon = iter.value(); gotMonth = true; } else { int value = token.getInteger(pos + 1, pos2 - pos - 1); // Day field in mm-dd-yyyy if (value < 1 || value > 31) return false; entry.timeStruct.tm_mday = value; gotDay = true; } value = token.getInteger(pos2 + 1, token.getLength() - pos2 - 1); if (gotYear) { // Day field in yyy-mm-dd if (!value || value > 31) return false; entry.timeStruct.tm_mday = value; gotDay = true; } else { if (value < 0) return false; if (value < 50) { value += 2000; } else if (value < 1000) { value += 1900; } entry.timeStruct.tm_year = value; gotYear = true; } if (!gotMonth || !gotDay || !gotYear) return false; return true; } bool FtpDirectoryParser::parseDos(DLine *line, DirectoryEntry &entry) { int index = 0; DToken token; // Get first token, has to be a valid date if (!line->getToken(index, token)) return false; if (!parseShortDate(token, entry)) return false; // Extract time if (!line->getToken(++index, token)) return false; if (!parseTime(token, entry)) return false; // If next token is , entry is a directory // else, it should be the filesize. if (!line->getToken(++index, token)) return false; if (token.getString() == "") { entry.setType('d'); entry.setSize(0); } else if (token.isNumeric() || token.isLeftNumeric()) { // Convert size, filter out separators unsigned long size = 0; int len = token.getLength(); for (int i = 0; i < len; i++) { char chr = token[i]; if (chr == ',' || chr == '.') continue; if (chr < '0' || chr > '9') return false; size *= 10; size += chr - '0'; } entry.setSize(size); entry.setType('f'); } else { return false; } // Extract filename if (!line->getToken(++index, token, true)) return false; entry.setFilename(token.getString()); return true; } bool FtpDirectoryParser::parseTime(DToken &token, DirectoryEntry &entry) { int pos = token.find(":"); if (pos < 1 || pos >= (token.getLength() - 1)) return false; int hour = token.getInteger(0, pos); if (hour < 0 || hour > 23) return false; int minute = token.getInteger(pos + 1, 2); if (minute < 0 || minute > 59) return false; // Convert to 24h format if (!token.isRightNumeric()) { if (token[token.getLength() - 2] == 'P') { if (hour < 12) { hour += 12; } } else if (hour == 12) { hour = 0; } } entry.timeStruct.tm_hour = hour; entry.timeStruct.tm_min = minute; return true; } bool FtpDirectoryParser::parseVms(DLine *line, DirectoryEntry &entry) { DToken token; int index = 0; if (!line->getToken(index, token)) return false; int pos = token.find(";"); if (pos == -1) return false; if (pos > 4 && token.getString().mid(pos - 4, 4) == ".DIR") { entry.setType('d'); entry.setFilename(token.getString().left(pos - 4) + token.getString().mid(pos)); } else { entry.setType('f'); entry.setFilename(token.getString()); } // Get size if (!line->getToken(++index, token)) return false; if (!token.isNumeric() && !token.isLeftNumeric()) return false; entry.setSize(token.getInteger()); // Get date if (!line->getToken(++index, token)) return false; if (!parseShortDate(token, entry)) return false; // Get time if (!line->getToken(++index, token)) return true; if (!parseTime(token, entry)) { int len = token.getLength(); if (token[0] == '[' && token[len] != ']') return false; if (token[0] == '(' && token[len] != ')') return false; if (token[0] != '[' && token[len] == ']') return false; if (token[0] != '(' && token[len] == ')') return false; index--; } // Owner / group while (line->getToken(++index, token)) { int len = token.getLength(); if (len > 2 && token[0] == '(' && token[len - 1] == ')') entry.setPermissions(0); else if (len > 2 && token[0] == '[' && token[len - 1] == ']') entry.setOwner(token.getString().mid(1, len - 2)); else entry.setPermissions(0); } return true; } bool FtpDirectoryParser::parseComplexFileSize(DToken &token, filesize_t &size) { if (token.isNumeric()) { size = token.getInteger(); return true; } int len = token.getLength() - 1; char last = token[len]; if (last == 'B' || last == 'b') { char c = token[len]; if (c < '0' || c > '9') { last = token[len]; len--; } } size = 0; int dot = -1; for (int i = 0; i < len; i++) { char c = token[i]; if (c >= '0' && c <= '9') { size *= 10; size += c - '0'; } else if (c == '.') { if (dot != -1) return false; dot = len - i - 1; } else { return false; } } switch (last) { case 'k': case 'K': { size *= 1000; break; } case 'm': case 'M': { size *= 1000 * 1000; break; } case 'g': case 'G': { size *= 1000 * 1000 * 1000; break; } case 't': case 'T': { size *= 1000 * 1000; size *= 1000 * 1000; break; } case 'b': case 'B': break; default: return false; } while (dot-- > 0) size /= 10; return true; } } kftpgrabber-0.8.99~svn1214766/src/engine/socket.cpp0000644000175000017500000006117711276037142021447 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2006 by the KFTPGrabber developers * Copyright (C) 2003-2006 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #include "socket.h" #include "thread.h" #include "connectionretry.h" #include "speedlimiter.h" #include "cache.h" #include "misc/config.h" #include namespace KFTPEngine { Socket::Socket(Thread *thread, const QString &protocol) : m_remoteEncoding(new KRemoteEncoding()), m_cmdData(0), m_settings(thread->settings()), m_thread(thread), m_transferBytes(0), m_speedLastTime(0), m_speedLastBytes(0), m_protocol(protocol), m_currentCommand(Commands::CmdNone), m_errorReporting(true) { } Socket::~Socket() { delete m_remoteEncoding; delete m_connectionRetry; } void Socket::emitError(ErrorCode code, const QString ¶m1) { // Intercept connect and login errors and pass them on to the ConnectionRetry class (if enabled) if (getConfig("retry", false) && (code == ConnectFailed || code == LoginFailed)) { if (!m_connectionRetry) m_connectionRetry = new ConnectionRetry(this); m_connectionRetry->startRetry(); return; } QList params; params.append(QVariant(code)); params.append(QVariant(param1)); // Dispatch the event via socket thread m_thread->emitEvent(Event::EventError, params); } void Socket::emitEvent(Event::Type type, const QString ¶m1, const QString ¶m2) { QList params; params.append(QVariant(param1)); params.append(QVariant(param2)); // Dispatch the event via socket thread m_thread->emitEvent(type, params); } void Socket::emitEvent(Event::Type type, DirectoryListing param1) { emitEvent(type, QVariant::fromValue(param1)); } void Socket::emitEvent(Event::Type type, DirectoryTree *param1) { emitEvent(type, QVariant::fromValue(param1)); } void Socket::emitEvent(Event::Type type, const QVariant ¶m1) { QList params; params.append(param1); // Dispatch the event via socket thread m_thread->emitEvent(type, params); } WakeupEvent *Socket::emitEventAndWait(Event::Type type, const QVariant ¶m1) { emitEvent(type, param1); return m_thread->waitForWakeup(); } void Socket::changeEncoding(const QString &encoding) { // Alter encoding and change socket config m_remoteEncoding->setEncoding(encoding.toAscii()); setConfig("encoding", encoding); } void Socket::protoDisconnect() { resetCommandClass(UserAbort); emitEvent(Event::EventMessage, i18n("Disconnected.")); emitEvent(Event::EventDisconnect); } void Socket::timeoutWait(bool start) { if (start) { m_timeoutCounter.start(); } else { m_timeoutCounter = QTime(); } } void Socket::timeoutPing() { m_timeoutCounter.restart(); } void Socket::timeoutCheck() { if (!isConnected()) return; if (!m_timeoutCounter.isNull()) { Commands::Type command = getCurrentCommand(); int timeout = 0; // Ignore timeouts for FXP transfers, since there is no way to do pings if (command == Commands::CmdFxp) return; if (command == Commands::CmdGet || command == Commands::CmdPut) timeout = KFTPCore::Config::dataTimeout(); else timeout = KFTPCore::Config::controlTimeout(); if (timeout > 0 && m_timeoutCounter.elapsed() > (timeout * 1000)) { timeoutWait(false); // We have a timeout, let's abort emitEvent(Event::EventMessage, i18n("Connection timed out.")); protoDisconnect(); } } } void Socket::keepaliveStart() { m_keepaliveCounter.start(); } void Socket::keepaliveCheck() { // Ignore keepalive if the socket is busy if (isBusy() || !isConnected()) { m_keepaliveCounter.restart(); return; } if (getConfig("keepalive.enabled", false) && m_keepaliveCounter.elapsed() > getConfig("keepalive.timeout", 0) * 1000) { protoKeepAlive(); // Reset the counter m_keepaliveCounter.restart(); } } bool Socket::errorReporting(bool ignoreChaining) const { return ignoreChaining ? m_errorReporting : m_errorReporting || !isChained(); } Commands::Type Socket::getCurrentCommand() { if (m_commandChain.count() > 0) { QStack::iterator chainEnd = m_commandChain.end(); for (QStack::iterator i = m_commandChain.begin(); i != chainEnd; i++) { if ((*i)->command() != Commands::CmdNone) return (*i)->command(); } } return m_currentCommand; } Commands::Type Socket::getToplevelCommand() { return m_currentCommand; } Commands::Type Socket::getPreviousCommand() { if (!isChained()) return Commands::CmdNone; if (m_commandChain.count() > 1) { Commands::Base *tmp = m_commandChain.pop(); Commands::Base *previous = m_commandChain.top(); m_commandChain.push(tmp); return previous->command(); } else { return m_currentCommand; } } void Socket::resetCommandClass(ResetCode code) { if (m_commandChain.count() > 0) { Commands::Base *current = m_commandChain.top(); if (current->isProcessing()) { current->autoDestruct(code); return; } else { if (!current->isClean()) current->cleanup(); delete m_commandChain.pop(); } if (code == Ok) { nextCommandAsync(); } else { // Command has completed with an error code. We should abort the // complete chain. resetCommandClass(code); } } else { if (m_cmdData) { if (m_cmdData->isProcessing()) { m_cmdData->autoDestruct(code); return; } else { if (!m_cmdData->isClean()) m_cmdData->cleanup(); delete m_cmdData; m_cmdData = 0; } } if (code == Failed) emitError(OperationFailed); // Reset current command and emit a ready event if (getCurrentCommand() != Commands::CmdConnectRetry) { setCurrentCommand(Commands::CmdNone); emitEvent(Event::EventReady); emitEvent(Event::EventState, i18n("Idle.")); } setErrorReporting(true); } } void Socket::nextCommand() { if (m_commandChain.count() > 0) { Commands::Base *current = m_commandChain.top(); current->setProcessing(true); current->process(); current->setProcessing(false); if (current->isDestructable()) resetCommandClass(current->resetCode()); } else if (m_cmdData) { m_cmdData->setProcessing(true); m_cmdData->process(); m_cmdData->setProcessing(false); if (m_cmdData->isDestructable()) resetCommandClass(m_cmdData->resetCode()); } } void Socket::nextCommandAsync() { m_thread->deferCommandExec(); } void Socket::wakeup(WakeupEvent *event) { if (m_commandChain.count() > 0) { Commands::Base *current = m_commandChain.top(); if (current->isProcessing()) { qDebug("WARNING: Attempted to wakeup a processing socket!"); return; } current->setProcessing(true); current->wakeup(event); current->setProcessing(false); if (current->isDestructable()) resetCommandClass(current->resetCode()); } else if (m_cmdData) { if (m_cmdData->isProcessing()) { qDebug("WARNING: Attempted to wakeup a processing socket!"); return; } m_cmdData->setProcessing(true); m_cmdData->wakeup(event); m_cmdData->setProcessing(false); if (m_cmdData->isDestructable()) resetCommandClass(m_cmdData->resetCode()); } } filesize_t Socket::getTransferSpeed() { time_t timeDelta = time(0) - m_speedLastTime; if (timeDelta == 0) return 0; if (m_speedLastBytes > m_transferBytes) m_speedLastBytes = 0; filesize_t speed = (m_transferBytes - m_speedLastBytes)/(time(0) - m_speedLastTime); m_speedLastBytes = m_transferBytes; m_speedLastTime = time(0); return speed; } void Socket::protoAbort() { if (m_connectionRetry && !m_cmdData) m_connectionRetry->abortRetry(); } // ******************************************************************************************* // ******************************************* STAT ****************************************** // ******************************************************************************************* class FtpCommandStat : public Commands::Base { public: enum State { None, WaitList }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandStat, Socket, CmdNone) KUrl path; void process() { switch (currentState) { case None: { // Issue a list of the parent directory currentState = WaitList; socket()->setErrorReporting(false); socket()->protoList(path.directory()); break; } case WaitList: { // Now just extract what we need QList list = socket()->getLastDirectoryListing().list(); QList::iterator listEnd = list.end(); for (QList::iterator i = list.begin(); i != listEnd; i++) { if ((*i).filename() == path.fileName()) { socket()->m_lastStatResponse = *i; socket()->resetCommandClass(); return; } } // We found no such file socket()->m_lastStatResponse = DirectoryEntry(); socket()->resetCommandClass(); break; } } } }; void Socket::protoStat(const KUrl &path) { // Lookup the cache first and don't even try to list if cached DirectoryListing cached = Cache::self()->findCached(this, path.directory()); if (cached.isValid()) { QList list = cached.list(); QList::iterator listEnd = list.end(); for (QList::iterator i = list.begin(); i != listEnd; i++) { if ((*i).filename() == path.fileName()) { m_lastStatResponse = *i; nextCommandAsync(); return; } } // Cached is valid but file can't be found m_lastStatResponse = DirectoryEntry(); nextCommandAsync(); return; } // Not cached, let's do a real listing FtpCommandStat *stat = new FtpCommandStat(this); stat->path = path; addToCommandChain(stat); nextCommand(); } // ******************************************************************************************* // ****************************************** SCAN ******************************************* // ******************************************************************************************* class FtpCommandScan : public Commands::Base { public: enum State { None, SentList, ProcessList, ScannedDir }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandScan, Socket, CmdNone) QList currentList; QList::ConstIterator currentEntry; QString currentDirectory; DirectoryTree *currentTree; void cleanup() { // We didn't emit the tree, so we should free it if (!socket()->isChained()) delete currentTree; } void process() { // NOTE: The missing breaks are mising for a purpuse! Do not dare to add them ;) switch (currentState) { case None: { // We would like to disable error reporting socket()->setErrorReporting(false); // Issue a directory listing on the given URL currentState = SentList; socket()->protoList(currentDirectory); break; } case SentList: { currentList = socket()->getLastDirectoryListing().list(); qSort(currentList); currentEntry = currentList.constBegin(); currentState = ProcessList; // Empty listing, we are done if (currentEntry == currentList.constEnd()) { if (socket()->isChained()) { socket()->resetCommandClass(); } else { // We are the toplevel scan command markClean(); socket()->emitEvent(Event::EventScanComplete, currentTree); socket()->emitEvent(Event::EventMessage, i18n("Scan complete.")); socket()->resetCommandClass(); } return; } } case ProcessList: { if ((*currentEntry).isDirectory()) { // A directory entry DirectoryTree *tree = currentTree->addDirectory(*currentEntry); currentState = ScannedDir; FtpCommandScan *scan = new FtpCommandScan(socket()); scan->currentDirectory = currentDirectory + "/" + (*currentEntry).filename(); scan->currentTree = tree; socket()->addToCommandChain(scan); socket()->nextCommandAsync(); return; } else { // A file entry currentTree->addFile(*currentEntry); } } case ScannedDir: { currentState = ProcessList; if (++currentEntry == currentList.constEnd()) { // We are done if (socket()->isChained()) { socket()->resetCommandClass(); } else { // We are the toplevel scan command markClean(); socket()->emitEvent(Event::EventScanComplete, currentTree); socket()->emitEvent(Event::EventMessage, i18n("Scan complete.")); socket()->resetCommandClass(); } } else { socket()->nextCommandAsync(); } break; } } } }; void Socket::protoScan(const KUrl &path) { emitEvent(Event::EventMessage, i18n("Starting recursive directory scan...")); // We have to create a new command class manually, since we need to set the // currentTree parameter FtpCommandScan *scan = new FtpCommandScan(this); scan->currentDirectory = path.path(); scan->currentTree = new DirectoryTree(DirectoryEntry()); m_cmdData = scan; m_cmdData->process(); } // ******************************************************************************************* // ***************************************** DELETE ****************************************** // ******************************************************************************************* class FtpCommandDelete : public Commands::Base { public: enum State { None, VerifyDir, SimpleRemove, SentList, ProcessList, DeletedDir, DeletedFile }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandDelete, Socket, CmdDelete) QList currentList; QList::const_iterator currentEntry; KUrl destinationPath; void process() { switch (currentState) { case None: { // We have to determine if the destination is a file or a directory // TODO use cached information if (socket()->isChained()) { // We know that it is a directory currentState = SentList; socket()->protoList(destinationPath); } else { currentState = VerifyDir; socket()->protoStat(destinationPath); } break; } case VerifyDir: { DirectoryEntry entry = socket()->getStatResponse(); if (entry.filename().isEmpty()) { // The file doesn't exist, abort socket()->resetCommandClass(Failed); } else { if (entry.isDirectory()) { // It is a directory, remove recursively currentState = SentList; socket()->protoList(destinationPath); } else { // A single file, a simple remove currentState = SimpleRemove; socket()->setConfig("params.remove.directory", 0); socket()->protoRemove(destinationPath); } } break; } case SimpleRemove: { if (!socket()->isChained()) socket()->emitEvent(Event::EventReloadNeeded); socket()->resetCommandClass(); break; } case SentList: { currentList = socket()->getLastDirectoryListing().list(); currentEntry = currentList.constBegin(); currentState = ProcessList; // Empty listing, we are done if (currentEntry == currentList.constEnd()) { if (socket()->isChained()) socket()->resetCommandClass(); else { // We are the top level command class, remove the destination dir currentState = SimpleRemove; socket()->setConfig("params.remove.directory", 1); socket()->protoRemove(destinationPath); } return; } } case ProcessList: { KUrl childPath = destinationPath; childPath.addPath((*currentEntry).filename()); if ((*currentEntry).isDirectory()) { // A directory, chain another delete command currentState = DeletedDir; // Chain manually, since we need to set some parameters FtpCommandDelete *del = new FtpCommandDelete(socket()); del->destinationPath = childPath; socket()->addToCommandChain(del); socket()->nextCommand(); } else { // A file entry - remove currentState = DeletedFile; socket()->setConfig("params.remove.directory", 0); socket()->protoRemove(childPath); } break; } case DeletedDir: { // We have to remove the empty directory KUrl childPath = destinationPath; childPath.addPath((*currentEntry).filename()); currentState = DeletedFile; socket()->setConfig("params.remove.directory", 1); socket()->protoRemove(childPath); break; } case DeletedFile: { currentState = ProcessList; if (++currentEntry == currentList.constEnd()) { if (socket()->isChained()) socket()->resetCommandClass(); else { // We are the top level command class, remove the destination dir currentState = SimpleRemove; socket()->setConfig("params.remove.directory", 1); socket()->protoRemove(destinationPath); } } else socket()->nextCommand(); break; } } } }; void Socket::protoDelete(const KUrl &path) { // We have to create a new command class manually to set some parameter FtpCommandDelete *del = new FtpCommandDelete(this); del->destinationPath = path; m_cmdData = del; m_cmdData->process(); } // ******************************************************************************************* // ***************************************** CHMOD ******************************************* // ******************************************************************************************* class FtpCommandRecursiveChmod : public Commands::Base { public: enum State { None, VerifyDir, SimpleChmod, SentList, ProcessList, ChmodedDir, ChmodedFile }; ENGINE_STANDARD_COMMAND_CONSTRUCTOR(FtpCommandRecursiveChmod, Socket, CmdChmod) QList currentList; QList::const_iterator currentEntry; KUrl destinationPath; int mode; void process() { switch (currentState) { case None: { // We have to determine if the destination is a file or a directory if (socket()->isChained()) { // We know that it is a directory currentState = SentList; socket()->protoList(destinationPath); } else { currentState = VerifyDir; socket()->protoStat(destinationPath); } break; } case VerifyDir: { DirectoryEntry entry = socket()->getStatResponse(); if (entry.filename().isEmpty()) { // The file doesn't exist, abort socket()->resetCommandClass(Failed); } else { if (entry.isDirectory()) { // It is a directory, chmod recursively currentState = SentList; socket()->protoList(destinationPath); } else { // A single file, a simple chmod currentState = SimpleChmod; socket()->protoChmodSingle(destinationPath, mode); } } break; } case SimpleChmod: { socket()->resetCommandClass(); break; } case SentList: { currentList = socket()->getLastDirectoryListing().list(); currentEntry = currentList.constBegin(); currentState = ProcessList; // Empty listing, we are done if (currentEntry == currentList.constEnd()) { if (socket()->isChained()) socket()->resetCommandClass(); else { // We are the top level command class, chmod the destination dir currentState = SimpleChmod; socket()->protoChmodSingle(destinationPath, mode); } return; } } case ProcessList: { KUrl childPath = destinationPath; childPath.addPath((*currentEntry).filename()); if ((*currentEntry).isDirectory()) { // A directory, chain another recursive chmod command currentState = ChmodedDir; // Chain manually, since we need to set some parameters FtpCommandRecursiveChmod *cm = new FtpCommandRecursiveChmod(socket()); cm->destinationPath = childPath; cm->mode = mode; socket()->addToCommandChain(cm); socket()->nextCommand(); } else { // A file entry - remove currentState = ChmodedFile; socket()->protoChmodSingle(childPath, mode); } break; } case ChmodedDir: { // We have to chmod the directory KUrl childPath = destinationPath; childPath.addPath((*currentEntry).filename()); currentState = ChmodedFile; socket()->protoChmodSingle(childPath, mode); break; } case ChmodedFile: { currentState = ProcessList; if (++currentEntry == currentList.constEnd()) { if (socket()->isChained()) socket()->resetCommandClass(); else { // We are the top level command class, chmod the destination dir currentState = SimpleChmod; socket()->protoChmodSingle(destinationPath, mode); } } else socket()->nextCommand(); break; } } } }; void Socket::protoChmod(const KUrl &path, int mode, bool recursive) { if (recursive) { // We have to create a new command class manually to set some parameters FtpCommandRecursiveChmod *cm = new FtpCommandRecursiveChmod(this); cm->destinationPath = path; cm->mode = mode; m_cmdData = cm; m_cmdData->process(); } else { // No recursive, just chmod a single file protoChmodSingle(path, mode); } } } kftpgrabber-0.8.99~svn1214766/src/engine/CMakeLists.txt0000644000175000017500000000104411276037142022176 0ustar michaelmichaelinclude_directories( .. ../misc ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(engine_SRCS settings.cpp socket.cpp thread.cpp directorylisting.cpp commands.cpp event.cpp ftpsocket.cpp ftpdirectoryparser.cpp cache.cpp sftpsocket.cpp connectionretry.cpp speedlimiter.cpp otpgenerator.cpp ) kde4_add_library(engine STATIC ${engine_SRCS}) target_link_libraries(engine ${LIBSSH2_LIBRARY}) add_dependencies(engine misc) kftpgrabber-0.8.99~svn1214766/src/CMakeLists.txt0000644000175000017500000000253611556266020020740 0ustar michaelmichaelADD_SUBDIRECTORY( misc ) ADD_SUBDIRECTORY( engine ) ADD_SUBDIRECTORY( ui ) ADD_SUBDIRECTORY( widgets ) include_directories( misc widgets ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ) ########### next target ############### SET(kftpgrabber_SRCS main.cpp mainwindow.cpp checksumverifier.cpp kftpbookmarks.cpp kftpqueue.cpp kftpqueueprocessor.cpp kftpsession.cpp kftpqueueconverter.cpp kftptransfer.cpp kftptransferfile.cpp kftptransferdir.cpp fileexistsactions.cpp statistics.cpp site.cpp queueobject.cpp queuegroup.cpp directoryscanner.cpp ) kde4_add_executable(kftpgrabber ${kftpgrabber_SRCS}) # bookmarkwidgets target_link_libraries(kftpgrabber ${KDE4_KPARTS_LIBS} ${KDE4_KDECORE_LIBS} ${KDE4_KDNSSD_LIBRARY} ${KDE4_KDE3SUPPORT_LIBRARY} ${KDE4_KUTILS_LIBRARY} ${KDE4_KFILE_LIBRARY} ${LIBSSH2_LIBRARY} ) target_link_libraries(kftpgrabber browser bookmarkwidgets queueviewwidget failedtransferswidget widgets engine misc customcommands ui kftpinterfaces crypto) install(TARGETS kftpgrabber ${INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install(PROGRAMS kftpgrabber.desktop DESTINATION ${XDG_APPS_INSTALL_DIR}) install(FILES kftpgrabberui.rc kftpgrabber-logo.png kftpgrabber-bi-wizard.png DESTINATION ${DATA_INSTALL_DIR}/kftpgrabber) kde4_install_icons( ${ICON_INSTALL_DIR} ) kftpgrabber-0.8.99~svn1214766/src/kftpgrabberui.rc0000644000175000017500000000122211276037142021344 0ustar michaelmichael Main Toolbar kftpgrabber-0.8.99~svn1214766/src/fileexistsactions.h0000644000175000017500000001077511276037142022115 0ustar michaelmichael/* * This file is part of the KFTPGrabber project * * Copyright (C) 2003-2007 by the KFTPGrabber developers * Copyright (C) 2003-2007 Jernej Kos * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and * NON-INFRINGEMENT. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * In addition, as a special exception, the copyright holders give * permission to link the code of portions of this program with the * OpenSSL library under certain conditions as described in each * individual source file, and distribute linked combinations * including the two. * You must obey the GNU General Public License in all respects * for all of the code used other than OpenSSL. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you * do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source * files in the program, then also delete it here. */ #ifndef KFTPQUEUEFILEEXISTSACTIONS_H #define KFTPQUEUEFILEEXISTSACTIONS_H #include #include #include typedef qulonglong filesize_t; class KComboBox; namespace KFTPQueue { enum FEAction { FE_DISABLE_ACT = -1, FE_SKIP_ACT = 0, FE_OVERWRITE_ACT = 1, FE_RESUME_ACT = 2, FE_RENAME_ACT = 3, FE_USER_ACT = 4 }; typedef QMap ActionMap; /** * This class provides configurable "on file exists" actions. They are * represented in a 3x3 matrix which determines the 9 possible scenarios. * The matrix goes like this: *
 *               | SAME TIMESTAMP | OLDER | NEWER
 * SAME FILESIZE |       1        |   2   |   3
 *       SMALLER |       4        |   5   |   6
 *        BIGGER |       7        |   8   |   9
 * 
* * @author Jernej Kos */ class FileExistsActions { public: /** * This method will construct a new widget that will represent * the current status of the overwrite matrix and the ability to * change the values. * * @param parent Widget's parent * @return A new @ref QWidget */ QWidget *getConfigWidget(QWidget *parent = 0); /** * Set action for a specific file exists situation. * * @param situation Situation (acoording to the above matrix) * @action A FEAction that determines the appropriate action */ void setActionForSituation(int situation, FEAction action) { m_actions[situation] = action; } /** * Get action for specific file exists situation. * * @param src_fileSize File size of the file that exists * @param src_fileTimestamp File timestamp of the file that exists * @param dst_fileSize File size of the file that will (or not) replace the old one * @param dst_fileTimestamp File timestamp of the file that will (or not) replace the old one * @return An action as @ref FEAction */ FEAction getActionForSituation(filesize_t src_fileSize, time_t src_fileTimestamp, filesize_t dst_fileSize, time_t dst_fileTimestamp); /** * Sets a text that will be used as type for these actions (like download/upload). * * @param text The text */ void setTypeText(const QString &text) { m_type = text; } /** * Update the current GUI widget with new settings. */ void updateWidget(); /** * Update the current configuration with the new settings (as dictated by the * GUI). */ void updateConfig(); private: ActionMap m_actions; QString m_type; KComboBox *m_combos[3][3]; friend QString &operator<<(QString &s, const FileExistsActions &a); friend QString &operator>>(QString &s, FileExistsActions &a); }; QString &operator<<(QString &s, const FileExistsActions &a); QString &operator>>(QString &s, FileExistsActions &a); } #endif kftpgrabber-0.8.99~svn1214766/COPYING0000644000175000017500000003544511276037142016451 0ustar michaelmichael GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 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. 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 kftpgrabber-0.8.99~svn1214766/cmake/0000755000175000017500000000000011276037142016463 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/cmake/modules/0000755000175000017500000000000011276037142020133 5ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/cmake/modules/FindLibSSH2.cmake0000644000175000017500000000114711276037142023107 0ustar michaelmichael# - Try to find the libssh2 library # Once done this will define # # LIBSSH2_FOUND - system has the libssh2 library # LIBSSH2_INCLUDE_DIR - the libssh2 include directory # LIBSSH2_LIBRARY - the libssh2 library name if (LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY) set(LibSSH2_FIND_QUIETLY TRUE) endif (LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY) FIND_PATH(LIBSSH2_INCLUDE_DIR libssh2.h ) FIND_LIBRARY(LIBSSH2_LIBRARY NAMES ssh2 ) include(FindPackageHandleStandardArgs) FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibSSH2 DEFAULT_MSG LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY ) MARK_AS_ADVANCED(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY) kftpgrabber-0.8.99~svn1214766/ChangeLog0000644000175000017500000000533211276037142017160 0ustar michaelmichaelKFTPGrabber Changelog ===================== (c) 2003-2005 the KFTPGrabber developers. VERSION 0.6.0 FIX: Resuming files using SFTP FIX: Do not refetch directory listings while processing the queue FIX: Queue/server management related crash FIX: Incorrect directory progress when aborting transfer VERSION 0.6.0-beta2 FIX: Request for password when selecting anonymous in quick connect dialog FIX: Set the correct home dir on some remote connections FIX: Bookmark related crash FIX: Proper encoding of URLs in the queue file FIX: One month timeshift when doing MDTM VERSION 0.6.0-beta1 ADD: According to the KDE HIG minimize to tray if the mainwindow is closed ADD: Experimental support for multiple threads ADD: Traffic graph ADD: Commonly used site commands for GlFTPD (more to follow) ADD: Support for setting per-site encoding CHG: Updated libssh to the latest version to support keyboard-interactive auth CHG: Removed howl in favor of KDNSSD Zeroconf API FIX: Lots of crash fixes FIX: Rewritten directory listing parser FIX: Different queue improvements and bugfixes VERSION 0.5.0 FIX: Behaviour of the "Show Tree View" button FIX: Processing of queued transfers after aborting a transfer FIX: Fix a progressbar related crash FIX: Many bugfixes to the quickconnect dialog FIX: Adjustment of licenses (thanks to Vince ) FIX: Support for servers that send their local IP instead of the correct one FIX: Upload of files >4GB FIX: FreeBSD threading lib detection ADD: README and Changelog VERSION 0.5.0-beta1 ADD: Experimental SFTP support ADD: Support of implicit SSL connections ADD: Support for setting the local directory ADD: Setting the password for anonymous connections is now possible ADD: Using transfermodes other than plain FTP is now possible from the quick connect dialog ADD: Bookmark sidebar ADD: Zeroconf sidebar ADD: Saving the mainwindow's position ADD: Password dialog for Zeroconf connections ADD: Plugin framework for import filters, currently featuring a gFTP import filter (more to come) ADD: Option for disabling the splash screen ADD: Ability to configure the default behavior of overwrite/resume/rename when files already exist in local and remote directories CHG: Use of KMDI for the user interface CHG: Reworked bookmark editor FIX: Off by one for the date's month when uploading files FIX: Reconnection delay can now be up to 9999 seconds FIX: Detection of QSA and Howl in the configure script FIX: ETA calculation FIX: Lots of compile fixes and other bugfixes REM: Global option for the remote directory. The one provided by the server is now used, if not being overridden by the bookmark setting kftpgrabber-0.8.99~svn1214766/TODO0000644000175000017500000000004111276037142016066 0ustar michaelmichaelSee the provided "Roadmap" file. kftpgrabber-0.8.99~svn1214766/AUTHORS0000644000175000017500000000011211276037142016445 0ustar michaelmichaelJernej Kos Markus Brueffer kftpgrabber-0.8.99~svn1214766/INSTALL0000644000175000017500000000013011276037142016426 0ustar michaelmichaelBuild instructions can be found at http://techbase.kde.org/Getting_Started/Build/KDE4 kftpgrabber-0.8.99~svn1214766/config-kftpgrabber.h.cmake0000644000175000017500000000040011276037142022361 0ustar michaelmichael#cmakedefine HAVE_GETHOSTBYNAME 1 #cmakedefine HAVE_SYS_POLL_H 1 #cmakedefine HAVE_SYS_TIME_H 1 #cmakedefine HAVE_OPENSSL_AES_H 1 #cmakedefine HAVE_OPENSSL_BLOWFISH_H 1 #cmakedefine HAVE_GETHOSTBYADDR 1 #cmakedefine HAVE_POLL 1 #cmakedefine HAVE_SELECT 1 kftpgrabber-0.8.99~svn1214766/README0000644000175000017500000000547311276037142016274 0ustar michaelmichael KFTPGrabber README -------------------- INTRODUCTION ============== KFTPGrabber - A graphical FTP client for KDE There are many FTP clients around these days. Most are console based, some feature a graphical user interface. What most clients are missing is support for latest or not so common technologies like ZeroConf, TLS/SSL or FXP (just to name a few), accompanied by a decent user interface that tries to support the user instead of frustrating him/her. KFTPGrabber tries to make a complete FTP client solution with support for plugins, scripting and everything else the users needs, based on the latest technologies provided by KDE. Here are some of the features: - Multiple FTP sessions (tabs) - Transfer queue - TLS/SSL support for encrypted connections (implicit and explicit) - Partial X509 certificate support for authentication - FXP transfer support (site-to-site) - OTP (one time password) support - S/Key, MD5, RMD160, SHA1 - Drag&Drop support - Site bookmarking - Encrypted bookmark support (password can be saved to KWallet) - Distributed FTP support (PRET) - SSCN and CPSV support - Skiplist - ZeroConf (aka. Rendezvous) support for local site discovery - Bookmark sharing with Kopete contacts (KDE >= 3.3) - Bookmark import plugins - Support for SFTP protocol [experimental] This file was last updated with relevance to KFTPGrabber 0.8.0 -------------------------------------------------------------------------------- DEPENDENCIES ============== Required: * KDElibs 3.3 http://www.kde.org * OpenSSL 0.9.7 http://www.openssl.org Please note: If you obtain these dependencies via a packaging system, you must also install the devel versions of these packages! -------------------------------------------------------------------------------- IMPORTANT INSTALL INSTRUCTIONS ================================ In order to compile and install KFTPGrabber on your system, type the following in the base directory of the KFTPGrabber distribution: % ./configure --prefix=`kde-config --prefix` % make % make install Note: --enable-final is not supported. Packages for popular distributions are available at http://www.kftp.org/ -------------------------------------------------------------------------------- CONTRIBUTING ============== If you wish to contribute to KFTPGrabber, you should build it from SVN and contact the developers via e-mail or irc - the IRC channel is also a place where it's nice to be, since you can talk to other developers much easier. -------------------------------------------------------------------------------- WWW : http://www.kftp.org/ MAIL: kostko@unimatrix-one.org IRC : irc.freenode.net, #kftpgrabber -------------------------------------------------------------------------------- kftpgrabber-0.8.99~svn1214766/Roadmap0000644000175000017500000000263211276037142016714 0ustar michaelmichaelPRIORITY ********************************************************** - Fix slow SSL data connections in the new engine. - Kostko VERSION 0.8 ********************************************************** - Keep alive (NOOP). - someone - Drag drop changing position in queue. After server as top item have been done. - anyone(tobias if no one does it first). - Tooltips. - Tobias/first come. - Auto save queue on folder complete. (unless someone disagrees with this idea - tobias). - anybody. - Handle bookmark file conflicts properly. - ???. - Documentation (should be docbook, see http://quality.kde.org/develop/howto/howtodocs.php) for [priority, view/edit, FXP speed, and what else tobias didn't comment] - tobias(well.. DOH). - Unify all the filtering options (highlighting, priority lists, ASCII extensions) by creating a filtering API. A Thunderbird-like filtering dialog should be used for user configuration. UNDECIDED: ********************************************************** - Kicker applet showing threads, and speed.(unless someone disagrees with this idea - tobias) - Split queue/logs (or rather.. any two(+) of the tabs). - Bookmark directories on server. - Mirror enter directories with alt+dbl click.. if directory names are similar in both panes. - Open an ssh window to the connected window.. and automagicly log in (how?.. i'm not sure i see the need) - Reconnect and do cd after disconnect (on timeout). kftpgrabber-0.8.99~svn1214766/LICENSE.OpenSSL0000644000175000017500000001420711276037142017676 0ustar michaelmichael LICENSE ISSUES ============== The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the OpenSSL License and the original SSLeay license apply to the toolkit. See below for the actual license texts. Actually both licenses are BSD-style Open Source licenses. In case of any license issues related to OpenSSL please contact openssl-core@openssl.org. OpenSSL License --------------- /* ==================================================================== * Copyright (c) 1998-2004 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are 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. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED 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 OpenSSL PROJECT OR * ITS CONTRIBUTORS 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. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ Original SSLeay License ----------------------- /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ kftpgrabber-0.8.99~svn1214766/NEWS0000644000175000017500000000000011276037142016070 0ustar michaelmichaelkftpgrabber-0.8.99~svn1214766/CMakeLists.txt0000644000175000017500000000226111276037142020144 0ustar michaelmichaelproject(KFTPgrabber) cmake_minimum_required(VERSION 2.6) find_package(KDE4 REQUIRED) include(KDE4Defaults) include(MacroLibrary) include(CheckIncludeFile) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules) find_package(LibSSH2 REQUIRED) add_definitions(-DQT3_SUPPORT -DQT3_SUPPORT_WARNINGS) add_definitions(${QT_DEFINITIONS} ${KDE4_DEFINITIONS}) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${KDE4_INCLUDES}) check_include_file(sys/poll.h HAVE_SYS_POLL_H) check_include_file(sys/time.h HAVE_SYS_TIME_H) check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H) check_include_file(openssl/blowfish.h HAVE_OPENSSL_BLOWFISH_H) check_symbol_exists(gethostbyname "netdb.h" HAVE_GETHOSTBYNAME) check_symbol_exists(gethostbyaddr "netdb.h" HAVE_GETHOSTBYADDR) check_symbol_exists(poll "poll.h" HAVE_POLL) check_symbol_exists(select "sys/select.h" HAVE_SELECT) configure_file(config-kftpgrabber.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kftpgrabber.h) add_subdirectory( src )