From 6f1a8216cfba28add0ef365b46a08d16d4eb87fe Mon Sep 17 00:00:00 2001 From: =?utf8?q?Florent=20=E2=80=98nextgens=E2=80=99=20Daign=C3=A8re?= Date: Mon, 3 Apr 2006 23:08:33 +0000 Subject: [PATCH] jSite: First commit : verion 4.0 (written by Bombe) --- COPYING | 340 +++++++++ build.xml | 160 ++++ images/jsite-icon.png | Bin 0 -> 4838 bytes .../jsite/application/EditionProject.java | 82 ++ src/de/todesbaum/jsite/application/FileOption.java | 142 ++++ .../jsite/application/Freenet7Interface.java | 105 +++ .../jsite/application/InsertListener.java | 40 + src/de/todesbaum/jsite/application/Node.java | 97 +++ src/de/todesbaum/jsite/application/Project.java | 243 ++++++ .../jsite/application/ProjectInserter.java | 328 ++++++++ src/de/todesbaum/jsite/gui/FileScanner.java | 97 +++ .../todesbaum/jsite/gui/FileScannerListener.java | 28 + .../todesbaum/jsite/gui/NodeManagerListener.java | 35 + src/de/todesbaum/jsite/gui/NodeManagerPage.java | 321 ++++++++ src/de/todesbaum/jsite/gui/ProjectFilesPage.java | 516 +++++++++++++ src/de/todesbaum/jsite/gui/ProjectInsertPage.java | 198 +++++ src/de/todesbaum/jsite/gui/ProjectPage.java | 455 +++++++++++ src/de/todesbaum/jsite/i18n/I18n.java | 56 ++ src/de/todesbaum/jsite/i18n/jSite.properties | 126 ++++ src/de/todesbaum/jsite/i18n/jSite_de.properties | 126 ++++ src/de/todesbaum/jsite/main/CLI.java | 222 ++++++ src/de/todesbaum/jsite/main/Configuration.java | 355 +++++++++ src/de/todesbaum/jsite/main/Main.java | 413 ++++++++++ src/de/todesbaum/jsite/main/Version.java | 34 + src/de/todesbaum/util/freenet/fcp2/Client.java | 216 ++++++ .../todesbaum/util/freenet/fcp2/ClientHello.java | 101 +++ src/de/todesbaum/util/freenet/fcp2/ClientPut.java | 217 ++++++ .../util/freenet/fcp2/ClientPutComplexDir.java | 121 +++ .../todesbaum/util/freenet/fcp2/ClientPutDir.java | 83 ++ src/de/todesbaum/util/freenet/fcp2/Command.java | 138 ++++ src/de/todesbaum/util/freenet/fcp2/Connection.java | 371 +++++++++ .../util/freenet/fcp2/ConnectionListener.java | 50 ++ .../util/freenet/fcp2/DirectFileEntry.java | 100 +++ .../todesbaum/util/freenet/fcp2/DiskFileEntry.java | 67 ++ src/de/todesbaum/util/freenet/fcp2/FileEntry.java | 83 ++ .../todesbaum/util/freenet/fcp2/GenerateSSK.java | 39 + src/de/todesbaum/util/freenet/fcp2/Message.java | 175 +++++ src/de/todesbaum/util/freenet/fcp2/Node.java | 82 ++ .../todesbaum/util/freenet/fcp2/Persistence.java | 49 ++ .../todesbaum/util/freenet/fcp2/PriorityClass.java | 58 ++ .../util/freenet/fcp2/RedirectFileEntry.java | 45 ++ src/de/todesbaum/util/freenet/fcp2/Verbosity.java | 51 ++ src/de/todesbaum/util/image/IconLoader.java | 51 ++ src/de/todesbaum/util/io/LineInputStream.java | 64 ++ .../todesbaum/util/io/ReplacingOutputStream.java | 83 ++ src/de/todesbaum/util/io/StreamCopier.java | 152 ++++ src/de/todesbaum/util/io/TempFileInputStream.java | 56 ++ src/de/todesbaum/util/mime/DefaultMIMETypes.java | 834 +++++++++++++++++++++ src/de/todesbaum/util/swing/SortedListModel.java | 248 ++++++ src/de/todesbaum/util/swing/TLabel.java | 94 +++ src/de/todesbaum/util/swing/TWizard.java | 260 +++++++ src/de/todesbaum/util/swing/TWizardPage.java | 81 ++ src/de/todesbaum/util/swing/WizardListener.java | 35 + src/de/todesbaum/util/xml/SimpleXML.java | 308 ++++++++ src/de/todesbaum/util/xml/XML.java | 177 +++++ 55 files changed, 9008 insertions(+) create mode 100644 COPYING create mode 100644 build.xml create mode 100644 images/jsite-icon.png create mode 100644 src/de/todesbaum/jsite/application/EditionProject.java create mode 100644 src/de/todesbaum/jsite/application/FileOption.java create mode 100644 src/de/todesbaum/jsite/application/Freenet7Interface.java create mode 100644 src/de/todesbaum/jsite/application/InsertListener.java create mode 100644 src/de/todesbaum/jsite/application/Node.java create mode 100644 src/de/todesbaum/jsite/application/Project.java create mode 100644 src/de/todesbaum/jsite/application/ProjectInserter.java create mode 100644 src/de/todesbaum/jsite/gui/FileScanner.java create mode 100644 src/de/todesbaum/jsite/gui/FileScannerListener.java create mode 100644 src/de/todesbaum/jsite/gui/NodeManagerListener.java create mode 100644 src/de/todesbaum/jsite/gui/NodeManagerPage.java create mode 100644 src/de/todesbaum/jsite/gui/ProjectFilesPage.java create mode 100644 src/de/todesbaum/jsite/gui/ProjectInsertPage.java create mode 100644 src/de/todesbaum/jsite/gui/ProjectPage.java create mode 100644 src/de/todesbaum/jsite/i18n/I18n.java create mode 100644 src/de/todesbaum/jsite/i18n/jSite.properties create mode 100644 src/de/todesbaum/jsite/i18n/jSite_de.properties create mode 100644 src/de/todesbaum/jsite/main/CLI.java create mode 100644 src/de/todesbaum/jsite/main/Configuration.java create mode 100644 src/de/todesbaum/jsite/main/Main.java create mode 100644 src/de/todesbaum/jsite/main/Version.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/Client.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/ClientHello.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/ClientPut.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/ClientPutComplexDir.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/ClientPutDir.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/Command.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/Connection.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/ConnectionListener.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/DirectFileEntry.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/DiskFileEntry.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/FileEntry.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/GenerateSSK.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/Message.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/Node.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/Persistence.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/PriorityClass.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/RedirectFileEntry.java create mode 100644 src/de/todesbaum/util/freenet/fcp2/Verbosity.java create mode 100644 src/de/todesbaum/util/image/IconLoader.java create mode 100644 src/de/todesbaum/util/io/LineInputStream.java create mode 100644 src/de/todesbaum/util/io/ReplacingOutputStream.java create mode 100644 src/de/todesbaum/util/io/StreamCopier.java create mode 100644 src/de/todesbaum/util/io/TempFileInputStream.java create mode 100644 src/de/todesbaum/util/mime/DefaultMIMETypes.java create mode 100644 src/de/todesbaum/util/swing/SortedListModel.java create mode 100644 src/de/todesbaum/util/swing/TLabel.java create mode 100644 src/de/todesbaum/util/swing/TWizard.java create mode 100644 src/de/todesbaum/util/swing/TWizardPage.java create mode 100644 src/de/todesbaum/util/swing/WizardListener.java create mode 100644 src/de/todesbaum/util/xml/SimpleXML.java create mode 100644 src/de/todesbaum/util/xml/XML.java diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..60549be --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..f20fcb4 --- /dev/null +++ b/build.xml @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/jsite-icon.png b/images/jsite-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fcddf6c7f3201887e53f77b9ee59d6561e7b1332 GIT binary patch literal 4838 zcmV-M?etdfkGi+}_RZ~1f^z1MdB1ah=hm&hw{CsE z^{c91RsC8>Dfw3x+du2WLWmS0g#DlO{YX8|qy-2e(ts;~^MQPmdVmmc1UO{SeZZ$u z%FSo2V#YfD+5`w8@_?&=tAXKw`!tK%2P^^>0&As|pQp&ntrNVl>e<=Y%h(5s6z-aSt=k|m0D`4ah zD9nT0Ot1@-;fH`=^jcR7m4{$U1uR+%i`PRxQ;-Qrh2XQF~G=YbhJBou#Snh zZfE7H8bTLKxRB^@u@S^l7(Nshz5{7a61IBGRnw*hxcE8Pcp&oeoxr71%F5FwKnRfo zYzA@w{_>ZOOr2T?Bx|Y@pp#%EK<@%U-g>Kod+z;~K$gTmDhyc`A3F@Tzd?o*R{R~x zdc`5Y0=%w=j>37*!J*nnsmp+|t$B`#y1-*P`0?Y@nKGpaNJCkfuEuT<+Z_%Zurczo z)!cUHH#A%r!hcg7@Bq0Gz8$JN!hqrM{Od%GO24+E`I)e25+pk#r49#vFNAO;BEZrD zgb=-eZGgQ~Cp$m<&<~Ht3#4jlv;sHE3LGdt1v6%BWbz*t6U+|dzci#;ErqDtbPBc9 z*{|{6Bdm-l57@4{#IQlIa5{KgShjdPeP${Ac}WDy7GRo`a$b80SOAm*y!>((?z*ch zs`b+}0#YjS{%fv^LphRiHjHVgXqFo5)-2=!SL;A?;$Ps4#zfa;5H05heO>#YcA(FKGM zgLLqvr7mu}tuv~n^;S>ONYJ}OI(k=Fy6k7xuKt1Uy*kmWM;^tQS(KG^A=%@E5Qw=> z>|dnPqx@|K-hYzb*DWHWco_I4LcqD_+UQjP`ALxKRny#r2jTDuqHc!KU7^;fCk%`vV9e z>DV!q6|1*X9SGvG<0s_f=mk{>R|9-CnH9L@cY8-+zuyCDCaT5 z1M~k1j$oXYH|2$!pzI~s5_OW^0^XBSt}qi2Ge8I-Is(H0`u9&_?AT7I{_Qqgb!*VO zf!-zDI2=y0vIO_t_aEfscqlE+qPqGR-AnHy+0&iAH?P8(mIHvV`bT!m9feE_t0L>c z?G}s};b8EEe(*ungxDaZjLs8g0#Ivu z8^8@WWDxZ_oJ6NQorEL<0lFo)02`NGHWFy2qN0LfBOb$*)sH?mF2#|Q0YJmy@7eXi zHH7VrkQs(1Rp|%_vRKYy-!R*ANHiNi#L%Joj3E2b|$j%}UGxCu*Hx2TzJIfjC)Ja=iGPIW>5 zeE4EN0G&|ubrnLm^j#z)0iE?kL4n>ZiTAP!3o~gtxtE3`n@P<*Cm{i@^v;x)&u)<) zY^vty=C?VqV;;`TQu++Mht#|>g1#DlTJi~Z{aJa0Zk=}>q%oat(poI#O`S|1&-#RXxSn_=rt7|;`IL$o5qKt$�iYb2dZ1J%z~~9)1Ei-5($aL`=B*l| z=h1}S?qm6~KQU?2Nb<4-dq2K|#$!9$MSxivk8Wenf?McT=%c8MBsCdI3Q>lbs7J;j zr?aO80RSEJj20Hqxic2Pb@0aZzYU)+$m-QwNJ+7As?JYZP9NOfqF+S7i5>GvO>=gzc$R^s1sJa}1atz($&nVIeSnkd>M$ENRPxO?r&zP@IBP!N zM<^u8C>}zG^QV$iHVM1SID@ob(u;<$|MUOm_;Gmg73fo>Rl|I~U`0gOaIZ;DY<2WI zO9E68j61UwcSbQu z8O6B0MYuDHae49)HtW;zZdXpn+wD@`S#&FlmNxOk-F_yH(ufGra&j_Tfx!YQV?2M1 zyF(tJIkFlQLM%ZYWz$p#NofwYY)R&vvU<9WdY#<b|CJ0UCy2mBxtCYk%V+VXH1qgGKNBwlSBS(LBZhOLhgQJT>ms)^fP-54O)2F;vjwQce(2US zNM&UcHk%Eb-A#Sv2AWRprMluHPVAVE!)Yfk$3|}VOgtVJp^&ottSmPrB_29;a^rTx z;lqvm&nrK0%HdNzP&+P=;V}N@gB;m0gTvoW$L2^Pv*&2CdS6S2k}I&gJ=opp6kPlW z`2+9a(E69S=jCUa@@6w{+~udd%wPd=S|6Y?c1O^7R}Y5$03pQVz#{;w7sJqDfD0!7 z(aEc?LC_z->2{HxZX+*8ke%(qX0wr!;^4|Fb2$I}OiD^TcsvfGHmRo5o_*I*(WMCn z01XDM2Wo+xAdZ65WhWR^<3^`*CQvYRDz5a1e@3XemV@h_rE=X<+;p*I#srDe${Gw~ zz_3}cdLL-H)3i!~+A0efEnv5vSho&_4p!+GUkH$wYiIFd2W~fnLI8q({Tz%LlgZ%0 z9dI~w)2%lY7bPIlEOw$BNJi-hVgYn54AChQPFBOuyJz$5_p>M+^ETOiuUD_T(^q&Wy1BX&)-0eq7laACB7EYumB{roamznqw9|K~~@ zyLLIr&URB<gy6zAbLtwzWPP>e=^4D!K$63AowReRT3Ho%Y$&x+r+jk?kUjv_N>7!E0*TCQjN-0kO z>j1v_9u8L$voBwi7v}Oyo9W-bf$VJEc260!#&E4M<(WEWJdr>UO7dXhXxKO#{%cH_ z1FIip@5gtj6{IGv^e&W)nZu?7lDp>w_^qKn1a_5V3|B0;H5bp^n2?x)#1# zPyD&oXSy~6KB+0O+7|r!uwjZ0(bJ>PfzKcIV>`8#E&qESzUrUw*B+$d$QF_vEj&J^ zu8O(cX-GE`^#v@C#-7m=4?K%?H?Sfhk+!i1=wm>P)fv`h=M}*B5BtfG2iY?H9JaoB z5oyjaozfsLEn3WqA7RX2k4jWM*!u$G!7*^xICuR6~s0{%+T0^0F9l<2H!(3s%{?d5W*6; z`Mx~_B(MNoJ2+waEiic?5R4ZZW3UdVgvl4c2jk$nzUuYE^>BY|>&M=~8YyM4RRT15K>Hk1 zXTXQcNZb_?S;Ogc0rL!Gwg{8>f>8c`%*ekL!(fM+k2jd#i%Wo%aw~AVO2f@h!1vqZ z0Bmh6XfFX);EmnDLMAPO^-;J-fsaj(th9$Z4#Ncuam$gw1t+j#f>CbOr=u7BP-#_ z$gvtB-~-gc$C$S`9=NuK$)y9EfbIb4$uRd`7^NR;8IP=tzzn+iCs@0~kZ0V#)6*gN zZExu2HG#K~dOzIwAuQSzll_ra&zL+Z<#%zhwIfnA3-}B;8&r!u{qJ!9XyOx~U*mwa z44yU~MZ|HS_SLAP@2%1E{~!wd7Sp3&Nhy~l#MPcyVWGl8m!Jhu01PgL=dXu>C8meX z2NhQPc4iWShO~t=2H=G+;khrNF51KEP|lkn%=`|ftb#+aTU?bW@a9msDqyyhvYA%obi?Icz(c^DXrXif zE<4;Z5XP6m&=PRy17185bkK3CaIh8@?tq^T3`?`7%j%YC{8=%YAd!pkGkfjK|=tl>Y%DVdaZ6Uza5buQLb&3#cu&% zfs}Hm#czr0|7-kdN(hmS8W{VbrpjKZNQ{(UP^?7t@m-o8kMrD4V1<564HMlcuR*QYcGGfjGs=Eoxs>u?f@fN<^O^YLq!zAz zF@~4}gSdzW8v0S78)*BA;Sg$7x4YFR+aPE9pQB!s1@r`pIlaH?hES2kyHUG2wTT~Z zpPW$wVm>5<8x@+8MQq5q2Q^kSqDtrue if this interface already has a node set, + * false otherwise + */ + public boolean hasNode() { + return (node != null) && (connection != null); + } + +} diff --git a/src/de/todesbaum/jsite/application/InsertListener.java b/src/de/todesbaum/jsite/application/InsertListener.java new file mode 100644 index 0000000..0966e10 --- /dev/null +++ b/src/de/todesbaum/jsite/application/InsertListener.java @@ -0,0 +1,40 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.application; + +import java.util.EventListener; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: InsertListener.java 397 2006-03-25 16:11:34Z bombe $ + */ +public interface InsertListener extends EventListener { + + public static enum ErrorType { + KEY_COLLISION, ROUTE_NOT_FOUND, DATA_NOT_FOUND, FCP_ERROR, IO_ERROR + } + + public void projectInsertStarted(Project project); + + public void projectInsertProgress(Project project, int succeeded, int failed, int fatal, int total, boolean finalized); + + public void projectInsertFinished(Project project, boolean success, Throwable cause); + +} diff --git a/src/de/todesbaum/jsite/application/Node.java b/src/de/todesbaum/jsite/application/Node.java new file mode 100644 index 0000000..7db0cb0 --- /dev/null +++ b/src/de/todesbaum/jsite/application/Node.java @@ -0,0 +1,97 @@ +/* + * jSite-0.7 - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.application; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: Node.java 419 2006-03-29 17:49:46Z bombe $ + */ +public class Node extends de.todesbaum.util.freenet.fcp2.Node { + + protected String name; + + /** + * @param hostname + */ + public Node(String hostname) { + this(hostname, DEFAULT_PORT); + } + + /** + * @param hostname + * @param port + */ + public Node(String hostname, int port) { + this(hostname, port, ""); + } + + public Node(String hostname, int port, String name) { + super(hostname, port); + this.name = name; + } + + public Node(Node node) { + this(node.getHostname(), node.getPort()); + } + + public Node(Node node, String name) { + this(node.getHostname(), node.getPort(), name); + } + + /** + * @param name + * The name to set. + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public void setPort(int port) { + this.port = port; + } + + public boolean equals(Object o) { + if ((o == null) || !(o instanceof Node)) { + return false; + } + Node node = (Node) o; + return name.equals(node.name) && hostname.equals(node.hostname) && (port == node.port); + } + + public int hashCode() { + return name.hashCode() ^ hostname.hashCode() ^ port; + } + + public String toString() { + return name + " (" + hostname + ":" + port + ")"; + } + +} diff --git a/src/de/todesbaum/jsite/application/Project.java b/src/de/todesbaum/jsite/application/Project.java new file mode 100644 index 0000000..0f28ef3 --- /dev/null +++ b/src/de/todesbaum/jsite/application/Project.java @@ -0,0 +1,243 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.application; + +import java.io.File; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import de.todesbaum.util.mime.DefaultMIMETypes; + +/** + * @author David Roden + * @version $Id: Project.java 357 2006-03-24 15:46:03Z bombe $ + */ +public abstract class Project implements Comparable { + + protected String name; + protected String description; + + protected String insertURI; + protected String requestURI; + + protected String indexFile; + protected String localPath; + protected String path; + protected long lastInsertionTime; + + protected Map fileOptions = new HashMap(); + + public Project() { + } + + /** + * Clone-constructor. + * + * @param project + */ + public Project(Project project) { + name = project.name; + description = project.description; + insertURI = project.insertURI; + requestURI = project.requestURI; + path = project.path; + localPath = project.localPath; + indexFile = project.indexFile; + lastInsertionTime = project.lastInsertionTime; + fileOptions = new HashMap(project.fileOptions); + } + + /** + * @return Returns the title. + */ + public String getName() { + return name; + } + + /** + * @param title + * The title to set. + */ + public void setName(String title) { + this.name = title; + } + + /** + * @return Returns the description. + */ + public String getDescription() { + return description; + } + + /** + * @param description + * The description to set. + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * @return Returns the localPath. + */ + public String getLocalPath() { + return localPath; + } + + /** + * @param localPath + * The localPath to set. + */ + public void setLocalPath(String localPath) { + this.localPath = localPath; + } + + /** + * @return Returns the indexFile. + */ + public String getIndexFile() { + return indexFile; + } + + /** + * @param indexFile + * The indexFile to set. + */ + public void setIndexFile(String indexFile) { + this.indexFile = indexFile; + } + + /** + * @return Returns the lastInserted. + */ + public long getLastInsertionTime() { + return lastInsertionTime; + } + + /** + * @param lastInserted + * The lastInserted to set. + */ + public void setLastInsertionTime(long lastInserted) { + this.lastInsertionTime = lastInserted; + } + + /** + * @return Returns the name. + */ + public String getPath() { + return path; + } + + /** + * @param name + * The name to set. + */ + public void setPath(String name) { + this.path = name; + } + + /** + * @return Returns the insertURI. + */ + public String getInsertURI() { + return insertURI; + } + + /** + * @param insertURI + * The insertURI to set. + */ + public void setInsertURI(String insertURI) { + this.insertURI = insertURI; + } + + /** + * @return Returns the requestURI. + */ + public String getRequestURI() { + return requestURI; + } + + /** + * @param requestURI + * The requestURI to set. + */ + public void setRequestURI(String requestURI) { + this.requestURI = requestURI; + } + + public String toString() { + return name; + } + + public String shortenFilename(File file) { + String filename = file.getPath(); + if (filename.startsWith(localPath)) { + filename = filename.substring(localPath.length()); + if (filename.startsWith(File.separator)) { + filename = filename.substring(1); + } + } + return filename; + } + + public FileOption getFileOption(String filename) { + FileOption fileOption = fileOptions.get(filename); + if (fileOption == null) { + fileOption = new FileOption(DefaultMIMETypes.guessMIMEType(filename)); + fileOptions.put(filename, fileOption); + } + return fileOption; + } + + public void setFileOption(String filename, FileOption fileOption) { + fileOptions.put(filename, fileOption); + } + + /** + * @return Returns the fileOptions. + */ + public Map getFileOptions() { + return Collections.unmodifiableMap(fileOptions); + } + + /** + * @param fileOptions + * The fileOptions to set. + */ + public void setFileOptions(Map fileOptions) { + this.fileOptions.clear(); + this.fileOptions.putAll(fileOptions); + } + + public String getFinalURI(int editionOffset) { + return requestURI + path + "/"; + } + + /** + * {@inheritDoc} + */ + public int compareTo(Object o) { + return name.compareToIgnoreCase(((Project) o).name); + } + +} diff --git a/src/de/todesbaum/jsite/application/ProjectInserter.java b/src/de/todesbaum/jsite/application/ProjectInserter.java new file mode 100644 index 0000000..8ec92db --- /dev/null +++ b/src/de/todesbaum/jsite/application/ProjectInserter.java @@ -0,0 +1,328 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.application; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +import de.todesbaum.jsite.gui.FileScanner; +import de.todesbaum.jsite.gui.FileScannerListener; +import de.todesbaum.util.freenet.fcp2.Client; +import de.todesbaum.util.freenet.fcp2.ClientPutComplexDir; +import de.todesbaum.util.freenet.fcp2.Connection; +import de.todesbaum.util.freenet.fcp2.DirectFileEntry; +import de.todesbaum.util.freenet.fcp2.FileEntry; +import de.todesbaum.util.freenet.fcp2.Message; +import de.todesbaum.util.freenet.fcp2.RedirectFileEntry; +import de.todesbaum.util.freenet.fcp2.Verbosity; +import de.todesbaum.util.io.ReplacingOutputStream; +import de.todesbaum.util.io.StreamCopier; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: ProjectInserter.java 440 2006-03-30 09:31:25Z bombe $ + */ +public class ProjectInserter implements FileScannerListener, Runnable { + + private static int counter = 0; + private boolean debug = false; + private List insertListeners = new ArrayList(); + protected Freenet7Interface freenetInterface; + protected Project project; + private FileScanner fileScanner; + protected final Object lockObject = new Object(); + private int maxRetries = 99999; + + public void addInsertListener(InsertListener insertListener) { + insertListeners.add(insertListener); + } + + public void removeInsertListener(InsertListener insertListener) { + insertListeners.remove(insertListener); + } + + protected void fireProjectInsertStarted() { + for (InsertListener insertListener: insertListeners) { + insertListener.projectInsertStarted(project); + } + } + + protected void fireProjectInsertProgress(int succeeded, int failed, int fatal, int total, boolean finalized) { + for (InsertListener insertListener: insertListeners) { + insertListener.projectInsertProgress(project, succeeded, failed, fatal, total, finalized); + } + } + + protected void fireProjectInsertFinished(boolean success, Throwable cause) { + for (InsertListener insertListener: insertListeners) { + insertListener.projectInsertFinished(project, success, cause); + } + } + + /** + * @param debug + * The debug to set. + */ + public void setDebug(boolean debug) { + this.debug = debug; + } + + /** + * @param project + * The project to set. + */ + public void setProject(Project project) { + this.project = project; + } + + /** + * @param freenetInterface + * The freenetInterface to set. + */ + public void setFreenetInterface(Freenet7Interface freenetInterface) { + this.freenetInterface = freenetInterface; + } + + /** + * @param maxRetries + * The maxRetries to set. + */ + public void setMaxRetries(int maxRetries) { + this.maxRetries = maxRetries; + } + + public void start() { + fileScanner = new FileScanner(project); + fileScanner.addFileScannerListener(this); + new Thread(fileScanner).start(); + } + + private InputStream createFileInputStream(String filename, FileOption fileOption, int edition, long[] length) throws IOException { + File file = new File(project.getLocalPath(), filename); + length[0] = file.length(); + if (!fileOption.getReplaceEdition()) { + return new FileInputStream(file); + } + ByteArrayOutputStream filteredByteOutputStream = new ByteArrayOutputStream(Math.min(Integer.MAX_VALUE, (int) length[0])); + ReplacingOutputStream outputStream = new ReplacingOutputStream(filteredByteOutputStream); + FileInputStream fileInput = new FileInputStream(file); + outputStream.addReplacement("$[CONTAINER]", "/"); + outputStream.addReplacement("$[EDITION]", String.valueOf(edition)); + outputStream.addReplacement("$[URI]", project.getFinalURI(0)); + for (int index = 1; index <= fileOption.getEditionRange(); index++) { + outputStream.addReplacement("$[URI+" + index + "]", project.getFinalURI(index)); + outputStream.addReplacement("$[URI+" + index + "]", project.getFinalURI(index)); + } + StreamCopier.copy(fileInput, outputStream, length[0]); + outputStream.close(); + filteredByteOutputStream.close(); + byte[] filteredBytes = filteredByteOutputStream.toByteArray(); + length[0] = filteredBytes.length; + return new ByteArrayInputStream(filteredBytes); + } + + private InputStream createContainerInputStream(Map> containerFiles, String containerName, int edition, long[] containerLength) throws IOException { + File tempFile = File.createTempFile("jsite", ".zip"); + tempFile.deleteOnExit(); + FileOutputStream fileOutputStream = new FileOutputStream(tempFile); + ZipOutputStream zipOutputStream = new ZipOutputStream(fileOutputStream); + for (String filename: containerFiles.get(containerName)) { + File dataFile = new File(project.getLocalPath(), filename); + if (dataFile.exists()) { + ZipEntry zipEntry = new ZipEntry(filename); + long[] fileLength = new long[1]; + InputStream wrappedInputStream = createFileInputStream(filename, project.getFileOption(filename), edition, fileLength); + zipOutputStream.putNextEntry(zipEntry); + StreamCopier.copy(wrappedInputStream, zipOutputStream, fileLength[0]); + zipOutputStream.closeEntry(); + wrappedInputStream.close(); + } + } + zipOutputStream.closeEntry(); + + /* FIXME - create metadata */ + // ZipEntry metadataEntry = new ZipEntry("metadata"); + // zipOutputStream.putNextEntry(metadataEntry); + // Metadata zipMetadata = new Metadata(); + // for (String filename: containerFiles.get(containerName)) { + // if (new File(project.getLocalPath(), filename).exists()) { + // DocumentMetadata zipEntryMetadata = new DocumentMetadata(); + // zipEntryMetadata.setName(filename); + // zipEntryMetadata.setFormat(project.getFileOption(filename).getMimeType()); + // zipMetadata.addDocument(zipEntryMetadata); + // } + // } + // zipOutputStream.write(zipMetadata.toByteArray()); + // zipOutputStream.closeEntry(); + zipOutputStream.close(); + + containerLength[0] = tempFile.length(); + return new FileInputStream(tempFile); + } + + private FileEntry createFileEntry(String filename, int edition, Map> containerFiles) { + FileEntry fileEntry = null; + FileOption fileOption = project.getFileOption(filename); + if (filename.startsWith("/container/:")) { + String containerName = filename.substring("/container/:".length()); + try { + long[] containerLength = new long[1]; + InputStream containerInputStream = createContainerInputStream(containerFiles, containerName, edition, containerLength); + fileEntry = new DirectFileEntry(containerName + ".zip", "application/zip", containerInputStream, containerLength[0]); + } catch (IOException ioe1) { + } + } else { + if (fileOption.isInsert()) { + try { + long[] fileLength = new long[1]; + InputStream fileEntryInputStream = createFileInputStream(filename, fileOption, edition, fileLength); + fileEntry = new DirectFileEntry(filename, project.getFileOption(filename).getMimeType(), fileEntryInputStream, fileLength[0]); + } catch (IOException ioe1) { + } + } else { + fileEntry = new RedirectFileEntry(filename, fileOption.getMimeType(), fileOption.getCustomKey()); + } + } + return fileEntry; + } + + private void createContainers(List files, List containers, Map> containerFiles) { + for (String filename: new ArrayList(files)) { + FileOption fileOption = project.getFileOption(filename); + String containerName = fileOption.getContainer(); + if (!containerName.equals("")) { + if (!containers.contains(containerName)) { + containers.add(containerName); + containerFiles.put(containerName, new ArrayList()); + /* hmm. looks like a hack to me. */ + files.add("/container/:" + containerName); + } + containerFiles.get(containerName).add(filename); + files.remove(filename); + } + } + } + + /** + * {@inheritDoc} + */ + public void run() { + fireProjectInsertStarted(); + List files = fileScanner.getFiles(); + + /* create connection to node */ + Connection connection = freenetInterface.getConnection("project-insert-" + counter++); + try { + connection.connect(); + } catch (IOException e1) { + fireProjectInsertFinished(false, e1); + return; + } + Client client = new Client(connection); + + /* create containers */ + final List containers = new ArrayList(); + final Map> containerFiles = new HashMap>(); + createContainers(files, containers, containerFiles); + + /* collect files */ + int edition = ((EditionProject) project).getEdition(); + String dirURI = project.getInsertURI() + project.getPath() + "-" + edition; + ClientPutComplexDir putDir = new ClientPutComplexDir("dir-" + counter++, dirURI); + putDir.setDefaultName(project.getIndexFile()); + putDir.setVerbosity(Verbosity.ALL); + putDir.setMaxRetries(maxRetries); + for (String filename: files) { + FileEntry fileEntry = createFileEntry(filename, edition, containerFiles); + if (fileEntry != null) { + putDir.addFileEntry(fileEntry); + } + } + + /* start request */ + try { + client.execute(putDir); + } catch (IOException ioe1) { + fireProjectInsertFinished(false, ioe1); + return; + } + + /* parse progress and success messages */ + boolean success = true; + boolean finished = false; + boolean disconnected = false; + while (!finished) { + Message message = client.readMessage(); + finished = (message == null) && (disconnected = client.isDisconnected()); + if (debug) { + System.out.println(message); + } + if (!finished) { + String messageName = message.getName(); + if ("SimpleProgress".equals(messageName)) { + int total = Integer.parseInt(message.get("Total")); + int succeeded = Integer.parseInt(message.get("Succeeded")); + int fatal = Integer.parseInt(message.get("FatallyFailed")); + int failed = Integer.parseInt(message.get("Failed")); + boolean finalized = Boolean.parseBoolean(message.get("FinalizedTotal")); + fireProjectInsertProgress(succeeded, failed, fatal, total, finalized); + } + success = "PutSuccessful".equals(messageName); + finished = success || "PutFailed".equals(messageName); + } + } + + /* post-insert work */ + fireProjectInsertFinished(success, disconnected ? new IOException("Connection terminated") : null); + if (success) { + if (project instanceof EditionProject) { + ((EditionProject) project).setEdition(edition + 1); + } + } + } + + // + // INTERFACE FileScannerListener + // + + /** + * {@inheritDoc} + */ + public void fileScannerFinished(FileScanner fileScanner) { + if (!fileScanner.isError()) { + new Thread(this).start(); + } else { + fireProjectInsertFinished(false, null); + } + fileScanner.removeFileScannerListener(this); + } + +} diff --git a/src/de/todesbaum/jsite/gui/FileScanner.java b/src/de/todesbaum/jsite/gui/FileScanner.java new file mode 100644 index 0000000..1b63fcd --- /dev/null +++ b/src/de/todesbaum/jsite/gui/FileScanner.java @@ -0,0 +1,97 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.gui; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import de.todesbaum.jsite.application.Project; +import de.todesbaum.jsite.i18n.I18n; + +public class FileScanner implements Runnable { + + private final List fileScannerListeners = new ArrayList(); + private final Project project; + private List files; + private boolean error = false; + + public FileScanner(Project project) { + this.project = project; + } + + public void addFileScannerListener(FileScannerListener fileScannerListener) { + fileScannerListeners.add(fileScannerListener); + } + + public void removeFileScannerListener(FileScannerListener fileScannerListener) { + fileScannerListeners.remove(fileScannerListener); + } + + protected void fireFileScannerFinished() { + for (FileScannerListener fileScannerListener: new ArrayList(fileScannerListeners)) { + fileScannerListener.fileScannerFinished(this); + } + } + + public void run() { + files = new ArrayList(); + error = false; + try { + scanFiles(new File(project.getLocalPath()), files); + Collections.sort(files); + } catch (IOException ioe1) { + error = true; + } + fireFileScannerFinished(); + } + + public boolean isError() { + return error; + } + + public List getFiles() { + return files; + } + + private void scanFiles(File rootDir, List fileList) throws IOException { + File[] files = rootDir.listFiles(new FileFilter() { + + public boolean accept(File file) { + return !file.isHidden(); + } + }); + if (files == null) { + throw new IOException(I18n.getMessage("jsite.file-scanner.can-not-read-directory")); + } + for (File file: files) { + if (file.isDirectory()) { + scanFiles(file, fileList); + continue; + } + String filename = project.shortenFilename(file); + fileList.add(filename); + } + } + +} \ No newline at end of file diff --git a/src/de/todesbaum/jsite/gui/FileScannerListener.java b/src/de/todesbaum/jsite/gui/FileScannerListener.java new file mode 100644 index 0000000..b8e373b --- /dev/null +++ b/src/de/todesbaum/jsite/gui/FileScannerListener.java @@ -0,0 +1,28 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.gui; + +import java.util.EventListener; + +public interface FileScannerListener extends EventListener { + + public void fileScannerFinished(FileScanner fileScanner); + +} \ No newline at end of file diff --git a/src/de/todesbaum/jsite/gui/NodeManagerListener.java b/src/de/todesbaum/jsite/gui/NodeManagerListener.java new file mode 100644 index 0000000..039561e --- /dev/null +++ b/src/de/todesbaum/jsite/gui/NodeManagerListener.java @@ -0,0 +1,35 @@ +/* + * jSite-0.7 - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.gui; + +import java.util.EventListener; + +import de.todesbaum.jsite.application.Node; + + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: NodeManagerListener.java 418 2006-03-29 17:49:16Z bombe $ + */ +public interface NodeManagerListener extends EventListener { + + public void nodesUpdated(Node[] nodes); + +} diff --git a/src/de/todesbaum/jsite/gui/NodeManagerPage.java b/src/de/todesbaum/jsite/gui/NodeManagerPage.java new file mode 100644 index 0000000..9b1c80a --- /dev/null +++ b/src/de/todesbaum/jsite/gui/NodeManagerPage.java @@ -0,0 +1,321 @@ +/* + * jSite-0.7 - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.gui; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; +import javax.swing.SpinnerNumberModel; +import javax.swing.border.EmptyBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; + +import de.todesbaum.jsite.application.Node; +import de.todesbaum.jsite.i18n.I18n; +import de.todesbaum.util.swing.TLabel; +import de.todesbaum.util.swing.TWizard; +import de.todesbaum.util.swing.TWizardPage; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: NodeManagerPage.java 418 2006-03-29 17:49:16Z bombe $ + */ +public class NodeManagerPage extends TWizardPage implements ListSelectionListener, DocumentListener, ChangeListener { + + private List nodeManagerListeners = new ArrayList(); + private TWizard wizard; + + private Action addNodeAction; + private Action deleteNodeAction; + private DefaultListModel nodeListModel; + private JList nodeList; + private JTextField nodeNameTextField; + private JTextField nodeHostnameTextField; + private JSpinner nodePortSpinner; + + public NodeManagerPage() { + super(); + pageInit(); + setHeading(I18n.getMessage("jsite.node-manager.heading")); + setDescription(I18n.getMessage("jsite.node-manager.description")); + } + + public void addNodeManagerListener(NodeManagerListener nodeManagerListener) { + nodeManagerListeners.add(nodeManagerListener); + } + + public void removeNodeManagerListener(NodeManagerListener nodeManagerListener) { + nodeManagerListeners.remove(nodeManagerListener); + } + + protected void fireNodesUpdated(Node[] nodes) { + for (NodeManagerListener nodeManagerListener: nodeManagerListeners) { + nodeManagerListener.nodesUpdated(nodes); + } + } + + private void createActions() { + addNodeAction = new AbstractAction(I18n.getMessage("jsite.node-manager.add-node")) { + + public void actionPerformed(ActionEvent actionEvent) { + addNode(); + } + }; + + deleteNodeAction = new AbstractAction(I18n.getMessage("jsite.node-manager.delete-node")) { + + public void actionPerformed(ActionEvent actionEvent) { + deleteNode(); + } + }; + deleteNodeAction.setEnabled(false); + } + + private void pageInit() { + createActions(); + nodeListModel = new DefaultListModel(); + nodeList = new JList(nodeListModel); + nodeList.setName("node-list"); + nodeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + nodeList.addListSelectionListener(this); + nodeList.setPreferredSize(new Dimension(250, -1)); + + nodeNameTextField = new JTextField(""); + nodeNameTextField.getDocument().putProperty("Name", "node-name"); + nodeNameTextField.getDocument().addDocumentListener(this); + nodeNameTextField.setEnabled(false); + + nodeHostnameTextField = new JTextField("localhost"); + nodeHostnameTextField.getDocument().putProperty("Name", "node-hostname"); + nodeHostnameTextField.getDocument().addDocumentListener(this); + nodeHostnameTextField.setEnabled(false); + + nodePortSpinner = new JSpinner(new SpinnerNumberModel(9481, 1, 65535, 1)); + nodePortSpinner.setName("node-port"); + nodePortSpinner.addChangeListener(this); + nodePortSpinner.setEnabled(false); + + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12)); + buttonPanel.setBorder(new EmptyBorder(-12, -12, -12, -12)); + buttonPanel.add(new JButton(addNodeAction)); + buttonPanel.add(new JButton(deleteNodeAction)); + + JPanel centerPanel = new JPanel(new BorderLayout()); + JPanel nodeInformationPanel = new JPanel(new GridBagLayout()); + centerPanel.add(nodeInformationPanel, BorderLayout.PAGE_START); + nodeInformationPanel.add(buttonPanel, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); + nodeInformationPanel.add(new JLabel("" + I18n.getMessage("jsite.node-manager.node-information") + ""), new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 0, 0, 0), 0, 0)); + nodeInformationPanel.add(new TLabel(I18n.getMessage("jsite.node-manager.name"), KeyEvent.VK_N, nodeNameTextField), new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + nodeInformationPanel.add(nodeNameTextField, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + nodeInformationPanel.add(new TLabel(I18n.getMessage("jsite.node-manager.hostname"), KeyEvent.VK_H, nodeHostnameTextField), new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + nodeInformationPanel.add(nodeHostnameTextField, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + nodeInformationPanel.add(new TLabel(I18n.getMessage("jsite.node-manager.port"), KeyEvent.VK_P, nodePortSpinner), new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + nodeInformationPanel.add(nodePortSpinner, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 6, 0, 0), 0, 0)); + + setLayout(new BorderLayout(12, 12)); + add(new JScrollPane(nodeList), BorderLayout.LINE_START); + add(centerPanel, BorderLayout.CENTER); + } + + /** + * {@inheritDoc} + */ + @Override + public void pageAdded(TWizard wizard) { + this.wizard = wizard; + wizard.setNextEnabled(nodeListModel.getSize() > 0); + } + + public void setNodes(Node[] nodes) { + nodeListModel.clear(); + for (Node node: nodes) { + nodeListModel.addElement(node); + } + nodeList.repaint(); + fireNodesUpdated(nodes); + } + + public Node[] getNodes() { + Node[] returnNodes = new Node[nodeListModel.getSize()]; + for (int nodeIndex = 0, nodeCount = nodeListModel.getSize(); nodeIndex < nodeCount; nodeIndex++) { + returnNodes[nodeIndex] = (Node) nodeListModel.get(nodeIndex); + } + return returnNodes; + } + + private Node getSelectedNode() { + return (Node) nodeList.getSelectedValue(); + } + + private void updateTextField(DocumentEvent documentEvent) { + Node node = getSelectedNode(); + if (node == null) { + return; + } + Document document = documentEvent.getDocument(); + String documentText = null; + try { + documentText = document.getText(0, document.getLength()); + } catch (BadLocationException ble1) { + } + if (documentText == null) { + return; + } + String documentName = (String) document.getProperty("Name"); + if ("node-name".equals(documentName)) { + node.setName(documentText); + nodeList.repaint(); + fireNodesUpdated(getNodes()); + } else if ("node-hostname".equals(documentName)) { + node.setHostname(documentText); + nodeList.repaint(); + } + } + + // + // ACTIONS + // + + protected void addNode() { + Node node = new Node("localhost", 9481, I18n.getMessage("jsite.node-manager.new-node")); + nodeListModel.addElement(node); + wizard.setNextEnabled(true); + fireNodesUpdated(getNodes()); + } + + protected void deleteNode() { + Node node = getSelectedNode(); + if (node == null) { + return; + } + if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.node-manager.delete-node.warning"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.CANCEL_OPTION) { + return; + } + nodeListModel.removeElement(node); + nodeList.repaint(); + fireNodesUpdated(getNodes()); + wizard.setNextEnabled(nodeListModel.size() > 0); + } + + // + // INTERFACE ListSelectionListener + // + + /** + * {@inheritDoc} + */ + public void valueChanged(ListSelectionEvent e) { + Object source = e.getSource(); + if (source instanceof JList) { + JList sourceList = (JList) source; + if ("node-list".equals(sourceList.getName())) { + Node node = (Node) sourceList.getSelectedValue(); + boolean enabled = (node != null); + nodeNameTextField.setEnabled(enabled); + nodeHostnameTextField.setEnabled(enabled); + nodePortSpinner.setEnabled(enabled); + deleteNodeAction.setEnabled(enabled); + if (enabled) { + nodeNameTextField.setText(node.getName()); + nodeHostnameTextField.setText(node.getHostname()); + nodePortSpinner.setValue(node.getPort()); + } else { + nodeNameTextField.setText(""); + nodeHostnameTextField.setText("localhost"); + nodePortSpinner.setValue(9481); + } + } + } + } + + // + // INTERFACE DocumentListener + // + + /** + * {@inheritDoc} + */ + public void insertUpdate(DocumentEvent e) { + updateTextField(e); + } + + /** + * {@inheritDoc} + */ + public void removeUpdate(DocumentEvent e) { + updateTextField(e); + } + + /** + * {@inheritDoc} + */ + public void changedUpdate(DocumentEvent e) { + updateTextField(e); + } + + // + // INTERFACE ChangeListener + // + + /** + * {@inheritDoc} + */ + public void stateChanged(ChangeEvent e) { + Object source = e.getSource(); + Node selectedNode = getSelectedNode(); + if (selectedNode == null) { + return; + } + if (source instanceof JSpinner) { + JSpinner sourceSpinner = (JSpinner) source; + if ("node-port".equals(sourceSpinner.getName())) { + selectedNode.setPort((Integer) sourceSpinner.getValue()); + nodeList.repaint(); + } + } + } + +} diff --git a/src/de/todesbaum/jsite/gui/ProjectFilesPage.java b/src/de/todesbaum/jsite/gui/ProjectFilesPage.java new file mode 100644 index 0000000..1b5b8c6 --- /dev/null +++ b/src/de/todesbaum/jsite/gui/ProjectFilesPage.java @@ -0,0 +1,516 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.gui; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.DefaultComboBoxModel; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; +import javax.swing.SpinnerNumberModel; +import javax.swing.SwingUtilities; +import javax.swing.border.EmptyBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; + +import de.todesbaum.jsite.application.EditionProject; +import de.todesbaum.jsite.application.FileOption; +import de.todesbaum.jsite.application.Project; +import de.todesbaum.jsite.i18n.I18n; +import de.todesbaum.util.mime.DefaultMIMETypes; +import de.todesbaum.util.swing.TLabel; +import de.todesbaum.util.swing.TWizard; +import de.todesbaum.util.swing.TWizardPage; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: ProjectFilesPage.java 404 2006-03-26 02:11:03Z bombe $ + */ +public class ProjectFilesPage extends TWizardPage implements ActionListener, ListSelectionListener, DocumentListener, FileScannerListener, ChangeListener { + + protected TWizard wizard; + + protected Project project; + + private Action scanAction; + private Action editContainerAction; + private Action addContainerAction; + private Action deleteContainerAction; + + protected JList projectFileList; + private JCheckBox defaultFileCheckBox; + private JCheckBox fileOptionsInsertCheckBox; + private JTextField fileOptionsCustomKeyTextField; + private JComboBox fileOptionsMIMETypeComboBox; + protected DefaultComboBoxModel containerComboBoxModel; + private JComboBox fileOptionsContainerComboBox; + private JSpinner replaceEditionRangeSpinner; + private JCheckBox replacementCheckBox; + + public ProjectFilesPage() { + super(); + pageInit(); + } + + private void pageInit() { + createActions(); + setLayout(new BorderLayout(12, 12)); + add(createProjectFilesPanel(), BorderLayout.CENTER); + } + + private void createActions() { + scanAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.rescan")) { + + public void actionPerformed(ActionEvent actionEvent) { + actionScan(); + } + }; + scanAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_S); + scanAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.rescan.tooltip")); + + addContainerAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.add-container")) { + + public void actionPerformed(ActionEvent actionEvent) { + actionAddContainer(); + } + }; + addContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.add-container.tooltip")); + addContainerAction.setEnabled(false); + + editContainerAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.edit-container")) { + + public void actionPerformed(ActionEvent actionEvent) { + actionEditContainer(); + } + }; + editContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.edit-container.tooltip")); + editContainerAction.setEnabled(false); + + deleteContainerAction = new AbstractAction(I18n.getMessage("jsite.project-files.action.delete-container")) { + + public void actionPerformed(ActionEvent actionEvent) { + actionDeleteContainer(); + } + }; + deleteContainerAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project-files.action.delete-container.tooltip")); + deleteContainerAction.setEnabled(false); + } + + public void pageAdded(TWizard wizard) { + this.wizard = wizard; + actionScan(); + } + + private JComponent createProjectFilesPanel() { + JPanel projectFilesPanel = new JPanel(new BorderLayout(12, 12)); + + projectFileList = new JList(); + projectFileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + projectFileList.setMinimumSize(new Dimension(250, projectFileList.getPreferredSize().height)); + projectFileList.addListSelectionListener(this); + + projectFilesPanel.add(new JScrollPane(projectFileList), BorderLayout.CENTER); + + JPanel fileOptionsAlignmentPanel = new JPanel(new BorderLayout(12, 12)); + projectFilesPanel.add(fileOptionsAlignmentPanel, BorderLayout.PAGE_END); + JPanel fileOptionsPanel = new JPanel(new GridBagLayout()); + fileOptionsAlignmentPanel.add(fileOptionsPanel, BorderLayout.PAGE_START); + + fileOptionsPanel.add(new JButton(scanAction), new GridBagConstraints(0, 0, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); + + fileOptionsPanel.add(new JLabel("" + I18n.getMessage("jsite.project-files.file-options") + ""), new GridBagConstraints(0, 1, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 0, 0, 0), 0, 0)); + + defaultFileCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.default")); + defaultFileCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.default.tooltip")); + defaultFileCheckBox.setName("default-file"); + defaultFileCheckBox.addActionListener(this); + defaultFileCheckBox.setEnabled(false); + + fileOptionsPanel.add(defaultFileCheckBox, new GridBagConstraints(0, 2, 5, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0)); + + fileOptionsInsertCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.insert"), true); + fileOptionsInsertCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.insert.tooltip")); + fileOptionsInsertCheckBox.setName("insert"); + fileOptionsInsertCheckBox.setMnemonic(KeyEvent.VK_I); + fileOptionsInsertCheckBox.addActionListener(this); + fileOptionsInsertCheckBox.setEnabled(false); + + fileOptionsPanel.add(fileOptionsInsertCheckBox, new GridBagConstraints(0, 3, 5, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + + fileOptionsCustomKeyTextField = new JTextField(45); + fileOptionsCustomKeyTextField.setToolTipText(I18n.getMessage("jsite.project-files.custom-key.tooltip")); + fileOptionsCustomKeyTextField.setEnabled(false); + fileOptionsCustomKeyTextField.getDocument().addDocumentListener(this); + + fileOptionsPanel.add(new TLabel(I18n.getMessage("jsite.project-files.custom-key"), KeyEvent.VK_K, fileOptionsCustomKeyTextField), new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + fileOptionsPanel.add(fileOptionsCustomKeyTextField, new GridBagConstraints(1, 4, 4, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + + fileOptionsMIMETypeComboBox = new JComboBox(DefaultMIMETypes.getAllMIMETypes()); + fileOptionsMIMETypeComboBox.setToolTipText(I18n.getMessage("jsite.project-files.mime-type.tooltip")); + fileOptionsMIMETypeComboBox.setName("project-files.mime-type"); + fileOptionsMIMETypeComboBox.addActionListener(this); + fileOptionsMIMETypeComboBox.setEnabled(false); + + fileOptionsPanel.add(new TLabel(I18n.getMessage("jsite.project-files.mime-type"), KeyEvent.VK_M, fileOptionsMIMETypeComboBox), new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + fileOptionsPanel.add(fileOptionsMIMETypeComboBox, new GridBagConstraints(1, 5, 4, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + + containerComboBoxModel = new DefaultComboBoxModel(); + fileOptionsContainerComboBox = new JComboBox(containerComboBoxModel); + fileOptionsContainerComboBox.setToolTipText(I18n.getMessage("jsite.project-files.container.tooltip")); + fileOptionsContainerComboBox.setName("project-files.container"); + fileOptionsContainerComboBox.addActionListener(this); + fileOptionsContainerComboBox.setEnabled(false); + + fileOptionsPanel.add(new TLabel(I18n.getMessage("jsite.project-files.container"), KeyEvent.VK_C, fileOptionsContainerComboBox), new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + fileOptionsPanel.add(fileOptionsContainerComboBox, new GridBagConstraints(1, 6, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + fileOptionsPanel.add(new JButton(addContainerAction), new GridBagConstraints(2, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + fileOptionsPanel.add(new JButton(editContainerAction), new GridBagConstraints(3, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + fileOptionsPanel.add(new JButton(deleteContainerAction), new GridBagConstraints(4, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + + JPanel fileOptionsReplacementPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 6, 6)); + fileOptionsReplacementPanel.setBorder(new EmptyBorder(-6, -6, -6, -6)); + + replacementCheckBox = new JCheckBox(I18n.getMessage("jsite.project-files.replacement")); + replacementCheckBox.setName("project-files.replace-edition"); + replacementCheckBox.setToolTipText(I18n.getMessage("jsite.project-files.replacement.tooltip")); + replacementCheckBox.addActionListener(this); + replacementCheckBox.setEnabled(false); + fileOptionsReplacementPanel.add(replacementCheckBox); + + replaceEditionRangeSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 99, 1)); + replaceEditionRangeSpinner.setName("project-files.replace-edition-range"); + replaceEditionRangeSpinner.setToolTipText(I18n.getMessage("jsite.project-files.replacement.edition-range.tooltip")); + replaceEditionRangeSpinner.addChangeListener(this); + replaceEditionRangeSpinner.setEnabled(false); + fileOptionsReplacementPanel.add(new JLabel(I18n.getMessage("jsite.project-files.replacement.edition-range"))); + fileOptionsReplacementPanel.add(replaceEditionRangeSpinner); + + fileOptionsPanel.add(fileOptionsReplacementPanel, new GridBagConstraints(0, 7, 5, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0)); + + return projectFilesPanel; + } + + public void setProject(Project project) { + this.project = project; + setHeading(MessageFormat.format(I18n.getMessage("jsite.project-files.heading"), project.getName())); + setDescription(I18n.getMessage("jsite.project-files.description")); + } + + private List getProjectFiles() { + List files = new ArrayList(); + for (int index = 0, size = projectFileList.getModel().getSize(); index < size; index++) { + files.add((String) projectFileList.getModel().getElementAt(index)); + } + return files; + } + + protected void rebuildContainerComboBox() { + /* scan files for containers */ + List files = getProjectFiles(); + List containers = new ArrayList(); // ComboBoxModel + // sucks. No + // contains()! + containers.add(""); + for (String filename: files) { + String container = project.getFileOption(filename).getContainer(); + if (!containers.contains(container)) { + containers.add(container); + } + } + Collections.sort(containers); + containerComboBoxModel.removeAllElements(); + for (String container: containers) { + containerComboBoxModel.addElement(container); + } + } + + // + // ACTIONS + // + + protected void actionScan() { + projectFileList.clearSelection(); + projectFileList.setListData(new Object[0]); + + wizard.setNextEnabled(false); + wizard.setPreviousEnabled(false); + wizard.setQuitEnabled(false); + + FileScanner fileScanner = new FileScanner(project); + fileScanner.addFileScannerListener(this); + new Thread(fileScanner).start(); + } + + protected void actionAddContainer() { + String containerName = JOptionPane.showInputDialog(wizard, I18n.getMessage("jsite.project-files.action.add-container.message") + ":", null, JOptionPane.INFORMATION_MESSAGE); + if (containerName == null) { + return; + } + containerName = containerName.trim(); + String filename = (String) projectFileList.getSelectedValue(); + FileOption fileOption = project.getFileOption(filename); + fileOption.setContainer(containerName); + rebuildContainerComboBox(); + fileOptionsContainerComboBox.setSelectedItem(containerName); + } + + protected void actionEditContainer() { + String selectedFilename = (String) projectFileList.getSelectedValue(); + FileOption fileOption = project.getFileOption(selectedFilename); + String oldContainerName = fileOption.getContainer(); + String containerName = JOptionPane.showInputDialog(wizard, I18n.getMessage("jsite.project-files.action.edit-container.message") + ":", oldContainerName); + if (containerName == null) { + return; + } + if (containerName.equals("")) { + fileOption.setContainer(""); + fileOptionsContainerComboBox.setSelectedItem(""); + return; + } + List files = getProjectFiles(); + for (String filename: files) { + fileOption = project.getFileOption(filename); + if (fileOption.getContainer().equals(oldContainerName)) { + fileOption.setContainer(containerName); + } + } + rebuildContainerComboBox(); + fileOptionsContainerComboBox.setSelectedItem(containerName); + } + + protected void actionDeleteContainer() { + if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.action.delete-container.message"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) { + String containerName = (String) fileOptionsContainerComboBox.getSelectedItem(); + List files = getProjectFiles(); + for (String filename: files) { + FileOption fileOption = project.getFileOption(filename); + if (fileOption.getContainer().equals(containerName)) { + fileOption.setContainer(""); + } + } + fileOptionsContainerComboBox.setSelectedItem(""); + } + } + + public void fileScannerFinished(FileScanner fileScanner) { + final boolean error = fileScanner.isError(); + if (!error) { + final List files = fileScanner.getFiles(); + SwingUtilities.invokeLater(new Runnable() { + + public void run() { + projectFileList.setListData(files.toArray(new String[files.size()])); + projectFileList.clearSelection(); + rebuildContainerComboBox(); + } + }); + } else { + JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.scan-error"), null, JOptionPane.ERROR_MESSAGE); + } + SwingUtilities.invokeLater(new Runnable() { + + public void run() { + wizard.setPreviousEnabled(true); + wizard.setNextEnabled(!error); + wizard.setQuitEnabled(true); + } + }); + } + + // + // INTERFACE ActionListener + // + + /** + * {@inheritDoc} + */ + public void actionPerformed(ActionEvent actionEvent) { + String filename = (String) projectFileList.getSelectedValue(); + if (filename == null) { + return; + } + FileOption fileOption = project.getFileOption(filename); + Object source = actionEvent.getSource(); + if (source instanceof JCheckBox) { + JCheckBox checkBox = (JCheckBox) source; + if ("default-file".equals(checkBox.getName())) { + if (checkBox.isSelected()) { + project.setIndexFile(filename); + } else { + project.setIndexFile(null); + } + } else if ("insert".equals(checkBox.getName())) { + boolean isInsert = checkBox.isSelected(); + fileOptionsCustomKeyTextField.setEnabled(!isInsert); + fileOption.setInsert(isInsert); + if (!isInsert) { + fileOptionsContainerComboBox.setSelectedItem(""); + } + } else if ("project-files.replace-edition".equals(checkBox.getName())) { + boolean replaceEdition = checkBox.isSelected(); + fileOption.setReplaceEdition(replaceEdition); + replaceEditionRangeSpinner.setEnabled(replaceEdition); + } + } else if (source instanceof JComboBox) { + JComboBox comboBox = (JComboBox) source; + if ("project-files.mime-type".equals(comboBox.getName())) { + fileOption.setMimeType((String) comboBox.getSelectedItem()); + } else if ("project-files.container".equals(comboBox.getName())) { + String containerName = (String) comboBox.getSelectedItem(); + fileOption.setContainer(containerName); + boolean enabled = !"".equals(containerName); + editContainerAction.setEnabled(enabled); + deleteContainerAction.setEnabled(enabled); + if (enabled) { + fileOptionsInsertCheckBox.setSelected(true); + } + } + } + } + + // + // INTERFACE ListSelectionListener + // + + /** + * {@inheritDoc} + */ + public void valueChanged(ListSelectionEvent e) { + String filename = (String) projectFileList.getSelectedValue(); + boolean enabled = filename != null; + boolean insert = fileOptionsInsertCheckBox.isSelected(); + defaultFileCheckBox.setEnabled(enabled); + fileOptionsInsertCheckBox.setEnabled(enabled); + fileOptionsCustomKeyTextField.setEnabled(enabled && !insert); + fileOptionsMIMETypeComboBox.setEnabled(enabled); + fileOptionsContainerComboBox.setEnabled(enabled); + addContainerAction.setEnabled(enabled); + editContainerAction.setEnabled(enabled); + deleteContainerAction.setEnabled(enabled); + replacementCheckBox.setEnabled(enabled && insert && (project instanceof EditionProject)); + if (filename != null) { + FileOption fileOption = project.getFileOption(filename); + defaultFileCheckBox.setSelected(filename.equals(project.getIndexFile())); + fileOptionsInsertCheckBox.setSelected(fileOption.isInsert()); + fileOptionsCustomKeyTextField.setText(fileOption.getCustomKey()); + fileOptionsMIMETypeComboBox.getModel().setSelectedItem(fileOption.getMimeType()); + fileOptionsContainerComboBox.setSelectedItem(fileOption.getContainer()); + replacementCheckBox.setSelected(fileOption.getReplaceEdition()); + replaceEditionRangeSpinner.setValue(fileOption.getEditionRange()); + replaceEditionRangeSpinner.setEnabled(fileOption.getReplaceEdition()); + } else { + defaultFileCheckBox.setSelected(false); + fileOptionsInsertCheckBox.setSelected(true); + fileOptionsCustomKeyTextField.setText("CHK@"); + fileOptionsMIMETypeComboBox.getModel().setSelectedItem(DefaultMIMETypes.DEFAULT_MIME_TYPE); + fileOptionsContainerComboBox.setSelectedItem(""); + replacementCheckBox.setSelected(false); + replaceEditionRangeSpinner.setValue(0); + } + } + + // + // INTERFACE DocumentListener + // + + private void processDocumentUpdate(DocumentEvent documentEvent) { + String filename = (String) projectFileList.getSelectedValue(); + if (filename == null) + return; + FileOption fileOption = project.getFileOption(filename); + Document document = documentEvent.getDocument(); + try { + String text = document.getText(0, document.getLength()); + fileOption.setCustomKey(text); + } catch (BadLocationException ble1) { + } + } + + /** + * {@inheritDoc} + */ + public void changedUpdate(DocumentEvent documentEvent) { + processDocumentUpdate(documentEvent); + } + + /** + * {@inheritDoc} + */ + public void insertUpdate(DocumentEvent documentEvent) { + processDocumentUpdate(documentEvent); + } + + /** + * {@inheritDoc} + */ + public void removeUpdate(DocumentEvent documentEvent) { + processDocumentUpdate(documentEvent); + } + + // + // INTERFACE ChangeListener + // + + /** + * {@inheritDoc} + */ + public void stateChanged(ChangeEvent changeEvent) { + String filename = (String) projectFileList.getSelectedValue(); + if (filename == null) + return; + FileOption fileOption = project.getFileOption(filename); + Object source = changeEvent.getSource(); + if (source instanceof JSpinner) { + JSpinner spinner = (JSpinner) source; + fileOption.setEditionRange((Integer) spinner.getValue()); + } + } + +} diff --git a/src/de/todesbaum/jsite/gui/ProjectInsertPage.java b/src/de/todesbaum/jsite/gui/ProjectInsertPage.java new file mode 100644 index 0000000..ef06fc5 --- /dev/null +++ b/src/de/todesbaum/jsite/gui/ProjectInsertPage.java @@ -0,0 +1,198 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.gui; + +import java.awt.BorderLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.text.DateFormat; +import java.text.MessageFormat; +import java.util.Date; + +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; + +import de.todesbaum.jsite.application.EditionProject; +import de.todesbaum.jsite.application.Freenet7Interface; +import de.todesbaum.jsite.application.InsertListener; +import de.todesbaum.jsite.application.Project; +import de.todesbaum.jsite.application.ProjectInserter; +import de.todesbaum.jsite.i18n.I18n; +import de.todesbaum.util.swing.TWizard; +import de.todesbaum.util.swing.TWizardPage; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: ProjectInsertPage.java 408 2006-03-29 09:31:10Z bombe $ + */ +public class ProjectInsertPage extends TWizardPage implements InsertListener { + + protected TWizard wizard; + protected ProjectInserter projectInserter; + + protected JTextField requestURITextField; + protected JLabel startTimeLabel; + protected JProgressBar progressBar; + protected long startTime; + + public ProjectInsertPage() { + super(); + pageInit(); + setHeading(I18n.getMessage("jsite.insert.heading")); + setDescription(I18n.getMessage("jsite.insert.description")); + projectInserter = new ProjectInserter(); + projectInserter.addInsertListener(this); + } + + private void pageInit() { + setLayout(new BorderLayout(12, 12)); + add(createProjectInsertPanel(), BorderLayout.CENTER); + } + + private JComponent createProjectInsertPanel() { + JComponent projectInsertPanel = new JPanel(new GridBagLayout()); + + requestURITextField = new JTextField(); + requestURITextField.setEditable(false); + requestURITextField.setBackground(getBackground()); + requestURITextField.setBorder(null); + + startTimeLabel = new JLabel(); + + progressBar = new JProgressBar(0, 1); + progressBar.setStringPainted(true); + progressBar.setValue(0); + + projectInsertPanel.add(new JLabel("" + I18n.getMessage("jsite.insert.project-information") + ""), new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0)); + projectInsertPanel.add(new JLabel(I18n.getMessage("jsite.insert.request-uri") + ":"), new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0)); + projectInsertPanel.add(requestURITextField, new GridBagConstraints(1, 1, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + projectInsertPanel.add(new JLabel(I18n.getMessage("jsite.insert.start-time") + ":"), new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0)); + projectInsertPanel.add(startTimeLabel, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + projectInsertPanel.add(new JLabel(I18n.getMessage("jsite.insert.progress") + ":"), new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 18, 0, 0), 0, 0)); + projectInsertPanel.add(progressBar, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + + return projectInsertPanel; + } + + /** + * {@inheritDoc} + */ + @Override + public void pageAdded(TWizard wizard) { + this.wizard = wizard; + wizard.setPreviousEnabled(false); + wizard.setNextEnabled(false); + wizard.setQuitEnabled(false); + progressBar.setValue(0); + projectInserter.start(); + } + + /** + * @param debug + * The debug to set. + */ + public void setDebug(boolean debug) { + projectInserter.setDebug(debug); + } + + /** + * @param project + * The project to set. + */ + public void setProject(final Project project) { + projectInserter.setProject(project); + SwingUtilities.invokeLater(new Runnable() { + + public void run() { + StringBuffer uriBuffer = new StringBuffer(); + uriBuffer.append(project.getRequestURI()); + uriBuffer.append(project.getPath()); + if (project instanceof EditionProject) { + uriBuffer.append('-').append(((EditionProject) project).getEdition()); + } + uriBuffer.append('/'); + requestURITextField.setText(uriBuffer.toString()); + } + }); + } + + public void setFreenetInterface(Freenet7Interface freenetInterface) { + projectInserter.setFreenetInterface(freenetInterface); + } + + // + // INTERFACE InsertListener + // + + /** + * {@inheritDoc} + */ + public void projectInsertStarted(final Project project) { + startTime = System.currentTimeMillis(); + SwingUtilities.invokeLater(new Runnable() { + + public void run() { + startTimeLabel.setText(DateFormat.getDateTimeInstance().format(new Date(startTime))); + } + }); + } + + /** + * {@inheritDoc} + */ + public void projectInsertProgress(Project project, final int succeeded, final int failed, final int fatal, final int total, final boolean finalized) { + SwingUtilities.invokeLater(new Runnable() { + + public void run() { + progressBar.setMaximum(total); + progressBar.setValue(succeeded + failed + fatal); + } + }); + } + + /** + * {@inheritDoc} + */ + public void projectInsertFinished(Project project, boolean success, Throwable cause) { + if (success) { + JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.insert.inserted"), null, JOptionPane.INFORMATION_MESSAGE); + } else { + if (cause == null) { + JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.insert.insert-failed"), null, JOptionPane.ERROR_MESSAGE); + } else { + JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.insert.insert-failed-with-cause"), cause.getMessage()), null, JOptionPane.ERROR_MESSAGE); + } + } + SwingUtilities.invokeLater(new Runnable() { + + public void run() { + wizard.setNextEnabled(true); + wizard.setQuitEnabled(true); + } + }); + } + +} diff --git a/src/de/todesbaum/jsite/gui/ProjectPage.java b/src/de/todesbaum/jsite/gui/ProjectPage.java new file mode 100644 index 0000000..96a027d --- /dev/null +++ b/src/de/todesbaum/jsite/gui/ProjectPage.java @@ -0,0 +1,455 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.gui; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.text.MessageFormat; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSpinner; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; +import javax.swing.SpinnerNumberModel; +import javax.swing.JSpinner.NumberEditor; +import javax.swing.border.EmptyBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; + +import de.todesbaum.jsite.application.EditionProject; +import de.todesbaum.jsite.application.Freenet7Interface; +import de.todesbaum.jsite.application.Project; +import de.todesbaum.jsite.i18n.I18n; +import de.todesbaum.util.swing.SortedListModel; +import de.todesbaum.util.swing.TLabel; +import de.todesbaum.util.swing.TWizard; +import de.todesbaum.util.swing.TWizardPage; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: ProjectPage.java 418 2006-03-29 17:49:16Z bombe $ + */ +public class ProjectPage extends TWizardPage implements ListSelectionListener, ChangeListener, DocumentListener { + + private Freenet7Interface freenetInterface; + + private Action projectLocalPathBrowseAction; + private Action projectAddAction; + private Action projectDeleteAction; + private Action projectCloneAction; + + private JFileChooser pathChooser; + private SortedListModel projectListModel; + private JList projectList; + private JTextField projectNameTextField; + private JTextField projectDescriptionTextField; + private JTextField projectLocalPathTextField; + private JTextField projectPublicKeyTextField; + private JTextField projectPrivateKeyTextField; + private JTextField projectPathTextField; + private JSpinner projectEditionSpinner; + + public ProjectPage() { + super(); + setLayout(new BorderLayout(12, 12)); + dialogInit(); + setHeading(I18n.getMessage("jsite.project.heading")); + setDescription(I18n.getMessage("jsite.project.description")); + } + + protected void dialogInit() { + createActions(); + + pathChooser = new JFileChooser(); + projectListModel = new SortedListModel(); + projectList = new JList(projectListModel); + projectList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + projectList.addListSelectionListener(this); + projectList.setPreferredSize(new Dimension(150, projectList.getPreferredSize().height)); + + add(new JScrollPane(projectList), BorderLayout.LINE_START); + add(createInformationPanel(), BorderLayout.CENTER); + } + + /** + * {@inheritDoc} + */ + @Override + public void pageAdded(TWizard wizard) { + super.pageAdded(wizard); + projectList.clearSelection(); + wizard.setNextEnabled(false); + } + + /** + */ + public void addListSelectionListener(ListSelectionListener listener) { + projectList.addListSelectionListener(listener); + } + + /** + */ + public void removeListSelectionListener(ListSelectionListener listener) { + projectList.removeListSelectionListener(listener); + } + + private void createActions() { + projectLocalPathBrowseAction = new AbstractAction(I18n.getMessage("jsite.project.action.browse")) { + + public void actionPerformed(ActionEvent actionEvent) { + actionLocalPathBrowse(); + } + }; + projectLocalPathBrowseAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.browse.tooltip")); + projectLocalPathBrowseAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_B); + projectLocalPathBrowseAction.setEnabled(false); + + projectAddAction = new AbstractAction(I18n.getMessage("jsite.project.action.add-project")) { + + public void actionPerformed(ActionEvent actionEvent) { + actionAdd(); + } + }; + projectAddAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.add-project.tooltip")); + projectAddAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A); + + projectDeleteAction = new AbstractAction(I18n.getMessage("jsite.project.action.delete-project")) { + + public void actionPerformed(ActionEvent actionEvent) { + actionDelete(); + } + }; + projectDeleteAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.delete-project.tooltip")); + projectDeleteAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D); + projectDeleteAction.setEnabled(false); + + projectCloneAction = new AbstractAction(I18n.getMessage("jsite.project.action.clone-project")) { + + public void actionPerformed(ActionEvent actionEvent) { + actionClone(); + } + }; + projectCloneAction.putValue(Action.SHORT_DESCRIPTION, I18n.getMessage("jsite.project.action.clone-project.tooltip")); + projectCloneAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_L); + projectCloneAction.setEnabled(false); + } + + private JComponent createInformationPanel() { + JPanel informationPanel = new JPanel(new BorderLayout(12, 12)); + + JPanel informationTable = new JPanel(new GridBagLayout()); + + JPanel functionButtons = new JPanel(new FlowLayout(FlowLayout.LEADING, 12, 12)); + functionButtons.setBorder(new EmptyBorder(-12, -12, -12, -12)); + functionButtons.add(new JButton(projectAddAction)); + functionButtons.add(new JButton(projectDeleteAction)); + functionButtons.add(new JButton(projectCloneAction)); + + informationPanel.add(functionButtons, BorderLayout.PAGE_START); + informationPanel.add(informationTable, BorderLayout.CENTER); + + informationTable.add(new JLabel("" + I18n.getMessage("jsite.project.project.information") + ""), new GridBagConstraints(0, 0, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0)); + + projectNameTextField = new JTextField(); + projectNameTextField.getDocument().putProperty("name", "project.name"); + projectNameTextField.getDocument().addDocumentListener(this); + projectNameTextField.setEnabled(false); + + informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.name") + ":", KeyEvent.VK_N, projectNameTextField), new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + informationTable.add(projectNameTextField, new GridBagConstraints(1, 1, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + + projectDescriptionTextField = new JTextField(); + projectDescriptionTextField.getDocument().putProperty("name", "project.description"); + projectDescriptionTextField.getDocument().addDocumentListener(this); + projectDescriptionTextField.setEnabled(false); + + informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.description") + ":", KeyEvent.VK_D, projectDescriptionTextField), new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + informationTable.add(projectDescriptionTextField, new GridBagConstraints(1, 2, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + + projectLocalPathTextField = new JTextField(); + projectLocalPathTextField.getDocument().putProperty("name", "project.localpath"); + projectLocalPathTextField.getDocument().addDocumentListener(this); + projectLocalPathTextField.setEnabled(false); + + informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.local-path") + ":", KeyEvent.VK_L, projectLocalPathTextField), new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + informationTable.add(projectLocalPathTextField, new GridBagConstraints(1, 3, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + informationTable.add(new JButton(projectLocalPathBrowseAction), new GridBagConstraints(2, 3, 1, 1, 0.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + + informationTable.add(new JLabel("" + I18n.getMessage("jsite.project.project.address") + ""), new GridBagConstraints(0, 4, 3, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(12, 0, 0, 0), 0, 0)); + + projectPublicKeyTextField = new JTextField(27); + projectPublicKeyTextField.getDocument().putProperty("name", "project.publickey"); + projectPublicKeyTextField.getDocument().addDocumentListener(this); + projectPublicKeyTextField.setEnabled(false); + + informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.public-key") + ":", KeyEvent.VK_U, projectPublicKeyTextField), new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + informationTable.add(projectPublicKeyTextField, new GridBagConstraints(1, 5, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + + projectPrivateKeyTextField = new JTextField(27); + projectPrivateKeyTextField.getDocument().putProperty("name", "project.privatekey"); + projectPrivateKeyTextField.getDocument().addDocumentListener(this); + projectPrivateKeyTextField.setEnabled(false); + + informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.private-key") + ":", KeyEvent.VK_R, projectPrivateKeyTextField), new GridBagConstraints(0, 6, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + informationTable.add(projectPrivateKeyTextField, new GridBagConstraints(1, 6, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + + projectPathTextField = new JTextField(); + projectPathTextField.getDocument().putProperty("name", "project.path"); + projectPathTextField.getDocument().addDocumentListener(this); + projectPathTextField.setEnabled(false); + + informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.path") + ":", KeyEvent.VK_P, projectPathTextField), new GridBagConstraints(0, 7, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + informationTable.add(projectPathTextField, new GridBagConstraints(1, 7, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(6, 6, 0, 0), 0, 0)); + + projectEditionSpinner = new JSpinner(new SpinnerNumberModel(1, 0, Integer.MAX_VALUE, 1)); + ((NumberEditor) projectEditionSpinner.getEditor()).getTextField().setColumns(6); + projectEditionSpinner.setName("project.edition"); + projectEditionSpinner.addChangeListener(this); + projectEditionSpinner.setEnabled(false); + + informationTable.add(new TLabel(I18n.getMessage("jsite.project.project.edition") + ":", KeyEvent.VK_E, projectEditionSpinner), new GridBagConstraints(0, 8, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 18, 0, 0), 0, 0)); + informationTable.add(projectEditionSpinner, new GridBagConstraints(1, 8, 2, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(6, 6, 0, 0), 0, 0)); + + return informationPanel; + } + + public void setProjects(Project[] projects) { + projectListModel.clear(); + for (Project project: projects) { + projectListModel.add(project); + } + } + + public Project[] getProjects() { + return (Project[]) projectListModel.toArray(new Project[projectListModel.size()]); + } + + /** + * @param freenetInterface + * The freenetInterface to set. + */ + public void setFreenetInterface(Freenet7Interface freenetInterface) { + this.freenetInterface = freenetInterface; + } + + public Project getSelectedProject() { + return (Project) projectList.getSelectedValue(); + } + + private void setTextField(DocumentEvent documentEvent) { + Document document = documentEvent.getDocument(); + String propertyName = (String) document.getProperty("name"); + Project project = (Project) projectList.getSelectedValue(); + if (project == null) { + return; + } + try { + String text = document.getText(0, document.getLength()).trim(); + if ("project.name".equals(propertyName)) { + project.setName(text); + projectList.repaint(); + } else if ("project.description".equals(propertyName)) { + project.setDescription(text); + } else if ("project.localpath".equals(propertyName)) { + project.setLocalPath(text); + } else if ("project.privatekey".equals(propertyName)) { + project.setInsertURI(text); + } else if ("project.publickey".equals(propertyName)) { + project.setRequestURI(text); + } else if ("project.path".equals(propertyName)) { + project.setPath(text); + } + } catch (BadLocationException e) { + } + } + + // + // ACTIONS + // + + protected void actionLocalPathBrowse() { + Project project = (Project) projectList.getSelectedValue(); + if (project == null) + return; + pathChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); + if (pathChooser.showDialog(this, I18n.getMessage("jsite.project.action.browse.choose")) == JFileChooser.APPROVE_OPTION) { + projectLocalPathTextField.setText(pathChooser.getSelectedFile().getPath()); + } + } + + protected void actionAdd() { + String[] keyPair = null; + if (!freenetInterface.hasNode()) { + JOptionPane.showMessageDialog(this, I18n.getMessage("jsite.project-files.no-node-selected"), null, JOptionPane.ERROR_MESSAGE); + return; + } + try { + keyPair = freenetInterface.generateKeyPair(); + } catch (IOException ioe1) { + JOptionPane.showMessageDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.keygen.io-error"), ioe1.getMessage()), null, JOptionPane.ERROR_MESSAGE); + return; + } + EditionProject newProject = new EditionProject(); + newProject.setName(I18n.getMessage("jsite.project.new-project.name")); + newProject.setInsertURI(keyPair[0]); + newProject.setRequestURI(keyPair[1]); + newProject.setEdition(1); + projectListModel.add(newProject); + projectList.setSelectedIndex(projectListModel.size() - 1); + } + + protected void actionDelete() { + int selectedIndex = projectList.getSelectedIndex(); + if (selectedIndex > -1) { + if (JOptionPane.showConfirmDialog(this, MessageFormat.format(I18n.getMessage("jsite.project.action.delete-project.confirm"), ((Project) projectList.getSelectedValue()).getName()), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) { + projectListModel.remove(selectedIndex); + projectList.clearSelection(); + if (projectListModel.getSize() != 0) { + projectList.setSelectedIndex(Math.min(selectedIndex, projectListModel.getSize() - 1)); + } + } + } + } + + protected void actionClone() { + int selectedIndex = projectList.getSelectedIndex(); + if (selectedIndex > -1) { + Project newProject = null; + Project selectedProject = (Project) projectList.getSelectedValue(); + if (selectedProject instanceof EditionProject) { + newProject = new EditionProject(selectedProject); + } // else { /* BUG! */ } + newProject.setName(MessageFormat.format(I18n.getMessage("jsite.project.action.clone-project.copy"), newProject.getName())); + projectListModel.add(newProject); + projectList.setSelectedIndex(projectListModel.indexOf(newProject)); + } + } + + // + // INTERFACE ListSelectionListener + // + + /** + * {@inheritDoc} + */ + public void valueChanged(ListSelectionEvent listSelectionEvent) { + int selectedRow = projectList.getSelectedIndex(); + Project selectedProject = (Project) projectList.getSelectedValue(); + projectNameTextField.setEnabled(selectedRow > -1); + projectDescriptionTextField.setEnabled(selectedRow > -1); + projectLocalPathTextField.setEnabled(selectedRow > -1); + projectPublicKeyTextField.setEnabled(selectedRow > -1); + projectPrivateKeyTextField.setEnabled(selectedRow > -1); + projectPathTextField.setEnabled(selectedRow > -1); + projectEditionSpinner.setEnabled(selectedRow > -1); + projectLocalPathBrowseAction.setEnabled(selectedRow > -1); + projectDeleteAction.setEnabled(selectedRow > -1); + projectCloneAction.setEnabled(selectedRow > -1); + if (selectedRow > -1) { + projectNameTextField.setText(selectedProject.getName()); + projectDescriptionTextField.setText(selectedProject.getDescription()); + projectLocalPathTextField.setText(selectedProject.getLocalPath()); + projectPublicKeyTextField.setText(selectedProject.getRequestURI()); + projectPrivateKeyTextField.setText(selectedProject.getInsertURI()); + projectPathTextField.setText(selectedProject.getPath()); + if (selectedProject instanceof EditionProject) { + EditionProject editionProject = (EditionProject) selectedProject; + projectEditionSpinner.setValue(editionProject.getEdition()); + } + } else { + projectNameTextField.setText(""); + projectDescriptionTextField.setText(""); + projectLocalPathTextField.setText(""); + projectPublicKeyTextField.setText(""); + projectPrivateKeyTextField.setText(""); + projectPathTextField.setText(""); + projectEditionSpinner.setValue(0); + } + } + + // + // INTERFACE ChangeListener + // + + /** + * {@inheritDoc} + */ + public void stateChanged(ChangeEvent changeEvent) { + Object source = changeEvent.getSource(); + if (source instanceof JSpinner) { + JSpinner spinner = (JSpinner) source; + Project currentProject = (Project) projectList.getSelectedValue(); + if (currentProject == null) { + return; + } + if ("project.edition".equals(spinner.getName())) { + ((EditionProject) currentProject).setEdition((Integer) spinner.getValue()); + } + } + } + + // + // INTERFACE DocumentListener + // + + /** + * {@inheritDoc} + */ + public void insertUpdate(DocumentEvent documentEvent) { + setTextField(documentEvent); + } + + /** + * {@inheritDoc} + */ + public void removeUpdate(DocumentEvent documentEvent) { + setTextField(documentEvent); + } + + /** + * {@inheritDoc} + */ + public void changedUpdate(DocumentEvent documentEvent) { + setTextField(documentEvent); + } + +} diff --git a/src/de/todesbaum/jsite/i18n/I18n.java b/src/de/todesbaum/jsite/i18n/I18n.java new file mode 100644 index 0000000..38a6916 --- /dev/null +++ b/src/de/todesbaum/jsite/i18n/I18n.java @@ -0,0 +1,56 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.i18n; + +import java.util.Locale; +import java.util.ResourceBundle; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: I18n.java 355 2006-03-24 15:04:11Z bombe $ + */ +public class I18n { + + private static Locale currentLocale; + + public static Locale getLocale() { + if (currentLocale == null) + currentLocale = Locale.getDefault(); + return currentLocale; + } + + public static void setLocale(Locale locale) { + currentLocale = locale; + Locale.setDefault(locale); + } + + public static ResourceBundle getResourceBundle() { + return getResourceBundle(getLocale()); + } + + public static ResourceBundle getResourceBundle(Locale locale) { + return ResourceBundle.getBundle("de.todesbaum.jsite.i18n.jSite", locale); + } + + public static String getMessage(String key) { + return getResourceBundle().getString(key); + } + +} diff --git a/src/de/todesbaum/jsite/i18n/jSite.properties b/src/de/todesbaum/jsite/i18n/jSite.properties new file mode 100644 index 0000000..204de9a --- /dev/null +++ b/src/de/todesbaum/jsite/i18n/jSite.properties @@ -0,0 +1,126 @@ +# +# jSite - a tool for uploading websites into Freenet +# Copyright (C) 2006 David Roden +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# English language file by David Roden + +jsite.main.already-running=jSite is already running

A lock file has been found that suggests that another
instance of jSite is already running. Running multiple instances
of jSite is guaranteed to break your configuration. + +jsite.wizard.previous=Previous +jsite.wizard.next=Next +jsite.wizard.quit=Quit + +jsite.quit.question=Do you really want to quit? +jsite.quit.config-not-saved=Configuration not saved

The configuration could not be saved.
Do you want to quit anyway? + +jsite.menu.languages=Languages +jsite.menu.language.change.restart-message=Restart necessary

For language changes to take effect,
jSite must be restarted! +jsite.menu.language.en=English +jsite.menu.language.de=German +jsite.menu.nodes=Nodes +jsite.menu.nodes.manage-nodes=Manage nodes +jsite.menu.help=Help +jsite.menu.help.about=About + +jsite.about.message=jSite {0}

Copyright \u00a9 2006 David Roden
Released under the GNU General Public License + +jsite.node-manager.heading=Node Manager +jsite.node-manager.description=Manage your nodes here. +jsite.node-manager.node-information=Node Information +jsite.node-manager.add-node=Add Node +jsite.node-manager.new-node=New Node +jsite.node-manager.delete-node=Delete Node +jsite.node-manager.delete-node.warning=Confirm node deletion

Really delete this node? +jsite.node-manager.name=Name +jsite.node-manager.hostname=Hostname +jsite.node-manager.port=Port + +jsite.insert.heading=Project insert +jsite.insert.description=Please wait while the project is being inserted. +jsite.insert.project-information=Project information +jsite.insert.request-uri=Freesite +jsite.insert.start-time=Start time +jsite.insert.progress=Progress +jsite.insert.insert-failed=Insert failed

The insert of the project failed.
Some files could not be inserted. +jsite.insert.insert-failed-with-cause=Insert failed

The insert of the project failed.
Some files could not be inserted.
The following error occured:

{0} +jsite.insert.inserted=Project inserted

Your project was inserted successfully. + +jsite.file-scanner.can-not-read-directory=Can not read directory + +jsite.project.heading=Select a Project +jsite.project.description=Select a project to process from the list below, or create a new project. +jsite.project.action.browse=Browse +jsite.project.action.browse.choose=Choose +jsite.project.action.browse.tooltip=Browse for directory +jsite.project.action.add-project=Add project +jsite.project.action.add-project.tooltip=Add a new project +jsite.project.new-project.name=New Project +jsite.project.action.delete-project=Delete project +jsite.project.action.delete-project.tooltip=Delete a project +jsite.project.action.delete-project.confirm=Confirm deletion

The project \u201c{0}\u201d will be deleted!
Do you want to continue? +jsite.project.action.clone-project=Clone project +jsite.project.action.clone-project.copy=Copy of {0} +jsite.project.action.clone-project.tooltip=Clone the selected project +jsite.project.project.information=Project Information +jsite.project.project.name=Name +jsite.project.project.description=Description +jsite.project.project.local-path=Local path +jsite.project.project.address=Address +jsite.project.project.public-key=Request URI +jsite.project.project.private-key=Insert URI +jsite.project.project.path=Path +jsite.project.project.edition=Edition +jsite.project.keygen.io-error=Node communication failure

Communication with the node failed
with the following error message:

{0}

Please make sure that you have entered
the correct host name and port number
on the "Node Settings" page. +jsite.project.warning.no-local-path=No local path

You did not specify a local path for the files to insert.
It is not possible to continue without one. +jsite.project.warning.no-path=No freesite path

You did not specify a freesite path.
It is not possible to continue without one. + +jsite.project-files.heading=Project Files +jsite.project-files.description=On this page you can specify parameters for the files within the project, such as
externally generated keys or MIME types, if the automatic detection failed. +jsite.project-files.action.rescan=Re-scan +jsite.project-files.action.rescan.tooltip=Re-scan the project directory for new files +jsite.project-files.action.add-container=Add +jsite.project-files.action.add-container.tooltip=Adds a new container to the project and this file to it +jsite.project-files.action.add-container.message=Enter the name of the new container +jsite.project-files.action.edit-container=Edit +jsite.project-files.action.edit-container.tooltip=Changes the name of the container +jsite.project-files.action.edit-container.message=Enter the new name of the container +jsite.project-files.action.delete-container=Delete +jsite.project-files.action.delete-container.tooltip=Deletes this container +jsite.project-files.action.delete-container.message=Do you really want to delete this container? +jsite.project-files.file-options=File Options +jsite.project-files.default=Default file +jsite.project-files.default.tooltip=Specify that this file is the project\u2019s index file +jsite.project-files.insert=Insert +jsite.project-files.insert.tooltip=Uncheck if this file was inserted externally +jsite.project-files.custom-key=Custom key +jsite.project-files.custom-key.tooltip=The externally created key for the file +jsite.project-files.mime-type=MIME type +jsite.project-files.mime-type.tooltip=Select the correct MIME type here if the detection failed +jsite.project-files.container=Container +jsite.project-files.container.tooltip=Selects a container for the current file +jsite.project-files.replacement=Replacements +jsite.project-files.replacement.tooltip=Activates replacements in file +jsite.project-files.replacement.edition-range=Range +jsite.project-files.replacement.edition-range.tooltip=Also replace $[EDITION+1], $[EDITION+2]\u2026 +jsite.project-files.scan-error=Error scanning files

Either the directory of the project does not exist
or some files/directories in it are notaccessible.
Please go back and select the correct directory. +jsite.project-files.empty-index=No default file

You did not specify a default file for this project.
While it is possible to insert a project without a default
file you should specify one to ease browsing. +jsite.project-files.container-index=Default file in container

Your default file was placed in a container!
This might make other people shun your page. +jsite.project-files.index-not-html=Default file is not HTML

Your default file does not have the MIME type "text/html"!
Loading your Freesite in a browser may give unexpected results. +jsite.project-files.no-node-running=Node is not running

You can not insert a project if your node is not running.
Please start your node and try again. +jsite.project-files.no-custom-key=No custom key for file

You specified not to insert {0}
but failed to enter a key to redirect to! +jsite.project-files.no-node-selected=No node selected

Please select a node from the menu! diff --git a/src/de/todesbaum/jsite/i18n/jSite_de.properties b/src/de/todesbaum/jsite/i18n/jSite_de.properties new file mode 100644 index 0000000..f9ec5d1 --- /dev/null +++ b/src/de/todesbaum/jsite/i18n/jSite_de.properties @@ -0,0 +1,126 @@ +# +# jSite - a tool for uploading websites into Freenet +# Copyright (C) 2006 David Roden +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# + +# German language file by David Roden + +jsite.main.already-running=jSite läuft bereits!

Es wurde festgestellt, dass jSite bereits läuft. Das kann
zu Beschädigungen an der Konfiguration führen. + +jsite.wizard.previous=Zurück +jsite.wizard.next=Vorwärts +jsite.wizard.quit=Beenden + +jsite.quit.question=Möchten Sie jSite wirklich beenden? +jsite.quit.config-not-saved=Konfiguration nicht gespeichert

Die Konfiguration konnte nicht gespeichert werden.
Soll jSite trotzdem beendet werden? + +jsite.menu.languages=Sprachen +jsite.menu.language.change.restart-message=Neustart notwending

Damit die Änderungen an der Sprache wirksam
werden, muss jSite neu gestartet werden! +jsite.menu.language.en=Englisch +jsite.menu.language.de=Deutsch +jsite.menu.nodes=Nodes +jsite.menu.nodes.manage-nodes=Nodes verwalten +jsite.menu.help=Hilfe +jsite.menu.help.about=Ãœber + +jsite.about.message=jSite {0}

Copyright \u00a9 2006 David Roden
Veröffentlicht unter der GNU General Public License + +jsite.node-manager.heading=Nodeverwaltung +jsite.node-manager.description=Verwalten Sie hier Ihre Nodes. +jsite.node-manager.node-information=Nodeinformation +jsite.node-manager.add-node=Node hinzufügen +jsite.node-manager.new-node=Neuer Node +jsite.node-manager.delete-node=Node löschen +jsite.node-manager.delete-node.warning=Nodelöschung bestätigen

Wollen Sie diesen Node wirklich löschen? +jsite.node-manager.name=Name +jsite.node-manager.hostname=Hostname +jsite.node-manager.port=Port + +jsite.insert.heading=Projekt einfügen +jsite.insert.description=Bitte warten Sie, während das Projekt eingefügt wird. +jsite.insert.project-information=Projektinformationen +jsite.insert.request-uri=Freesite +jsite.insert.start-time=Beginn +jsite.insert.progress=Fortschritt +jsite.insert.insert-failed=Einfügen fehlgeschlagen

Das Einfügen des Projektes ist fehlgeschlagen, da
einige Dateien nicht eingefügt werden konnten. +jsite.insert.insert-failed-with-cause=Einfügen fehlgeschlagen

Das Einfügen des Projektes ist fehlgeschlagen, da
einige Dateien nicht eingefügt werden konnten.
Folgender Fehler trat auf:

{0} +jsite.insert.inserted=Projekt eingefügt

Ihr Projekt wurde erfolgreich eingefügt. + +jsite.file-scanner.can-not-read-directory=Kann Verzeichnis nicht lesen + +jsite.project.heading=Projekt auswählen +jsite.project.description=Wählen Sie das Projekt aus, welches sie einfügen möchten, oder erstellen Sie ein neues Projekt. +jsite.project.action.browse=Durchsuchen +jsite.project.action.browse.choose=Auswählen +jsite.project.action.browse.tooltip=Lokalen Pfad für Projekt auswählen +jsite.project.action.add-project=Projekt erstellen +jsite.project.action.add-project.tooltip=Ein neues Projekt erstellen +jsite.project.new-project.name=Neues Projekt +jsite.project.action.delete-project=Projekt löschen +jsite.project.action.delete-project.tooltip=Ein Projekt löschen +jsite.project.action.delete-project.confirm=Löschung bestätigen

Das Projekt \u201e{0}\u201c wird gelöscht!
Möchten Sie fortfahren? +jsite.project.action.clone-project=Projekt duplizieren +jsite.project.action.clone-project.copy=Kopie von {0} +jsite.project.action.clone-project.tooltip=Das ausgewählte Projekt duplizieren +jsite.project.project.information=Projektinformation +jsite.project.project.name=Name +jsite.project.project.description=Beschreibung +jsite.project.project.local-path=Lokaler Pfad +jsite.project.project.address=Adresse +jsite.project.project.public-key=Anfrage-URI +jsite.project.project.private-key=Einfüge-URI +jsite.project.project.path=Pfad +jsite.project.project.edition=Edition +jsite.project.keygen.io-error=Kommunikation fehlgeschlagen

Die Kommunikation mit dem Freenet Node
ergab folgende Fehlermeldung:

{0}

Bitte vergewissern Sie sich, dass der Node läuft und dass Sie
den korrekten Hostnamen und die korrekte Portnummer auf der
\u201eNode Einstellungen\u201c Seite eingegeben haben. +jsite.project.warning.no-local-path=Kein lokaler Pfad

Sie haben keinen lokalen Pfad für die einzufügenden Dateien angegeben.
Es ist nicht möglich, ohne lokalen Pfad weiter zu machen. +jsite.project.warning.no-path=Kein Freesite-Pfad

Sie haben keinen Pfad für die Freesite angegeben.
Es ist nicht möglich, ohne einen Freesite-Pfad weiter zu machen. + +jsite.project-files.heading=Projektdateien +jsite.project-files.description=Auf dieser Seite können Parameter für die einzelnen Dateien dieses Projekts angegeben werden, z.B.
extern erstellte Schlüssel oder der korrekte MIME-Typ, wenn er nicht automatisch richtig erkannt wurde. +jsite.project-files.action.rescan=Erneut einlesen +jsite.project-files.action.rescan.tooltip=Die Liste mit Dateien dieses Projekts neu einlesen +jsite.project-files.action.add-container=Hinzufügen +jsite.project-files.action.add-container.tooltip=Erzeugt einen neuen Container und fügt diese Datei hinzu +jsite.project-files.action.add-container.message=Bitte geben Sie den Namen des neuen Containers an +jsite.project-files.action.edit-container=Ändern +jsite.project-files.action.edit-container.tooltip=Ändert den Namen des Containers +jsite.project-files.action.edit-container.message=Bitte geben Sie den neuen Namen des Containers an +jsite.project-files.action.delete-container=Löschen +jsite.project-files.action.delete-container.tooltip=Löscht diesen Container +jsite.project-files.action.delete-container.message=Wollen Sie diesen Container wirklich löschen? +jsite.project-files.file-options=Dateioptionen +jsite.project-files.default=Index-Datei +jsite.project-files.default.tooltip=Lege Index-Datei für Projekt fest +jsite.project-files.insert=Einfügen +jsite.project-files.insert.tooltip=jSite fügt diese Datei ein +jsite.project-files.custom-key=Extern erstellter Schlüssel +jsite.project-files.custom-key.tooltip=Der extern erstellte Schlüssel für diese Datei +jsite.project-files.mime-type=MIME-Typ +jsite.project-files.mime-type.tooltip=Den richtigen MIME-Typ hier auswählen, wenn die automatische Erkennenung falsch ist +jsite.project-files.container=Container +jsite.project-files.container.tooltip=Wählt einen Container für diese Datei aus +jsite.project-files.replacement=Ersetzungen +jsite.project-files.replacement.tooltip=Aktiviert Ersetzungen in Datei +jsite.project-files.replacement.edition-range=Reichweite +jsite.project-files.replacement.edition-range.tooltip=Ersetzt auch $[EDITION+1], $[EDITION+2], usw. +jsite.project-files.scan-error=Fehler beim Einlesen der Dateien

Entweder existiert das Projektverzeichnis nicht,
oder einige Dateien und/oder Verzeichnisse sind nicht lesbar!
Bitte gehen Sie zurück und beheben Sie den Fehler! +jsite.project-files.empty-index=Keine Index-Datei gewählt

Sie haben keine Index-Datei für das Projekt angegeben.
Obwohl es möglich ist, das zu machen, sollten Sie doch
eine Index-Datei angeben, um das Browsen zu erleichtern. +jsite.project-files.container-index=Index-Datei in Container

Ihre Index-Datei befindet sich in einem Container! Das kann
dazu führen, dass Ihre Freesite von anderen Leuten gemieden wird. +jsite.project-files.index-not-html=Index-Datei ist kein HTML

Ihre Index-Datei hat nicht den MIME-Typ "text/html"!
Das kann beim Besuch Ihrer Freesite zu
unerwarteten Ergebnissen führen. +jsite.project-files.no-node-running=Der Node läuft nicht

Sie können das Projekt nicht einfügen, wenn
Ihr Node nicht läuft. Bitte starten Sie Ihren Node
und probieren Sie es erneut. +jsite.project-files.no-custom-key=Kein externer Schlüssel

Sie haben angegeben, dass die Datei {0}
nicht eingefügt werden soll. Allerdings haben Sie
keinen extern erstellten Schlüssel angegeben. +jsite.project-files.no-node-selected=Kein Node ausgewählt

Bitte wählen Sie einen Node aus dem Menü! diff --git a/src/de/todesbaum/jsite/main/CLI.java b/src/de/todesbaum/jsite/main/CLI.java new file mode 100644 index 0000000..c401aaa --- /dev/null +++ b/src/de/todesbaum/jsite/main/CLI.java @@ -0,0 +1,222 @@ +/* + * jSite - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.main; + +import java.io.PrintWriter; + +import de.todesbaum.jsite.application.EditionProject; +import de.todesbaum.jsite.application.Freenet7Interface; +import de.todesbaum.jsite.application.InsertListener; +import de.todesbaum.jsite.application.Node; +import de.todesbaum.jsite.application.Project; +import de.todesbaum.jsite.application.ProjectInserter; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: CLI.java 418 2006-03-29 17:49:16Z bombe $ + */ +public class CLI implements InsertListener { + + private Object lockObject = new Object(); + private PrintWriter outputWriter = new PrintWriter(System.out, true); + private Freenet7Interface freenetInterface; + private ProjectInserter projectInserter = new ProjectInserter(); + private Node[] nodes; + private Project[] projects; + private boolean finished = false; + private boolean success; + + private CLI(String[] args) { + + if ((args.length == 0) || args[0].equals("-h") || args[0].equals("--help")) { + outputWriter.println("\nParameters:\n"); + outputWriter.println(" --node="); + outputWriter.println(" --project="); + outputWriter.println(" --local-directory="); + outputWriter.println(" --path="); + outputWriter.println(" --edition="); + outputWriter.println("\nA project gets inserted when a new project is loaded on the command line,"); + outputWriter.println("or when the command line is finished. --local-directory, --path, and --edition"); + outputWriter.println("override the parameters in the project."); + return; + } + + Configuration configuration = new Configuration(); + if (!configuration.createLockFile()) { + outputWriter.println("Lock file found!"); + return; + } + + projectInserter.addInsertListener(this); + projects = configuration.getProjects(); + Node node = configuration.getSelectedNode(); + nodes = configuration.getNodes(); + + freenetInterface = new Freenet7Interface(); + freenetInterface.setNode(node); + + projectInserter.setFreenetInterface(freenetInterface); + + Project currentProject = null; + for (int argumentIndex = 0, argumentSize = args.length; argumentIndex < argumentSize; argumentIndex++) { + String argument = args[argumentIndex]; + String value = argument.substring(argument.indexOf('=') + 1).trim(); + if (argument.startsWith("--node=")) { + Node newNode = getNode(value); + if (newNode == null) { + outputWriter.println("Node \"" + value + "\" not found."); + return; + } + node = newNode; + freenetInterface.setNode(node); + } else if (argument.startsWith("--project=")) { + if (currentProject != null) { + if (insertProject(currentProject)) { + outputWriter.println("Project \"" + currentProject.getName() + "\" successfully inserted."); + } else { + outputWriter.println("Project \"" + currentProject.getName() + "\" was not successfully inserted."); + } + currentProject = null; + } + currentProject = getProject(value); + if (currentProject == null) { + outputWriter.println("Project \"" + value + "\" not found."); + } + } else if (argument.startsWith("--local-directory")) { + if (currentProject == null) { + outputWriter.println("You can't specifiy --local-directory before --project."); + return; + } + currentProject.setLocalPath(value); + } else if (argument.startsWith("--path=")) { + if (currentProject == null) { + outputWriter.println("You can't specify --path before --project."); + return; + } + currentProject.setPath(value); + } else if (argument.startsWith("--edition=")) { + if (currentProject == null) { + outputWriter.println("You can't specify --edition before --project."); + return; + } + if (currentProject instanceof EditionProject) { + ((EditionProject) currentProject).setEdition(Integer.parseInt(value)); + } else { + outputWriter.println("Project \"" + currentProject.getName() + "\" is not an edition-based project."); + return; + } + } else { + outputWriter.println("Unknown parameter: " + argument); + return; + } + } + + if (currentProject != null) { + if (insertProject(currentProject)) { + outputWriter.println("Project \"" + currentProject.getName() + "\" successfully inserted."); + } else { + outputWriter.println("Project \"" + currentProject.getName() + "\" was not successfully inserted."); + } + } + + configuration.setProjects(projects); + configuration.save(); + } + + private Project getProject(String name) { + for (Project project: projects) { + if (project.getName().equals(name)) { + return project; + } + } + return null; + } + + private Node getNode(String name) { + for (Node node: nodes) { + if (node.getName().equals(name)) { + return node; + } + } + return null; + } + + private boolean insertProject(Project currentProject) { + if (!freenetInterface.hasNode()) { + outputWriter.println("Node is not running!"); + return false; + } + projectInserter.setProject(currentProject); + projectInserter.start(); + synchronized (lockObject) { + while (!finished) { + try { + lockObject.wait(); + } catch (InterruptedException e) { + } + } + } + return success; + } + + // + // INTERFACE InsertListener + // + + /** + * {@inheritDoc} + */ + public void projectInsertStarted(Project project) { + outputWriter.println("Starting Insert of project \"" + project.getName() + "\"."); + } + + /** + * {@inheritDoc} + */ + public void projectInsertProgress(Project project, int succeeded, int failed, int fatal, int total, boolean finalized) { + outputWriter.println("Progress: " + succeeded + " done, " + failed + " failed, " + fatal + " fatal, " + total + " total" + (finalized ? " (finalized)" : "") + ", " + ((succeeded + failed + fatal) * 100 / total) + "%"); + } + + /** + * {@inheritDoc} + */ + public void projectInsertFinished(Project project, boolean success, Throwable cause) { + outputWriter.println("Request URI: " + project.getFinalURI(0)); + finished = true; + if (success) { + if (project instanceof EditionProject) { + ((EditionProject) project).setEdition(((EditionProject) project).getEdition() + 1); + } + } + this.success = success; + synchronized (lockObject) { + lockObject.notify(); + } + } + + // + // MAIN + // + + public static void main(String[] args) { + new CLI(args); + } + +} diff --git a/src/de/todesbaum/jsite/main/Configuration.java b/src/de/todesbaum/jsite/main/Configuration.java new file mode 100644 index 0000000..3931dcb --- /dev/null +++ b/src/de/todesbaum/jsite/main/Configuration.java @@ -0,0 +1,355 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.main; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; + +import de.todesbaum.jsite.application.EditionProject; +import de.todesbaum.jsite.application.FileOption; +import de.todesbaum.jsite.application.Node; +import de.todesbaum.jsite.application.Project; +import de.todesbaum.util.io.StreamCopier; +import de.todesbaum.util.xml.SimpleXML; +import de.todesbaum.util.xml.XML; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: Configuration.java 418 2006-03-29 17:49:16Z bombe $ + */ +public class Configuration { + + private String filename; + private String lockFilename; + private SimpleXML rootNode; + + public Configuration() { + filename = System.getProperty("user.home") + "/.jSite/config7"; + lockFilename = System.getProperty("user.home") + "/.jSite/lock7"; + readConfiguration(); + } + + private boolean createConfigDirectory() { + File configDirectory = new File(System.getProperty("user.home"), ".jSite"); + return (configDirectory.exists() && configDirectory.isDirectory()) || configDirectory.mkdirs(); + } + + public boolean createLockFile() { + if (!createConfigDirectory()) { + return false; + } + File lockFile = new File(lockFilename); + lockFile.deleteOnExit(); + try { + return lockFile.createNewFile(); + } catch (IOException e) { + } + return false; + } + + private void readConfiguration() { + File configurationFile = new File(filename); + if (configurationFile.exists()) { + ByteArrayOutputStream fileByteOutputStream = null; + FileInputStream fileInputStream = null; + try { + fileByteOutputStream = new ByteArrayOutputStream(); + fileInputStream = new FileInputStream(configurationFile); + StreamCopier.copy(fileInputStream, fileByteOutputStream, configurationFile.length()); + fileByteOutputStream.close(); + byte[] fileBytes = fileByteOutputStream.toByteArray(); + rootNode = SimpleXML.fromDocument(XML.transformToDocument(fileBytes)); + return; + } catch (FileNotFoundException e) { + } catch (IOException e) { + } finally { + if (fileInputStream != null) { + try { + fileInputStream.close(); + } catch (IOException ioe1) { + } + } + if (fileByteOutputStream != null) { + try { + fileByteOutputStream.close(); + } catch (IOException ioe1) { + } + } + } + } + rootNode = new SimpleXML("configuration"); + } + + public boolean save() { + File configurationFile = new File(filename); + if (!configurationFile.exists()) { + File configurationFilePath = configurationFile.getParentFile(); + if (!configurationFilePath.exists() && !configurationFilePath.mkdirs()) { + return false; + } + } + FileOutputStream fileOutputStream = null; + ByteArrayInputStream configurationInputStream = null; + try { + byte[] configurationBytes = XML.transformToByteArray(rootNode.getDocument()); + configurationInputStream = new ByteArrayInputStream(configurationBytes); + fileOutputStream = new FileOutputStream(configurationFile); + StreamCopier.copy(configurationInputStream, fileOutputStream, configurationBytes.length); + return true; + } catch (IOException ioe1) { + } finally { + if (configurationInputStream != null) { + try { + configurationInputStream.close(); + } catch (IOException ioe1) { + } + } + if (fileOutputStream != null) { + try { + fileOutputStream.close(); + } catch (IOException ioe1) { + } + } + } + return false; + } + + private String getNodeValue(String[] nodeNames, String defaultValue) { + SimpleXML node = rootNode; + int nodeIndex = 0; + while ((node != null) && (nodeIndex < nodeNames.length)) { + node = node.getNode(nodeNames[nodeIndex++]); + } + if (node == null) { + return defaultValue; + } + return node.getValue(); + } + + private int getNodeIntValue(String[] nodeNames, int defaultValue) { + try { + return Integer.parseInt(getNodeValue(nodeNames, String.valueOf(defaultValue))); + } catch (NumberFormatException nfe1) { + } + return defaultValue; + } + + private boolean getNodeBooleanValue(String[] nodeNames, boolean defaultValue) { + String nodeValue = getNodeValue(nodeNames, null); + if (nodeValue == null) { + return defaultValue; + } + return Boolean.parseBoolean(nodeValue); + } + + public String getNodeAddress() { + return getNodeValue(new String[] { "node-address" }, "localhost"); + } + + public void setNodeAddress(String nodeAddress) { + rootNode.replace("node-address", nodeAddress); + } + + public int getNodePort() { + return getNodeIntValue(new String[] { "node-port" }, 9481); + } + + public void setNodePort(int nodePort) { + rootNode.replace("node-port", String.valueOf(nodePort)); + } + + public boolean isSkipNodePage() { + return getNodeBooleanValue(new String[] { "skip-node-page" }, false); + } + + public void setSkipNodePage(boolean skipNodePage) { + rootNode.replace("skip-node-page", String.valueOf(skipNodePage)); + } + + public Project[] getProjects() { + List projects = new ArrayList(); + SimpleXML projectsNode = rootNode.getNode("project-list"); + if (projectsNode != null) { + SimpleXML[] projectNodes = projectsNode.getNodes("project"); + for (SimpleXML projectNode: projectNodes) { + try { + Project project = null; + SimpleXML typeNode = projectNode.getNode("type"); + if ("edition".equals(typeNode.getValue())) { + EditionProject editionProject = new EditionProject(); + project = editionProject; + editionProject.setEdition(Integer.parseInt(projectNode.getNode("edition").getValue())); + } + projects.add(project); + project.setDescription(projectNode.getNode("description").getValue()); + project.setIndexFile(projectNode.getNode("index-file").getValue()); + project.setLastInsertionTime(Long.parseLong(projectNode.getNode("last-insertion-time").getValue())); + project.setLocalPath(projectNode.getNode("local-path").getValue()); + project.setName(projectNode.getNode("name").getValue()); + project.setPath(projectNode.getNode("path").getValue()); + project.setInsertURI(projectNode.getNode("insert-uri").getValue()); + project.setRequestURI(projectNode.getNode("request-uri").getValue()); + SimpleXML fileOptionsNode = projectNode.getNode("file-options"); + Map fileOptions = new HashMap(); + if (fileOptionsNode != null) { + SimpleXML[] fileOptionNodes = fileOptionsNode.getNodes("file-option"); + for (SimpleXML fileOptionNode: fileOptionNodes) { + String filename = fileOptionNode.getNode("filename").getValue(); + FileOption fileOption = project.getFileOption(filename); + fileOption.setInsert(Boolean.parseBoolean(fileOptionNode.getNode("insert").getValue())); + fileOption.setCustomKey(fileOptionNode.getNode("custom-key").getValue()); + fileOption.setMimeType(fileOptionNode.getNode("mime-type").getValue()); + fileOption.setContainer(fileOptionNode.getNode("container").getValue()); + if (fileOptionNode.getNode("replace-edition") != null) { + fileOption.setReplaceEdition(Boolean.parseBoolean(fileOptionNode.getNode("replace-edition").getValue())); + fileOption.setEditionRange(Integer.parseInt(fileOptionNode.getNode("edition-range").getValue())); + } + fileOptions.put(filename, fileOption); + } + } + project.setFileOptions(fileOptions); + } catch (NumberFormatException nfe1) { + nfe1.printStackTrace(); + } + } + } + return projects.toArray(new Project[projects.size()]); + } + + public void setProjects(Project[] projects) { + SimpleXML projectsNode = new SimpleXML("project-list"); + for (Project project: projects) { + SimpleXML projectNode = projectsNode.append("project"); + if (project instanceof EditionProject) { + projectNode.append("type", "edition"); + projectNode.append("edition", String.valueOf(((EditionProject) project).getEdition())); + } + projectNode.append("description", project.getDescription()); + projectNode.append("index-file", project.getIndexFile()); + projectNode.append("last-insertion-time", String.valueOf(project.getLastInsertionTime())); + projectNode.append("local-path", project.getLocalPath()); + projectNode.append("name", project.getName()); + projectNode.append("path", project.getPath()); + projectNode.append("insert-uri", project.getInsertURI()); + projectNode.append("request-uri", project.getRequestURI()); + SimpleXML fileOptionsNode = projectNode.append("file-options"); + Iterator> entries = project.getFileOptions().entrySet().iterator(); + while (entries.hasNext()) { + Entry entry = entries.next(); + FileOption fileOption = entry.getValue(); + if (fileOption.isCustom()) { + SimpleXML fileOptionNode = fileOptionsNode.append("file-option"); + fileOptionNode.append("filename", entry.getKey()); + fileOptionNode.append("insert", String.valueOf(fileOption.isInsert())); + fileOptionNode.append("custom-key", fileOption.getCustomKey()); + fileOptionNode.append("mime-type", fileOption.getMimeType()); + fileOptionNode.append("container", fileOption.getContainer()); + fileOptionNode.append("replace-edition", String.valueOf(fileOption.getReplaceEdition())); + fileOptionNode.append("edition-range", String.valueOf(fileOption.getEditionRange())); + } + } + } + rootNode.replace(projectsNode); + } + + public Locale getLocale() { + String language = getNodeValue(new String[] { "i18n", "language" }, "en"); + String country = getNodeValue(new String[] { "i18n", "country" }, null); + if (country != null) { + return new Locale(language, country); + } + return new Locale(language); + } + + public void setLocale(Locale locale) { + SimpleXML i18nNode = new SimpleXML("i18n"); + if (locale.getCountry().length() != 0) { + i18nNode.append("country", locale.getCountry()); + } + i18nNode.append("language", locale.getLanguage()); + rootNode.replace(i18nNode); + return; + } + + public Node[] getNodes() { + SimpleXML nodesNode = rootNode.getNode("nodes"); + if (nodesNode == null) { + String hostname = getNodeAddress(); + int port = getNodePort(); + return new Node[] { new Node(hostname, port, "Node") }; + } + SimpleXML[] nodeNodes = nodesNode.getNodes("node"); + Node[] returnNodes = new Node[nodeNodes.length]; + int nodeIndex = 0; + for (SimpleXML nodeNode: nodeNodes) { + String name = nodeNode.getNode("name").getValue(); + String hostname = nodeNode.getNode("hostname").getValue(); + int port = Integer.parseInt(nodeNode.getNode("port").getValue()); + Node node = new Node(hostname, port, name); + returnNodes[nodeIndex++] = node; + } + return returnNodes; + } + + public void setNodes(Node[] nodes) { + SimpleXML nodesNode = new SimpleXML("nodes"); + for (Node node: nodes) { + SimpleXML nodeNode = nodesNode.append("node"); + nodeNode.append("name", node.getName()); + nodeNode.append("hostname", node.getHostname()); + nodeNode.append("port", String.valueOf(node.getPort())); + } + rootNode.replace(nodesNode); + rootNode.remove("node-address"); + rootNode.remove("node-port"); + } + + public void setSelectedNode(Node selectedNode) { + SimpleXML selectedNodeNode = new SimpleXML("selected-node"); + selectedNodeNode.append("name", selectedNode.getName()); + selectedNodeNode.append("hostname", selectedNode.getHostname()); + selectedNodeNode.append("port", String.valueOf(selectedNode.getPort())); + rootNode.replace(selectedNodeNode); + } + + public Node getSelectedNode() { + SimpleXML selectedNodeNode = rootNode.getNode("selected-node"); + if (selectedNodeNode == null) { + return null; + } + String name = selectedNodeNode.getNode("name").getValue(); + String hostname = selectedNodeNode.getNode("hostname").getValue(); + int port = Integer.valueOf(selectedNodeNode.getNode("port").getValue()); + return new Node(hostname, port, name); + } + +} diff --git a/src/de/todesbaum/jsite/main/Main.java b/src/de/todesbaum/jsite/main/Main.java new file mode 100644 index 0000000..4891f8f --- /dev/null +++ b/src/de/todesbaum/jsite/main/Main.java @@ -0,0 +1,413 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.main; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ButtonGroup; +import javax.swing.Icon; +import javax.swing.JList; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; + +import de.todesbaum.jsite.application.FileOption; +import de.todesbaum.jsite.application.Freenet7Interface; +import de.todesbaum.jsite.application.Node; +import de.todesbaum.jsite.application.Project; +import de.todesbaum.jsite.gui.NodeManagerListener; +import de.todesbaum.jsite.gui.NodeManagerPage; +import de.todesbaum.jsite.gui.ProjectFilesPage; +import de.todesbaum.jsite.gui.ProjectInsertPage; +import de.todesbaum.jsite.gui.ProjectPage; +import de.todesbaum.jsite.i18n.I18n; +import de.todesbaum.util.image.IconLoader; +import de.todesbaum.util.swing.TWizard; +import de.todesbaum.util.swing.TWizardPage; +import de.todesbaum.util.swing.WizardListener; + +/** + * @author David Roden + * @version $Id: Main.java 456 2006-04-03 17:54:44Z bombe $ + */ +public class Main implements ActionListener, ListSelectionListener, WizardListener, NodeManagerListener { + + private static boolean debug = false; + private Configuration configuration = new Configuration(); + private Freenet7Interface freenetInterface = new Freenet7Interface(); + protected Icon jSiteIcon; + + private static enum PageType { + PAGE_NODE_MANAGER, PAGE_PROJECTS, PAGE_PROJECT_FILES, PAGE_INSERT_PROJECT + } + + private static final Locale[] SUPPORTED_LOCALES = new Locale[] { Locale.ENGLISH, Locale.GERMAN }; + private Map languageActions = new HashMap(); + private Action manageNodeAction; + private Action aboutAction; + protected TWizard wizard; + protected JMenu nodeMenu; + private Node selectedNode; + private final Map pages = new HashMap(); + + private Main() { + Locale.setDefault(configuration.getLocale()); + I18n.setLocale(configuration.getLocale()); + if (!configuration.createLockFile()) { + JOptionPane.showMessageDialog(null, I18n.getMessage("jsite.main.already-running"), null, JOptionPane.ERROR_MESSAGE); + return; + } + wizard = new TWizard(); + createActions(); + wizard.setJMenuBar(createMenuBar()); + wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous")); + wizard.setNextName(I18n.getMessage("jsite.wizard.next")); + wizard.setQuitName(I18n.getMessage("jsite.wizard.quit")); + wizard.setPreviousEnabled(false); + wizard.setNextEnabled(true); + wizard.addWizardListener(this); + jSiteIcon = IconLoader.loadIcon("/jsite-icon.png"); + wizard.setIcon(jSiteIcon); + + initPages(); + showPage(PageType.PAGE_PROJECTS); + wizard.setPreviousName((String) manageNodeAction.getValue(Action.NAME)); + } + + private void createActions() { + for (final Locale locale: SUPPORTED_LOCALES) { + languageActions.put(locale, new AbstractAction(I18n.getMessage("jsite.menu.language." + locale.getLanguage())) { + + public void actionPerformed(ActionEvent actionEvent) { + switchLanguage(locale); + } + }); + } + manageNodeAction = new AbstractAction(I18n.getMessage("jsite.menu.nodes.manage-nodes")) { + public void actionPerformed(ActionEvent actionEvent) { + showPage(PageType.PAGE_NODE_MANAGER); + } + }; + aboutAction = new AbstractAction(I18n.getMessage("jsite.menu.help.about")) { + + public void actionPerformed(ActionEvent e) { + JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.about.message"), Version.getVersion()), null, JOptionPane.INFORMATION_MESSAGE, jSiteIcon); + } + }; + } + + private JMenuBar createMenuBar() { + JMenuBar menuBar = new JMenuBar(); + JMenu languageMenu = new JMenu(I18n.getMessage("jsite.menu.languages")); + menuBar.add(languageMenu); + ButtonGroup languageButtonGroup = new ButtonGroup(); + for (Locale locale: SUPPORTED_LOCALES) { + Action languageAction = languageActions.get(locale); + JRadioButtonMenuItem menuItem = new JRadioButtonMenuItem(languageActions.get(locale)); + if (locale.equals(Locale.getDefault())) { + menuItem.setSelected(true); + } + languageAction.putValue("menuItem", menuItem); + languageButtonGroup.add(menuItem); + languageMenu.add(menuItem); + } + nodeMenu = new JMenu(I18n.getMessage("jsite.menu.nodes")); + menuBar.add(nodeMenu); + selectedNode = configuration.getSelectedNode(); + nodesUpdated(configuration.getNodes()); + + /* evil hack to right-align the help menu */ + JPanel panel = new JPanel(); + panel.setOpaque(false); + menuBar.add(panel); + + JMenu helpMenu = new JMenu(I18n.getMessage("jsite.menu.help")); + menuBar.add(helpMenu); + helpMenu.add(aboutAction); + return menuBar; + } + + private void initPages() { + NodeManagerPage nodeManagerPage = new NodeManagerPage(); + nodeManagerPage.setName("page.node-manager"); + nodeManagerPage.addNodeManagerListener(this); + nodeManagerPage.setNodes(configuration.getNodes()); + pages.put(PageType.PAGE_NODE_MANAGER, nodeManagerPage); + + ProjectPage projectPage = new ProjectPage(); + projectPage.setName("page.project"); + projectPage.setProjects(configuration.getProjects()); + projectPage.setFreenetInterface(freenetInterface); + projectPage.addListSelectionListener(this); + pages.put(PageType.PAGE_PROJECTS, projectPage); + + ProjectFilesPage projectFilesPage = new ProjectFilesPage(); + projectFilesPage.setName("page.project.files"); + pages.put(PageType.PAGE_PROJECT_FILES, projectFilesPage); + + ProjectInsertPage projectInsertPage = new ProjectInsertPage(); + projectInsertPage.setDebug(debug); + projectInsertPage.setName("page.project.insert"); + projectInsertPage.setFreenetInterface(freenetInterface); + pages.put(PageType.PAGE_INSERT_PROJECT, projectInsertPage); + } + + protected void showPage(PageType pageType) { + wizard.setPreviousEnabled(pageType.ordinal() > 0); + wizard.setNextEnabled(pageType.ordinal() < (pages.size() - 1)); + wizard.setPage(pages.get(pageType)); + wizard.setTitle(pages.get(pageType).getHeading() + " - jSite"); + } + + private boolean saveConfiguration() { + NodeManagerPage nodeManagerPage = (NodeManagerPage) pages.get(PageType.PAGE_NODE_MANAGER); + configuration.setNodes(nodeManagerPage.getNodes()); + if (selectedNode != null) { + configuration.setSelectedNode(selectedNode); + } + + ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS); + configuration.setProjects(projectPage.getProjects()); + + return configuration.save(); + } + + private Locale findSupportedLocale(Locale forLocale) { + for (Locale locale: SUPPORTED_LOCALES) { + if (locale.equals(forLocale)) { + return locale; + } + } + for (Locale locale: SUPPORTED_LOCALES) { + if (locale.getCountry().equals(forLocale.getCountry()) && locale.getLanguage().equals(forLocale.getLanguage())) { + return locale; + } + } + for (Locale locale: SUPPORTED_LOCALES) { + if (locale.getLanguage().equals(forLocale.getLanguage())) { + return locale; + } + } + return SUPPORTED_LOCALES[0]; + } + + // + // ACTIONS + // + + protected void switchLanguage(Locale locale) { + Locale supportedLocale = findSupportedLocale(locale); + Action languageAction = languageActions.get(supportedLocale); + JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) languageAction.getValue("menuItem"); + menuItem.setSelected(true); + /* show the restart message in the other language! */ + Locale currentLocale = I18n.getLocale(); + I18n.setLocale(supportedLocale); + JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.menu.language.change.restart-message"), null, JOptionPane.INFORMATION_MESSAGE); + I18n.setLocale(currentLocale); + configuration.setLocale(supportedLocale); + } + + // + // INTERFACE ListSelectionListener + // + + /** + * {@inheritDoc} + */ + public void valueChanged(ListSelectionEvent e) { + JList list = (JList) e.getSource(); + int selectedRow = list.getSelectedIndex(); + wizard.setNextEnabled(selectedRow > -1); + } + + // + // INTERFACE WizardListener + // + + /** + * {@inheritDoc} + */ + public void wizardNextPressed(TWizard wizard) { + String pageName = wizard.getPage().getName(); + if ("page.node-manager".equals(pageName)) { + showPage(PageType.PAGE_PROJECTS); + wizard.setPreviousName((String) manageNodeAction.getValue(Action.NAME)); + } else if ("page.project".equals(pageName)) { + ProjectPage projectPage = (ProjectPage) wizard.getPage(); + Project project = projectPage.getSelectedProject(); + if ((project.getLocalPath() == null) || (project.getLocalPath().trim().length() == 0)) { + JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.no-local-path"), null, JOptionPane.ERROR_MESSAGE); + return; + } + if ((project.getPath() == null) || (project.getPath().trim().length() == 0)) { + JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project.warning.no-path"), null, JOptionPane.ERROR_MESSAGE); + return; + } + ((ProjectFilesPage) pages.get(PageType.PAGE_PROJECT_FILES)).setProject(project); + ((ProjectInsertPage) pages.get(PageType.PAGE_INSERT_PROJECT)).setProject(project); + showPage(PageType.PAGE_PROJECT_FILES); + wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous")); + } else if ("page.project.files".equals(pageName)) { + ProjectPage projectPage = (ProjectPage) pages.get(PageType.PAGE_PROJECTS); + Project project = projectPage.getSelectedProject(); + if (selectedNode == null) { + JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-node-selected"), null, JOptionPane.ERROR_MESSAGE); + return; + } + if (project.getIndexFile() == null) { + if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.empty-index"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) { + return; + } + } + if (!project.getFileOption(project.getIndexFile()).getContainer().equals("")) { + if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.container-index"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) { + return; + } + } + if (!project.getFileOption(project.getIndexFile()).getMimeType().equals("text/html")) { + if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.project-files.index-not-html"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) != JOptionPane.OK_OPTION) { + return; + } + } + Map fileOptions = project.getFileOptions(); + Set> fileOptionEntries = fileOptions.entrySet(); + for (Entry fileOptionEntry: fileOptionEntries) { + FileOption fileOption = fileOptionEntry.getValue(); + if (!fileOption.isInsert() && ((fileOption.getCustomKey().length() == 0) || "CHK@".equals(fileOption.getCustomKey()))) { + JOptionPane.showMessageDialog(wizard, MessageFormat.format(I18n.getMessage("jsite.project-files.no-custom-key"), fileOptionEntry.getKey()), null, JOptionPane.ERROR_MESSAGE); + return; + } + } + boolean nodeRunning = false; + try { + nodeRunning = freenetInterface.isNodePresent(); + } catch (IOException e) { + } + if (!nodeRunning) { + JOptionPane.showMessageDialog(wizard, I18n.getMessage("jsite.project-files.no-node-running"), null, JOptionPane.ERROR_MESSAGE); + return; + } + showPage(PageType.PAGE_INSERT_PROJECT); + nodeMenu.setEnabled(false); + } else if ("page.project.insert".equals(pageName)) { + showPage(PageType.PAGE_PROJECTS); + nodeMenu.setEnabled(true); + } + } + + /** + * {@inheritDoc} + */ + public void wizardPreviousPressed(TWizard wizard) { + String pageName = wizard.getPage().getName(); + if ("page.project".equals(pageName)) { + showPage(PageType.PAGE_NODE_MANAGER); + wizard.setPreviousName(I18n.getMessage("jsite.wizard.previous")); + } else if ("page.project.files".equals(pageName)) { + showPage(PageType.PAGE_PROJECTS); + wizard.setPreviousName((String) manageNodeAction.getValue(Action.NAME)); + } else if ("page.project.insert".equals(pageName)) { + showPage(PageType.PAGE_PROJECT_FILES); + } + } + + /** + * {@inheritDoc} + */ + public void wizardQuitPressed(TWizard wizard) { + if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.question"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) { + if (saveConfiguration()) { + System.exit(0); + } + if (JOptionPane.showConfirmDialog(wizard, I18n.getMessage("jsite.quit.config-not-saved"), null, JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.OK_OPTION) { + System.exit(0); + } + } + } + + // + // INTERFACE NodeManagerListener + // + + /** + * {@inheritDoc} + */ + public void nodesUpdated(Node[] nodes) { + nodeMenu.removeAll(); + ButtonGroup nodeButtonGroup = new ButtonGroup(); + Node newSelectedNode = null; + for (Node node: nodes) { + JRadioButtonMenuItem nodeMenuItem = new JRadioButtonMenuItem(node.getName()); + nodeMenuItem.putClientProperty("Node", node); + nodeMenuItem.addActionListener(this); + nodeButtonGroup.add(nodeMenuItem); + if (node.equals(selectedNode)) { + newSelectedNode = node; + nodeMenuItem.setSelected(true); + } + nodeMenu.add(nodeMenuItem); + } + nodeMenu.addSeparator(); + nodeMenu.add(manageNodeAction); + selectedNode = newSelectedNode; + freenetInterface.setNode(selectedNode); + } + + /** + * {@inheritDoc} + */ + public void actionPerformed(ActionEvent e) { + Object source = e.getSource(); + if (source instanceof JRadioButtonMenuItem) { + JRadioButtonMenuItem menuItem = (JRadioButtonMenuItem) source; + Node node = (Node) menuItem.getClientProperty("Node"); + selectedNode = node; + freenetInterface.setNode(selectedNode); + } + } + + // + // MAIN METHOD + // + + public static void main(String[] args) { + System.setProperty("swing.plaf.metal.userFont", "Tahoma"); + System.setProperty("swing.plaf.metal.controlFont", "Tahoma"); + System.setProperty("swing.aatext", "true"); + debug = (args.length > 0) && (args[0].equals("--debug")); + new Main(); + } + +} diff --git a/src/de/todesbaum/jsite/main/Version.java b/src/de/todesbaum/jsite/main/Version.java new file mode 100644 index 0000000..2192062 --- /dev/null +++ b/src/de/todesbaum/jsite/main/Version.java @@ -0,0 +1,34 @@ +/* + * jSite - a tool for uploading websites into Freenet + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.jsite.main; + +/** + * @author David Roden + * @version $Id: Version.java 457 2006-04-03 22:08:35Z bombe $ + */ +public class Version { + + private static final String VERSION = "0.4"; + + public static final String getVersion() { + return VERSION; + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/Client.java b/src/de/todesbaum/util/freenet/fcp2/Client.java new file mode 100644 index 0000000..e904a26 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/Client.java @@ -0,0 +1,216 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * A Client executes {@link Command}s over a {@link Connection} to a + * {@link Node} and delivers resulting {@link Message}s. + * + * @author David Roden <droden@gmail.com> + * @version $Id: Client.java 413 2006-03-29 12:22:31Z bombe $ + */ +public class Client implements ConnectionListener { + + /** The connection this client operates on. */ + private final Connection connection; + + /** The identifiers the client filters messages for. */ + private List identifiers = new ArrayList(); + + /** The queued messages. */ + private final List messageQueue = new ArrayList(); + + /** Whether the client was disconnected. */ + private boolean disconnected = false; + + /** Whether to catch all messages from the connection. */ + private boolean catchAll = false; + + /** + * Creates a new client that operates on the specified connection. + * + * @param connection + * The connection to operate on + */ + public Client(Connection connection) { + this.connection = connection; + connection.addConnectionListener(this); + } + + /** + * Creates a new client that operates on the specified connection and + * immediately executes the specified command. + * + * @param connection + * The connection to operate on + * @param command + * The command to execute + * @throws IOException + * if an I/O error occurs + * @see #execute(Command) + */ + public Client(Connection connection, Command command) throws IOException { + this(connection); + execute(command); + } + + /** + * Returns whether this client catches all messages going over the + * connection. + * + * @return true if the client catches all messages, + * false otherwise + */ + public boolean isCatchAll() { + return catchAll; + } + + /** + * Sets whether this client catches all messages going over the connection. + * + * @param catchAll + * true if the client should catch all messages, + * false otherwise + */ + public void setCatchAll(boolean catchAll) { + this.catchAll = catchAll; + } + + /** + * Executes the specified command. This will also clear the queue of + * messages, discarding all messages that resulted from the previous command + * and have not yet been read. + * + * @param command + * The command to execute + * @throws IOException + * if an I/O error occurs + * @see #execute(Command, boolean) + */ + public void execute(Command command) throws IOException { + execute(command, true); + } + + /** + * Executes the specified command and optionally clears the list of + * identifiers this clients listens to before starting the command. + * + * @param command + * The command to execute + * @param removeExistingIdentifiers + * If true, the list of identifiers that this + * clients listens to is cleared + * @throws IOException + * if an I/O error occurs + */ + public void execute(Command command, boolean removeExistingIdentifiers) throws IOException { + synchronized (messageQueue) { + messageQueue.clear(); + if (removeExistingIdentifiers) { + identifiers.clear(); + } + identifiers.add(command.getIdentifier()); + } + connection.execute(command); + } + + /** + * Returns the next message, waiting endlessly for it, if need be. If you + * are not sure whether a message will arrive, better use + * {@link #readMessage(long)} to only wait for a specific time. + * + * @return The next message that resulted from the execution of the last + * command + * @see #readMessage(long) + * @see #execute(Command) + */ + public Message readMessage() { + return readMessage(0); + } + + /** + * Returns the next message. If the message queue is currently empty, at + * least maxWaitTime milliseconds will be waited for a + * message to arrive. + * + * @param maxWaitTime + * The minimum time to wait for a message, in milliseconds + * @return The message, or null if no message arrived in time + * or the client is currently disconnected + * @see #isDisconnected() + * @see Object#wait(long) + */ + public Message readMessage(long maxWaitTime) { + synchronized (messageQueue) { + if (disconnected) { + return null; + } + if (messageQueue.size() == 0) { + try { + messageQueue.wait(maxWaitTime); + } catch (InterruptedException ie1) { + } + } + if (messageQueue.size() > 0) { + return messageQueue.remove(0); + } + } + return null; + } + + /** + * Returns whether the client is currently disconnected. + * + * @return true if the client is disconnected, + * false otherwise + */ + public boolean isDisconnected() { + synchronized (messageQueue) { + return disconnected; + } + } + + /** + * {@inheritDoc} + */ + public void messageReceived(Connection connection, Message message) { + synchronized (messageQueue) { + if (catchAll || (message.getIdentifier().length() == 0) || identifiers.contains(message.getIdentifier())) { + messageQueue.add(message); + messageQueue.notify(); + } + } + } + + /** + * {@inheritDoc} + */ + public void connectionTerminated(Connection connection) { + synchronized (messageQueue) { + disconnected = true; + messageQueue.notify(); + } + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/ClientHello.java b/src/de/todesbaum/util/freenet/fcp2/ClientHello.java new file mode 100644 index 0000000..a482345 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/ClientHello.java @@ -0,0 +1,101 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +import java.io.IOException; +import java.io.Writer; + +/** + * Implementation of the ClientHello command. This command must + * be sent as the first command on a connection ({@link de.todesbaum.util.freenet.fcp2.Connection#connect()} + * takes care of that) and must not be sent afterwards. + *

+ * The node can answer with the following messages: NodeHello. + * + * @author David Roden <droden@gmail.com> + * @version $Id: ClientHello.java 356 2006-03-24 15:13:38Z bombe $ + */ +public class ClientHello extends Command { + + /** The name of the client. */ + protected String name; + + /** The version of the FCP protocol the client expects. */ + protected String expectedVersion = "2.0"; + + /** + * Creates a new ClientHello command. + */ + public ClientHello() { + super("ClientHello", "ClientHello-" + System.currentTimeMillis()); + } + + /** + * Returns the value of the ExpectedVersion parameter of this + * command. At the moment this value is not used by the node but in the + * future this may be used to enforce certain node versions. + * + * @return The expected version + */ + public String getExpectedVersion() { + return expectedVersion; + } + + /** + * Sets the value of the ExpectedVersion parameter of this + * command. At the moment this value is not used by the node but in the + * future this may be used to enforce certain node versions. + * + * @param expectedVersion + * The expected version + */ + public void setExpectedVersion(String expectedVersion) { + this.expectedVersion = expectedVersion; + } + + /** + * Returns the name of the client that is connecting. + * + * @return The name of the client + */ + public String getName() { + return name; + } + + /** + * Sets the name of the client that is connecting. + * + * @param name + * The name of the client + */ + public void setName(String name) { + this.name = name; + } + + /** + * {@inheritDoc} + */ + @Override + protected void write(Writer writer) throws IOException { + writer.write("Name=" + name + LINEFEED); + writer.write("ExpectedVersion=" + expectedVersion + LINEFEED); + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/ClientPut.java b/src/de/todesbaum/util/freenet/fcp2/ClientPut.java new file mode 100644 index 0000000..1d97ed3 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/ClientPut.java @@ -0,0 +1,217 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +import java.io.IOException; +import java.io.Writer; + +/** + * Abstract base class for all put requests. It contains all parameters that put + * requests have in common. + * + * @author David Roden <droden@gmail.com> + * @version $Id: ClientPut.java 356 2006-03-24 15:13:38Z bombe $ + */ +public abstract class ClientPut extends Command { + + /** The URI of this request. */ + protected final String uri; + + /** The client token of this request. */ + protected String clientToken = null; + + /** Whether this request should only create a CHK. */ + protected boolean getCHKOnly = false; + + /** Whether this request is a global request. */ + protected boolean global = false; + + /** Whether the node should not try to compress the file. */ + protected boolean dontCompress = false; + + /** The maximum number of retries of this command. */ + protected int maxRetries = 0; + + /** The persistence of this request. */ + protected Persistence persistence = Persistence.CONNECTION; + + /** The priority class of this request. */ + protected PriorityClass priorityClass = PriorityClass.INTERACTIVE; + + /** The verbosiry of this request. */ + protected Verbosity verbosity = Verbosity.NONE; + + /** + * Creates a new put request with the specified name, identifier and URI. + * + * @param name + * The name of this request + * @param identifier + * The identifier of this request + * @param uri + * The URI of this request + */ + protected ClientPut(String name, String identifier, String uri) { + super(name, identifier); + this.uri = uri; + } + + /** + * Returns whether the node should not try to compress the data. + * + * @return true if the node should not try + * to compress the data + */ + public boolean isDontCompress() { + return dontCompress; + } + + /** + * Sets whether the node should not try to compress the data. A client might + * set this hint on data that is clearly not compressible, like MPEG audio + * files, JPEG or PNG images, highly compressed movies, or compressed + * archives like ZIP files. Otherwise the node will try to compress the file + * which -- depending on the size of the data -- might take a lot of time + * and memory. + * + * @param dontCompress + * true if the node should not + * try to compress the data + */ + public void setDontCompress(boolean dontCompress) { + this.dontCompress = dontCompress; + } + + /** + * Returns whether this request should only return the CHK of the data. + * @return Whether this request should only return the CHK of the data + */ + public boolean isGetCHKOnly() { + return getCHKOnly; + } + + /** + * Sets whether this request should only return the CHK of the data. + * @param getCHKOnly + * true if this request should only return the CHK of the data + */ + public void setGetCHKOnly(boolean getCHKOnly) { + this.getCHKOnly = getCHKOnly; + } + + /** + * Returns whether this request is a global request. + * @return true if this request is a global request, false otherwise + */ + public boolean isGlobal() { + return global; + } + + /** + * Sets whether this request is a global request. + * @param global + * true if this request is a global request, false otherwise + */ + public void setGlobal(boolean global) { + this.global = global; + } + + /** + * Returns the maximum number of retries of this request. + * @return The maximum number of retries of this request + */ + public int getMaxRetries() { + return maxRetries; + } + + /** + * Sets the maximum number of retries of this request + * @param maxRetries + * The maximum number of retries of this request + */ + public void setMaxRetries(int maxRetries) { + this.maxRetries = maxRetries; + } + + /** + * Returns the priority class of this request. + * @return The priority class of this request + */ + public PriorityClass getPriorityClass() { + return priorityClass; + } + + /** + * Sets the priority class of this request. + * @param priorityClass + * The priority class of this request + */ + public void setPriorityClass(PriorityClass priorityClass) { + this.priorityClass = priorityClass; + } + + /** + * Returns the verbosity of this request. + * @return The verbosity of this request + */ + public Verbosity getVerbosity() { + return verbosity; + } + + /** + * Sets the verbosity of this request. + * @param verbosity + * The verbosity of this request + */ + public void setVerbosity(Verbosity verbosity) { + this.verbosity = verbosity; + } + + /** + * Returns the URI of this request + * @return The URI of this request. + */ + public String getUri() { + return uri; + } + + /** + * {@inheritDoc} + */ + @Override + protected void write(Writer writer) throws IOException { + super.write(writer); + writer.write("URI=" + uri + LINEFEED); + if (verbosity != null) + writer.write("Verbosity=" + verbosity.getValue() + LINEFEED); + if (maxRetries != 0) + writer.write("MaxRetries=" + maxRetries + LINEFEED); + if (priorityClass != null) + writer.write("PriorityClass=" + priorityClass.getValue() + LINEFEED); + writer.write("GetCHKOnly=" + getCHKOnly + LINEFEED); + writer.write("Global=" + global + LINEFEED); + writer.write("DontCompress=" + dontCompress + LINEFEED); + if (clientToken != null) + writer.write("ClientToken=" + clientToken + LINEFEED); + if (persistence != null) + writer.write("Persistence=" + persistence.getName() + LINEFEED); + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/ClientPutComplexDir.java b/src/de/todesbaum/util/freenet/fcp2/ClientPutComplexDir.java new file mode 100644 index 0000000..08c8a53 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/ClientPutComplexDir.java @@ -0,0 +1,121 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +import java.io.IOException; +import java.io.InputStream; +import java.io.SequenceInputStream; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.Vector; + +/** + * Implementation of the ClientPutComplexDir command. This + * command can be used to insert directories that do not exist on disk. + * + * @author David Roden <droden@gmail.com> + * @version $Id: ClientPutComplexDir.java 356 2006-03-24 15:13:38Z bombe $ + */ +public class ClientPutComplexDir extends ClientPutDir { + + /** The file entries of this directory. */ + private List fileEntries = new ArrayList(); + + /** Whether this request has payload. */ + private boolean hasPayload = false; + + /** The input streams for the payload. */ + private List payloadInputStreams = new ArrayList(); + + /** The total number of bytes of the payload. */ + private long payloadLength = 0; + + /** + * Creates a new ClientPutComplexDir command with the specified identifier and URI. + * @param identifier The identifier of the command + * @param uri The URI of the command + */ + public ClientPutComplexDir(String identifier, String uri) { + super("ClientPutComplexDir", identifier, uri); + } + + /** + * Adds a file to the directory inserted by this request. + * @param fileEntry The file entry to add to the directory + */ + public void addFileEntry(FileEntry fileEntry) { + fileEntries.add(fileEntry); + } + + /** + * {@inheritDoc} + */ + @Override + protected void write(Writer writer) throws IOException { + super.write(writer); + int fileIndex = 0; + for (FileEntry fileEntry: fileEntries) { + writer.write("Files." + fileIndex + ".Name=" + fileEntry.getFilename() + LINEFEED); + if (fileEntry.getContentType() != null) { + writer.write("Files." + fileIndex + ".Metadata.ContentType=" + fileEntry.getContentType() + LINEFEED); + } + writer.write("Files." + fileIndex + ".UploadFrom=" + fileEntry.getName() + LINEFEED); + if (fileEntry instanceof DirectFileEntry) { + hasPayload = true; + writer.write("Files." + fileIndex + ".DataLength=" + ((DirectFileEntry) fileEntry).getDataLength() + LINEFEED); + payloadLength += ((DirectFileEntry) fileEntry).getDataLength(); + payloadInputStreams.add(((DirectFileEntry) fileEntry).getDataInputStream()); + } else if (fileEntry instanceof DiskFileEntry) { + writer.write("Files." + fileIndex + ".Filename=" + ((DiskFileEntry) fileEntry).getFilename() + LINEFEED); + } else if (fileEntry instanceof RedirectFileEntry) { + writer.write("Files." + fileIndex + ".TargetURI=" + ((RedirectFileEntry) fileEntry).getTargetURI() + LINEFEED); + } + fileIndex++; + } + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean hasPayload() { + return hasPayload; + } + + /** + * {@inheritDoc} + */ + @Override + protected long getPayloadLength() { + return payloadLength; + } + + /** + * {@inheritDoc} + */ + @Override + protected InputStream getPayload() { + /* grr. use Vector here because it returns an Enumeration. */ + Vector inputStreams = new Vector(payloadInputStreams); + return new SequenceInputStream(inputStreams.elements()); + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/ClientPutDir.java b/src/de/todesbaum/util/freenet/fcp2/ClientPutDir.java new file mode 100644 index 0000000..1181e11 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/ClientPutDir.java @@ -0,0 +1,83 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +import java.io.IOException; +import java.io.Writer; + +/** + * Abstract base class for all put requests that insert a directory. + * + * @author David Roden <droden@gmail.com> + * @version $Id: ClientPutDir.java 356 2006-03-24 15:13:38Z bombe $ + */ +public class ClientPutDir extends ClientPut { + + /** The default file of the directory. */ + protected String defaultName; + + /** + * Creates a new request with the specified name, identifier, and URI. + * + * @param name + * The name of the request + * @param identifier + * The identifier of the request + * @param uri + * The URI of the request + */ + public ClientPutDir(String name, String identifier, String uri) { + super(name, identifier, uri); + } + + /** + * Returns the default name of the directory. + * + * @return The default name of the directory + */ + public String getDefaultName() { + return defaultName; + } + + /** + * Sets the default name of the directory. The default name of a directory + * is the name of the file that will be delivered if the directory was + * requested without a filename. It's about the same as the + * index.html file that gets delivered if you only request a + * directory from a webserver. + * + * @param defaultName + * The default name of the directory + */ + public void setDefaultName(String defaultName) { + this.defaultName = defaultName; + } + + /** + * {@inheritDoc} + */ + @Override + protected void write(Writer writer) throws IOException { + super.write(writer); + if (defaultName != null) + writer.write("DefaultName=" + defaultName + LINEFEED); + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/Command.java b/src/de/todesbaum/util/freenet/fcp2/Command.java new file mode 100644 index 0000000..5dd9593 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/Command.java @@ -0,0 +1,138 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; + +/** + * Abstract base class for all commands. + *

+ * In addition to the replies listed at the type comment of each specific + * command the node can always send the following messages: + * ProtocolError (if this library screws up), + * CloseConnectionDuplicateClientName (if a client with the same + * name of the {@link de.todesbaum.util.freenet.fcp2.Connection} connects). So + * when receiving messages from the node you should always be prepared for + * something you did not expect. + * + * @author David Roden <droden@gmail.com> + * @version $Id: Command.java 371 2006-03-25 10:38:13Z bombe $ + */ +public abstract class Command { + + /** The line feed sequence used by the library. */ + protected static final String LINEFEED = "\r\n"; + + /** + * The name of the command. The name is sent to the node so it can not be + * chosen arbitrarily! + */ + private final String commandName; + + /** + * The identifier of the command. This identifier is used to identify + * replies that are caused by a command. + */ + private final String identifier; + + /** + * Creates a new command with the specified name and identifier. + * + * @param name + * The name of the command + * @param identifier + * The identifier of the command + */ + public Command(String name, String identifier) { + this.commandName = name; + this.identifier = identifier; + } + + /** + * Returns the name of this command. + * + * @return The name of this command + */ + public String getCommandName() { + return commandName; + } + + /** + * Return the identifier of this command. + * + * @return The identifier of this command + */ + public String getIdentifier() { + return identifier; + } + + /** + * Writes all parameters to the specified writer. + *

+ * NOTE: Subclasses of Command must call + * super.write(writer) before or after writing their own + * parameters! + * + * @param writer + * The stream to write the parameters to + * @throws IOException + * if an I/O error occurs + */ + protected void write(Writer writer) throws IOException { + if (identifier != null) + writer.write("Identifier=" + identifier + LINEFEED); + } + + /** + * Returns whether this command has payload to send after the message. + * Subclasses need to return true here if they need to send + * payload after the message. + * + * @return true if this command has payload to send, + * false otherwise + */ + protected boolean hasPayload() { + return false; + } + + /** + * Returns the payload of this command as an {@link InputStream}. This + * method is never called if {@link #hasPayload()} returns + * false. + * + * @return The payload of this command + */ + protected InputStream getPayload() { + return null; + } + + /** + * Returns the length of the payload. This method is never called if + * {@link #hasPayload()} returns false. + * + * @return The length of the payload + */ + protected long getPayloadLength() { + return -1; + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/Connection.java b/src/de/todesbaum/util/freenet/fcp2/Connection.java new file mode 100644 index 0000000..15757d0 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/Connection.java @@ -0,0 +1,371 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.net.Socket; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +import de.todesbaum.util.io.LineInputStream; +import de.todesbaum.util.io.StreamCopier; +import de.todesbaum.util.io.TempFileInputStream; + +/** + * A physical connection to a Freenet node. + * + * @author David Roden <droden@gmail.com> + * @version $Id: Connection.java 413 2006-03-29 12:22:31Z bombe $ + */ +public class Connection { + + /** The listeners that receive events from this connection. */ + private List connectionListeners = new ArrayList(); + + /** The node this connection is connected to. */ + private final Node node; + + /** The name of this connection. */ + private final String name; + + /** The network socket of this connection. */ + private Socket nodeSocket; + + /** The input stream that reads from the socket. */ + private InputStream nodeInputStream; + + /** The output stream that writes to the socket. */ + private OutputStream nodeOutputStream; + + /** The thread that reads from the socket. */ + private NodeReader nodeReader; + + /** A writer for the output stream. */ + private Writer nodeWriter; + + /** The NodeHello message sent by the node on connect. */ + protected Message nodeHello; + + /** + * Creates a new connection to the specified node with the specified name. + * + * @param node + * The node to connect to + * @param name + * The name of this connection + */ + public Connection(Node node, String name) { + this.node = node; + this.name = name; + } + + /** + * Adds a listener that gets notified on connection events. + * + * @param connectionListener + * The listener to add + */ + public void addConnectionListener(ConnectionListener connectionListener) { + connectionListeners.add(connectionListener); + } + + /** + * Removes a listener from the list of registered listeners. Only the first + * matching listener is removed. + * + * @param connectionListener + * The listener to remove + * @see List#remove(java.lang.Object) + */ + public void removeConnectionListener(ConnectionListener connectionListener) { + connectionListeners.remove(connectionListener); + } + + /** + * Notifies listeners about a received message. + * + * @param message + * The received message + */ + protected void fireMessageReceived(Message message) { + for (ConnectionListener connectionListener: connectionListeners) { + connectionListener.messageReceived(this, message); + } + } + + /** + * Notifies listeners about the loss of the connection. + */ + protected void fireConnectionTerminated() { + for (ConnectionListener connectionListener: connectionListeners) { + connectionListener.connectionTerminated(this); + } + } + + /** + * Returns the name of the connection. + * + * @return The name of the connection + */ + public String getName() { + return name; + } + + /** + * Connects to the node. + * + * @return true if the connection succeeded and the node + * returned a NodeHello message + * @throws IOException + * if an I/O error occurs + * @see #getNodeHello() + */ + public synchronized boolean connect() throws IOException { + nodeSocket = null; + nodeInputStream = null; + nodeOutputStream = null; + nodeWriter = null; + nodeReader = null; + try { + nodeSocket = new Socket(node.getHostname(), node.getPort()); + nodeSocket.setReceiveBufferSize(65535); + nodeInputStream = nodeSocket.getInputStream(); + nodeOutputStream = nodeSocket.getOutputStream(); + // nodeWriter = new TeeWriter(new + // OutputStreamWriter(nodeOutputStream, Charset.forName("UTF-8")), + // new PrintWriter(System.out)); + nodeWriter = new OutputStreamWriter(nodeOutputStream, Charset.forName("UTF-8")); + nodeReader = new NodeReader(nodeInputStream); + Thread nodeReaderThread = new Thread(nodeReader); + nodeReaderThread.setDaemon(true); + nodeReaderThread.start(); + ClientHello clientHello = new ClientHello(); + clientHello.setName(name); + clientHello.setExpectedVersion("2.0"); + execute(clientHello); + synchronized (this) { + try { + wait(); + } catch (InterruptedException e) { + } + } + return nodeHello != null; + } catch (IOException ioe1) { + disconnect(); + throw ioe1; + } + } + + /** + * Returns whether this connection is still connected to the node. + * + * @return true if this connection is still valid, + * false otherwise + */ + public boolean isConnected() { + return (nodeHello != null) && (nodeSocket != null) && (nodeSocket.isConnected()); + } + + /** + * Returns the NodeHello message the node sent on connection. + * + * @return The NodeHello message of the node + */ + public Message getNodeHello() { + return nodeHello; + } + + /** + * Disconnects from the node. + */ + public void disconnect() { + if (nodeWriter != null) { + try { + nodeWriter.close(); + } catch (IOException ioe1) { + } + nodeWriter = null; + } + if (nodeOutputStream != null) { + try { + nodeOutputStream.close(); + } catch (IOException ioe1) { + } + nodeOutputStream = null; + } + if (nodeInputStream != null) { + try { + nodeInputStream.close(); + } catch (IOException ioe1) { + } + nodeInputStream = null; + } + if (nodeSocket != null) { + try { + nodeSocket.close(); + } catch (IOException ioe1) { + } + nodeSocket = null; + } + fireConnectionTerminated(); + } + + /** + * Executes the specified command. + * + * @param command + * The command to execute + * @throws IllegalStateException + * if the connection is not connected + * @throws IOException + * if an I/O error occurs + */ + public synchronized void execute(Command command) throws IllegalStateException, IOException { + if (nodeSocket == null) { + throw new IllegalStateException("connection is not connected"); + } + nodeWriter.write(command.getCommandName() + Command.LINEFEED); + command.write(nodeWriter); + nodeWriter.write("EndMessage" + Command.LINEFEED); + nodeWriter.flush(); + if (command.hasPayload()) { + StreamCopier.copy(command.getPayload(), nodeOutputStream, command.getPayloadLength()); + nodeOutputStream.flush(); + } + } + + /** + * The reader thread for this connection. This is essentially a thread that + * reads lines from the node, creates messages from them and notifies + * listeners about the messages. + * + * @author David Roden <droden@gmail.com> + * @version $Id: Connection.java 413 2006-03-29 12:22:31Z bombe $ + */ + private class NodeReader implements Runnable { + + /** The input stream to read from. */ + @SuppressWarnings("hiding") + private InputStream nodeInputStream; + + /** + * Creates a new reader that reads from the specified input stream. + * + * @param nodeInputStream + * The input stream to read from + */ + public NodeReader(InputStream nodeInputStream) { + this.nodeInputStream = nodeInputStream; + } + + /** + * Main loop of the reader. Lines are read and converted into + * {@link Message} objects. + */ + public void run() { + LineInputStream nodeReader = null; + try { + nodeReader = new LineInputStream(nodeInputStream); + String line = ""; + Message message = null; + while (line != null) { + line = nodeReader.readLine(); + // System.err.println("> " + line); + if (line == null) { + break; + } + if (message == null) { + message = new Message(line); + continue; + } + if ("Data".equals(line)) { + /* need to read message from stream now */ + File tempFile = null; + try { + tempFile = File.createTempFile("fcpv2", "data"); + tempFile.deleteOnExit(); + FileOutputStream tempFileOutputStream = new FileOutputStream(tempFile); + long dataLength = Long.parseLong(message.get("DataLength")); + StreamCopier.copy(nodeInputStream, tempFileOutputStream, dataLength); + tempFileOutputStream.close(); + message.setPayloadInputStream(new TempFileInputStream(tempFile)); + } catch (IOException ioe1) { + ioe1.printStackTrace(); + } + } + if ("Data".equals(line) || "EndMessage".equals(line)) { + if (message.getName().equals("NodeHello")) { + nodeHello = message; + synchronized (Connection.this) { + Connection.this.notify(); + } + } else { + fireMessageReceived(message); + } + message = null; + continue; + } + int equalsPosition = line.indexOf('='); + if (equalsPosition > -1) { + String key = line.substring(0, equalsPosition).trim(); + String value = line.substring(equalsPosition + 1).trim(); + if (key.equals("Identifier")) { + message.setIdentifier(value); + } else { + message.put(key, value); + } + continue; + } + /* skip lines consisting of whitespace only */ + if (line.trim().length() == 0) { + continue; + } + /* if we got here, some error occured! */ + throw new IOException("Unexpected line: " + line); + } + } catch (IOException ioe1) { + // ioe1.printStackTrace(); + } finally { + if (nodeReader != null) { + try { + nodeReader.close(); + } catch (IOException ioe1) { + } + } + if (nodeInputStream != null) { + try { + nodeInputStream.close(); + } catch (IOException ioe1) { + } + } + } + Connection.this.disconnect(); + } + + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/ConnectionListener.java b/src/de/todesbaum/util/freenet/fcp2/ConnectionListener.java new file mode 100644 index 0000000..0bc77bb --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/ConnectionListener.java @@ -0,0 +1,50 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +import java.util.EventListener; + +/** + * Interface for clients that want to be notified when a message was received. + * + * @author David Roden <droden@gmail.com> + * @version $Id: ConnectionListener.java 356 2006-03-24 15:13:38Z bombe $ + */ +public interface ConnectionListener extends EventListener { + + /** + * Notifies a client that a message was received. + * + * @param connection + * The connection the message was received on + * @param message + * The message that was received + */ + public void messageReceived(Connection connection, Message message); + + /** + * Notifies a client that the connection to the node has been lost. + * + * @param connection + * The connection that was lost + */ + public void connectionTerminated(Connection connection); + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/DirectFileEntry.java b/src/de/todesbaum/util/freenet/fcp2/DirectFileEntry.java new file mode 100644 index 0000000..a337d17 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/DirectFileEntry.java @@ -0,0 +1,100 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * A {@link FileEntry} that sends its payload directly to the node, using the + * existing FCP connection. + * + * @author David Roden <droden@gmail.com> + * @version $Id: DirectFileEntry.java 413 2006-03-29 12:22:31Z bombe $ + */ +public class DirectFileEntry extends FileEntry { + + /** The input stream to read the data for this file from. */ + private final InputStream dataInputStream; + + /** The length of the data. */ + private final long dataLength; + + /** + * Creates a new FileEntry with the specified name and content type that + * gets its data from the specified byte array. + * + * @param filename + * The name of the file + * @param contentType + * The content type of the file + * @param dataBytes + * The content of the file + */ + public DirectFileEntry(String filename, String contentType, byte[] dataBytes) { + this(filename, contentType, new ByteArrayInputStream(dataBytes), dataBytes.length); + } + + /** + * Creates a new FileEntry with the specified name and content type that + * gets its data from the specified input stream. + * + * @param filename + * The name of the file + * @param contentType + * The content type of the file + * @param dataInputStream + * The input stream to read the content from + * @param dataLength + * The length of the data input stream + */ + public DirectFileEntry(String filename, String contentType, InputStream dataInputStream, long dataLength) { + super(filename, contentType); + this.dataInputStream = dataInputStream; + this.dataLength = dataLength; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return "direct"; + } + + /** + * Returns the input stream for the file's content. + * + * @return The input stream for the file's content + */ + public InputStream getDataInputStream() { + return dataInputStream; + } + + /** + * Returns the length of this file's content. + * + * @return The length of this file's content + */ + public long getDataLength() { + return dataLength; + } + +} \ No newline at end of file diff --git a/src/de/todesbaum/util/freenet/fcp2/DiskFileEntry.java b/src/de/todesbaum/util/freenet/fcp2/DiskFileEntry.java new file mode 100644 index 0000000..c4fed77 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/DiskFileEntry.java @@ -0,0 +1,67 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +/** + * A {@link FileEntry} that reads the content from a file on the disk. + * + * @author David Roden <droden@gmail.com> + * @version $Id: DiskFileEntry.java 413 2006-03-29 12:22:31Z bombe $ + */ +public class DiskFileEntry extends FileEntry { + + /** The local file name. */ + private final String localFilename; + + /** + * Creates a new {@link FileEntry} with the specified name and content type + * that is read from the file specified by localFilename. + * + * @param filename + * The name of the file + * @param contentType + * The content type of the file + * @param localFilename + * The name of the local file that holds the content of the file + * to insert + */ + public DiskFileEntry(String filename, String contentType, String localFilename) { + super(filename, contentType); + this.localFilename = localFilename; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return "disk"; + } + + /** + * Returns the name of the local file that holds the content for this file. + * + * @return The name of the local file + */ + public String getLocalFilename() { + return localFilename; + } + +} \ No newline at end of file diff --git a/src/de/todesbaum/util/freenet/fcp2/FileEntry.java b/src/de/todesbaum/util/freenet/fcp2/FileEntry.java new file mode 100644 index 0000000..7567725 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/FileEntry.java @@ -0,0 +1,83 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +/** + * Abstract base class of file entries that are used in the + * {@link de.todesbaum.util.freenet.fcp2.ClientPutComplexDir} command to define + * the files of an insert. + * + * @author David Roden <droden@gmail.com> + * @version $Id: FileEntry.java 413 2006-03-29 12:22:31Z bombe $ + */ +public abstract class FileEntry { + + /** The name of the file. */ + private final String filename; + + /** The content type of the file. */ + private final String contentType; + + /** + * Creates a new file entry with the specified name and content type. The + * content type should be a standard MIME type with an additional charset + * specification for text-based types. + * + * @param filename + * The name of the file + * @param contentType + * The content type of the file, e.g. + * "application/x-tar" or + * "text/html; charset=iso8859-15" + */ + protected FileEntry(String filename, String contentType) { + this.filename = filename; + this.contentType = contentType; + } + + /** + * Returns the name of this entry's type. Can be one of direct, + * disk, or redirect. This method is + * implemented by the subclasses {@link DirectFileEntry}, + * {@link DiskFileEntry}, and {@link RedirectFileEntry}, respectively. + * + * @return The name of this entry's type + */ + public abstract String getName(); + + /** + * Returns the content type of this file. + * + * @return The content type of this file + */ + public String getContentType() { + return contentType; + } + + /** + * Returns the name of this file. + * + * @return The name of this file + */ + public String getFilename() { + return filename; + } + +} \ No newline at end of file diff --git a/src/de/todesbaum/util/freenet/fcp2/GenerateSSK.java b/src/de/todesbaum/util/freenet/fcp2/GenerateSSK.java new file mode 100644 index 0000000..cfeaa74 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/GenerateSSK.java @@ -0,0 +1,39 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +/** + * Implementation of the GenerateSSK command. + *

+ * The node can answer with the following messages: SSKKeypair. + * + * @author David Roden <droden@gmail.com> + * @version $Id: GenerateSSK.java 413 2006-03-29 12:22:31Z bombe $ + */ +public class GenerateSSK extends Command { + + /** + * Creates a new GenerateSSK request. + */ + public GenerateSSK() { + super("GenerateSSK", null); + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/Message.java b/src/de/todesbaum/util/freenet/fcp2/Message.java new file mode 100644 index 0000000..a8460f8 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/Message.java @@ -0,0 +1,175 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +/** + * Contains replies sent by the Freenet node. A message always has a name, and + * most of the messages also have an identifier which binds it to a specific + * command. Exceptions are among others NodeHello, + * SSKKeypair, and EndListPersistentRequests. + * + * @author David Roden <droden@gmail.com> + * @version $Id: Message.java 413 2006-03-29 12:22:31Z bombe $ + * @see de.todesbaum.util.freenet.fcp2.Client + */ +public class Message { + + /** The name of this message. */ + private final String name; + + /** The identifier of this message. */ + private String identifier = ""; + + /** The parameters of this message. */ + private Map parameters = new HashMap(); + + /** The payload. */ + private InputStream payloadInputStream; + + /** + * Creates a new message with the specified name. + * + * @param name + * The name of this message + */ + public Message(String name) { + this.name = name; + } + + /** + * Returns the identifier of this message. + * + * @return The identifier + */ + public String getIdentifier() { + return identifier; + } + + /** + * Sets the identifier of this message. + * + * @param identifier + * The identifier of this message + */ + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + /** + * Returns the name of this message. + * + * @return The name of this message + */ + public String getName() { + return name; + } + + /** + * Tests whether this message contains the parameter with the specified key. + * Key names are compared ignoring case. + * + * @param key + * The name of the parameter + * @return true if this parameter exists in this message, + * false otherwise + */ + public boolean containsKey(String key) { + return parameters.containsKey(key.toLowerCase()); + } + + /** + * Returns all parameters of this message. The keys of the entries are all + * lower case so if you want to match the parameter names you have to watch + * out. + * + * @return All parameters of this message + */ + public Set> entrySet() { + return parameters.entrySet(); + } + + /** + * Returns the value of the parameter with the name specified by + * key. + * + * @param key + * The name of the parameter + * @return The value of the parameter + */ + public String get(String key) { + return parameters.get(key.toLowerCase()); + } + + /** + * Stores the specified value as parameter with the name specified by + * key. + * + * @param key + * The name of the parameter + * @param value + * The value of the parameter + * @return The previous value, or null if there was no + * previous value + */ + public String put(String key, String value) { + return parameters.put(key.toLowerCase(), value); + } + + /** + * Returns the number of parameters in this message. + * + * @return The number of parameters + */ + public int size() { + return parameters.size(); + } + + /** + * @return Returns the payloadInputStream. + */ + public InputStream getPayloadInputStream() { + return payloadInputStream; + } + + /** + * @param payloadInputStream + * The payloadInputStream to set. + */ + public void setPayloadInputStream(InputStream payloadInputStream) { + this.payloadInputStream = payloadInputStream; + } + + /** + * Returns a textual representation of this message, containing its name, + * the identifier, and the parameters. + * + * @return A textual representation of this message + */ + public String toString() { + return name + "[identifier=" + identifier + ",parameters=" + parameters.toString() + "]"; + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/Node.java b/src/de/todesbaum/util/freenet/fcp2/Node.java new file mode 100644 index 0000000..e444d22 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/Node.java @@ -0,0 +1,82 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +/** + * Contains the hostname and port number of the Freenet node. + * + * @author David Roden <droden@gmail.com> + * @version $Id: Node.java 356 2006-03-24 15:13:38Z bombe $ + */ +public class Node { + + /** The default port of FCPv2. */ + public static final int DEFAULT_PORT = 9481; + + /** The hostname of the node. */ + protected String hostname; + + /** The port number of the node. */ + protected int port; + + /** + * Creates a new node with the specified hostname and the default port + * number. + * + * @param hostname + * The hostname of the node + * @see #DEFAULT_PORT + */ + public Node(String hostname) { + this(hostname, DEFAULT_PORT); + } + + /** + * Creates a new node with the specified hostname and port number. + * + * @param hostname + * The hostname of the node + * @param port + * The port number of the node + */ + public Node(String hostname, int port) { + this.hostname = hostname; + this.port = port; + } + + /** + * Returns the hostname of the node. + * + * @return The hostname of the node + */ + public String getHostname() { + return hostname; + } + + /** + * Returns the port number of the node. + * + * @return The port number of the node + */ + public int getPort() { + return port; + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/Persistence.java b/src/de/todesbaum/util/freenet/fcp2/Persistence.java new file mode 100644 index 0000000..105fdb1 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/Persistence.java @@ -0,0 +1,49 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: Persistence.java 373 2006-03-25 10:42:52Z bombe $ + */ +public final class Persistence { + + public static final Persistence CONNECTION = new Persistence("connection"); + public static final Persistence REBOOT = new Persistence("reboot"); + public static final Persistence FOREVER = new Persistence("forever"); + + private String name; + + private Persistence(String name) { + this.name = name; + } + + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + + public String toString() { + return name; + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/PriorityClass.java b/src/de/todesbaum/util/freenet/fcp2/PriorityClass.java new file mode 100644 index 0000000..9f9ea0e --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/PriorityClass.java @@ -0,0 +1,58 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: PriorityClass.java 356 2006-03-24 15:13:38Z bombe $ + */ +public final class PriorityClass { + + public static final PriorityClass MAXIMUM = new PriorityClass("maximum", 0); + public static final PriorityClass INTERACTIVE = new PriorityClass("interactive", 1); + public static final PriorityClass SEMI_INTERACTIVE = new PriorityClass("semiInteractive", 2); + public static final PriorityClass UPDATABLE = new PriorityClass("updatable", 3); + public static final PriorityClass BULK = new PriorityClass("bulk", 4); + public static final PriorityClass PREFETCH = new PriorityClass("prefetch", 5); + public static final PriorityClass MINIMUM = new PriorityClass("minimum", 6); + + private String name; + private int value; + + private PriorityClass(String name, int value) { + this.name = name; + this.value = value; + } + + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + + /** + * @return Returns the value. + */ + public int getValue() { + return value; + } + +} diff --git a/src/de/todesbaum/util/freenet/fcp2/RedirectFileEntry.java b/src/de/todesbaum/util/freenet/fcp2/RedirectFileEntry.java new file mode 100644 index 0000000..cecb5a4 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/RedirectFileEntry.java @@ -0,0 +1,45 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +public class RedirectFileEntry extends FileEntry { + + final String targetURI; + + public RedirectFileEntry(String filename, String contentType, String targetURI) { + super(filename, contentType); + this.targetURI = targetURI; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return "redirect"; + } + + /** + * @return Returns the targetURI. + */ + public String getTargetURI() { + return targetURI; + } +} \ No newline at end of file diff --git a/src/de/todesbaum/util/freenet/fcp2/Verbosity.java b/src/de/todesbaum/util/freenet/fcp2/Verbosity.java new file mode 100644 index 0000000..f027779 --- /dev/null +++ b/src/de/todesbaum/util/freenet/fcp2/Verbosity.java @@ -0,0 +1,51 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.freenet.fcp2; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: Verbosity.java 356 2006-03-24 15:13:38Z bombe $ + */ +public final class Verbosity { + + public static final Verbosity PROGRESS = new Verbosity(1); + public static final Verbosity COMPRESSION = new Verbosity(512); + + public static final Verbosity NONE = new Verbosity(0); + public static final Verbosity ALL = new Verbosity(PROGRESS, COMPRESSION); + + private final int value; + + private Verbosity(int value) { + this.value = value; + } + + private Verbosity(Verbosity verbosity1, Verbosity verbosity2) { + this(verbosity1.value | verbosity2.value); + } + + /** + * @return Returns the value. + */ + public int getValue() { + return value; + } + +} diff --git a/src/de/todesbaum/util/image/IconLoader.java b/src/de/todesbaum/util/image/IconLoader.java new file mode 100644 index 0000000..a889481 --- /dev/null +++ b/src/de/todesbaum/util/image/IconLoader.java @@ -0,0 +1,51 @@ +/* + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.image; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.swing.Icon; +import javax.swing.ImageIcon; + +/** + * @author David Roden + * @version $Id: IconLoader.java 130 2006-02-18 18:27:11Z bombe $ + */ +public class IconLoader { + + public static Icon loadIcon(String resourceName) { + try { + InputStream resourceStream = IconLoader.class.getResourceAsStream(resourceName); + if (resourceStream == null) { + return null; + } + ByteArrayOutputStream imageOutput = new ByteArrayOutputStream(); + byte[] buffer = new byte[16384]; + int r = 0; + while ((r = resourceStream.read(buffer)) != -1) { + imageOutput.write(buffer, 0, r); + } + imageOutput.flush(); + return new ImageIcon(imageOutput.toByteArray()); + } catch (IOException e) { + } + return null; + } + +} diff --git a/src/de/todesbaum/util/io/LineInputStream.java b/src/de/todesbaum/util/io/LineInputStream.java new file mode 100644 index 0000000..48500bb --- /dev/null +++ b/src/de/todesbaum/util/io/LineInputStream.java @@ -0,0 +1,64 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.io; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: LineInputStream.java 429 2006-03-29 18:04:48Z bombe $ + */ +public class LineInputStream extends FilterInputStream { + + private boolean skipLinefeed = false; + private StringBuffer lineBuffer = new StringBuffer(); + + /** + * @param in + */ + public LineInputStream(InputStream in) { + super(in); + } + + public synchronized String readLine() throws IOException { + lineBuffer.setLength(0); + int c = 0; + while (c != -1) { + c = read(); + if ((c == -1) && lineBuffer.length() == 0) + return null; + if (skipLinefeed && (c == '\n')) { + skipLinefeed = false; + continue; + } + skipLinefeed = (c == '\r'); + if ((c == '\r') || (c == '\n')) { + c = -1; + } else { + lineBuffer.append((char) c); + } + } + return lineBuffer.toString(); + } + +} diff --git a/src/de/todesbaum/util/io/ReplacingOutputStream.java b/src/de/todesbaum/util/io/ReplacingOutputStream.java new file mode 100644 index 0000000..65e9c5d --- /dev/null +++ b/src/de/todesbaum/util/io/ReplacingOutputStream.java @@ -0,0 +1,83 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.io; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; + + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: ReplacingOutputStream.java 431 2006-03-29 18:06:18Z bombe $ + */ +public class ReplacingOutputStream extends FilterOutputStream { + + private Map replacements = new HashMap(); + private StringBuffer ringBuffer = new StringBuffer(); + + /** + * @param out + */ + public ReplacingOutputStream(OutputStream out) { + super(out); + } + + public void addReplacement(String token, String value) { + replacements.put(token, value); + } + + /** + * {@inheritDoc} + */ + @Override + public void write(int b) throws IOException { + ringBuffer.append((char) b); + Iterator> entries = replacements.entrySet().iterator(); + boolean found = false; + Entry entry = null; + while (!found && entries.hasNext()) { + entry = entries.next(); + if (entry.getKey().startsWith(ringBuffer.toString())) { + found = true; + } + } + if (!found) { + String buffer = ringBuffer.toString(); + for (int index = 0, size = buffer.length(); index < size; index++) { + super.write(buffer.charAt(index)); + } + ringBuffer.setLength(0); + } else { + if (entry.getKey().equals(ringBuffer.toString())) { + String buffer = entry.getValue(); + for (int index = 0, size = buffer.length(); index < size; index++) { + super.write(buffer.charAt(index)); + } + ringBuffer.setLength(0); + } + } + } + +} diff --git a/src/de/todesbaum/util/io/StreamCopier.java b/src/de/todesbaum/util/io/StreamCopier.java new file mode 100644 index 0000000..982d556 --- /dev/null +++ b/src/de/todesbaum/util/io/StreamCopier.java @@ -0,0 +1,152 @@ +/* + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.io; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * Copies input from an {@link InputStream} to an {@link OutputStream}. + * + * @author David Roden + * @version $Id: StreamCopier.java 428 2006-03-29 18:03:36Z bombe $ + */ +public class StreamCopier { + + /** + * The default size of the buffer. + */ + private static final int BUFFER_SIZE = 64 * 1024; + + /** + * The {@link InputStream} to read from. + */ + private InputStream inputStream; + + /** + * The {@link OutputStream} to write to. + */ + private OutputStream outputStream; + + /** + * The number of bytes to copy. + */ + private long length; + + /** + * The size of the buffer. + */ + private int bufferSize; + + /** + * Creates a new StreamCopier with the specified parameters and the default + * buffer size. + * + * @param inputStream + * The {@link InputStream} to read from + * @param outputStream + * The {@link OutputStream} to write to + * @param length + * The number of bytes to copy + */ + public StreamCopier(InputStream inputStream, OutputStream outputStream, long length) { + this(inputStream, outputStream, length, BUFFER_SIZE); + } + + /** + * Creates a new StreamCopier with the specified parameters and the default + * buffer size. + * + * @param inputStream + * The {@link InputStream} to read from + * @param outputStream + * The {@link OutputStream} to write to + * @param length + * The number of bytes to copy + * @param bufferSize + * The number of bytes to copy at a time + */ + public StreamCopier(InputStream inputStream, OutputStream outputStream, long length, int bufferSize) { + this.inputStream = inputStream; + this.outputStream = outputStream; + this.length = length; + this.bufferSize = bufferSize; + } + + /** + * Copies the stream data. If the input stream is depleted before the + * requested number of bytes have been read an {@link EOFException} is + * thrown. + * + * @throws EOFException + * if the input stream is depleted before the requested number + * of bytes has been read + * @throws IOException + * if an I/O error occurs + */ + public void copy() throws EOFException, IOException { + copy(inputStream, outputStream, length, bufferSize); + } + + /** + * Copies length bytes from the inputStream to + * the outputStream. + * + * @param inputStream + * The input stream to read from + * @param outputStream + * The output stream to write to + * @param length + * The number of bytes to copy + * @throws IOException + * if an I/O exception occurs + */ + public static void copy(InputStream inputStream, OutputStream outputStream, long length) throws IOException { + copy(inputStream, outputStream, length, BUFFER_SIZE); + } + + /** + * Copies length bytes from the inputStream to + * the outputStream using a buffer with the specified size + * + * @param inputStream + * The input stream to read from + * @param outputStream + * The output stream to write to + * @param length + * The number of bytes to copy + * @param bufferSize + * The size of the copy buffer + * @throws IOException + * if an I/O exception occurs + */ + public static void copy(InputStream inputStream, OutputStream outputStream, long length, int bufferSize) throws IOException { + long remaining = length; + byte[] buffer = new byte[bufferSize]; + while (remaining > 0) { + int read = inputStream.read(buffer, 0, (int) Math.min(Integer.MAX_VALUE, Math.min(bufferSize, remaining))); + if (read == -1) { + throw new EOFException(); + } + outputStream.write(buffer, 0, read); + remaining -= read; + } + } + +} diff --git a/src/de/todesbaum/util/io/TempFileInputStream.java b/src/de/todesbaum/util/io/TempFileInputStream.java new file mode 100644 index 0000000..0cefd79 --- /dev/null +++ b/src/de/todesbaum/util/io/TempFileInputStream.java @@ -0,0 +1,56 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.io; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id$ + */ +public class TempFileInputStream extends FileInputStream { + + private File tempFile; + + /** + * @param name + * @throws FileNotFoundException + */ + public TempFileInputStream(String name) throws FileNotFoundException { + this(new File(name)); + } + + /** + * @param file + * @throws FileNotFoundException + */ + public TempFileInputStream(File file) throws FileNotFoundException { + super(file); + } + + public void close() throws IOException { + super.close(); + tempFile.delete(); + } + +} diff --git a/src/de/todesbaum/util/mime/DefaultMIMETypes.java b/src/de/todesbaum/util/mime/DefaultMIMETypes.java new file mode 100644 index 0000000..c821912 --- /dev/null +++ b/src/de/todesbaum/util/mime/DefaultMIMETypes.java @@ -0,0 +1,834 @@ +/* taken from freenet (http://www.freenetproject.org/) */ +package de.todesbaum.util.mime; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +/** + * Holds the default MIME types. + */ +public class DefaultMIMETypes { + + /** Default MIME type - what to set it to if we don't know any better */ + public static final String DEFAULT_MIME_TYPE = "application/octet-stream"; + + /** MIME types: number -> name */ + private static List mimeTypesByNumber = new Vector(); + + /** MIME types: name -> number */ + private static Map mimeTypesByName = new HashMap(); + + /** MIME types by extension. One extension maps to one MIME type, but not necessarily + * the other way around. */ + private static Map mimeTypesByExtension = new HashMap(); + + /** Primary extension by MIME type number. */ + private static Map primaryExtensionByMimeNumber = new HashMap(); + + /** + * Add a MIME type, without any extensions. + * @param number The number of the MIME type for compression. This *must not change* + * for a given type, or the metadata format will be affected. + * @param type The actual MIME type string. Do not include ;charset= etc; these are + * parameters and there is a separate mechanism for them. + */ + protected static synchronized void addMIMEType(short number, String type) { + if(mimeTypesByNumber.size() > number) { + String s = mimeTypesByNumber.get(number); + if(s != null) throw new IllegalArgumentException("Already used: "+number); + } else { + mimeTypesByNumber.add(number, null); + } + mimeTypesByNumber.set(number, type); + mimeTypesByName.put(type, new Short(number)); + } + + /** + * Add a MIME type. + * @param number The number of the MIME type for compression. This *must not change* + * for a given type, or the metadata format will be affected. + * @param type The actual MIME type string. Do not include ;charset= etc; these are + * parameters and there is a separate mechanism for them. + * @param extensions An array of common extensions for files of this type. Must be + * unique for the type. + */ + protected static synchronized void addMIMEType(short number, String type, String[] extensions, String outExtension) { + addMIMEType(number, type); + Short t = new Short(number); + if(extensions != null) { + for(int i=0;i mimeTypesByNumber.size() || x < 0) + return null; + return mimeTypesByNumber.get(x); + } + + /** + * Get the number of a MIME type, or -1 if it is not in the table of known MIME + * types, in which case it will have to be sent uncompressed. + */ + public static short byName(String s) { + Short x = mimeTypesByName.get(s); + if(x != null) return x.shortValue(); + return -1; + } + + /* From toad's /etc/mime.types + * cat /etc/mime.types | sed "/^$/d;/#/d" | tr --squeeze '\t' ' ' | + * (y=0; while read x; do echo "$x" | + * sed -n "s/^\([^ ]*\)$/addMIMEType\($y, \"\1\"\);/p;s/^\([^ (),]\+\) \(.*\)$/addMIMEType\($y, \"\1\", \"\2\"\);/p;"; y=$((y+1)); done) + */ + + static { + addMIMEType((short) 0, "application/activemessage"); + addMIMEType((short) 1, "application/andrew-inset", "ez"); + addMIMEType((short) 2, "application/applefile"); + addMIMEType((short) 3, "application/atomicmail"); + addMIMEType((short) 4, "application/batch-SMTP"); + addMIMEType((short) 5, "application/beep+xml"); + addMIMEType((short) 6, "application/cals-1840"); + addMIMEType((short) 7, "application/commonground"); + addMIMEType((short) 8, "application/cu-seeme", "cu"); + addMIMEType((short) 9, "application/cybercash"); + addMIMEType((short) 10, "application/dca-rft"); + addMIMEType((short) 11, "application/dec-dx"); + addMIMEType((short) 12, "application/docbook+xml"); + addMIMEType((short) 13, "application/dsptype", "tsp"); + addMIMEType((short) 14, "application/dvcs"); + addMIMEType((short) 15, "application/edi-consent"); + addMIMEType((short) 16, "application/edi-x12"); + addMIMEType((short) 17, "application/edifact"); + addMIMEType((short) 18, "application/eshop"); + addMIMEType((short) 19, "application/font-tdpfr"); + addMIMEType((short) 20, "application/futuresplash", "spl"); + addMIMEType((short) 21, "application/ghostview"); + addMIMEType((short) 22, "application/hta", "hta"); + addMIMEType((short) 23, "application/http"); + addMIMEType((short) 24, "application/hyperstudio"); + addMIMEType((short) 25, "application/iges"); + addMIMEType((short) 26, "application/index"); + addMIMEType((short) 27, "application/index.cmd"); + addMIMEType((short) 28, "application/index.obj"); + addMIMEType((short) 29, "application/index.response"); + addMIMEType((short) 30, "application/index.vnd"); + addMIMEType((short) 31, "application/iotp"); + addMIMEType((short) 32, "application/ipp"); + addMIMEType((short) 33, "application/isup"); + addMIMEType((short) 34, "application/java-archive", "jar"); + addMIMEType((short) 35, "application/java-serialized-object", "ser"); + addMIMEType((short) 36, "application/java-vm", "class"); + addMIMEType((short) 37, "application/mac-binhex40", "hqx"); + addMIMEType((short) 38, "application/mac-compactpro", "cpt"); + addMIMEType((short) 39, "application/macwriteii"); + addMIMEType((short) 40, "application/marc"); + addMIMEType((short) 41, "application/mathematica", "nb"); + addMIMEType((short) 42, "application/mathematica-old"); + addMIMEType((short) 43, "application/msaccess", "mdb"); + addMIMEType((short) 44, "application/msword", "doc dot"); + addMIMEType((short) 45, "application/news-message-id"); + addMIMEType((short) 46, "application/news-transmission"); + addMIMEType((short) 47, "application/ocsp-request"); + addMIMEType((short) 48, "application/ocsp-response"); + addMIMEType((short) 49, "application/octet-stream", "bin"); + addMIMEType((short) 50, "application/oda", "oda"); + addMIMEType((short) 51, "application/ogg", "ogg"); + addMIMEType((short) 52, "application/parityfec"); + addMIMEType((short) 53, "application/pdf", "pdf"); + addMIMEType((short) 54, "application/pgp-encrypted"); + addMIMEType((short) 55, "application/pgp-keys", "key"); + addMIMEType((short) 56, "application/pgp-signature", "pgp"); + addMIMEType((short) 57, "application/pics-rules", "prf"); + addMIMEType((short) 58, "application/pkcs10"); + addMIMEType((short) 59, "application/pkcs7-mime"); + addMIMEType((short) 60, "application/pkcs7-signature"); + addMIMEType((short) 61, "application/pkix-cert"); + addMIMEType((short) 62, "application/pkix-crl"); + addMIMEType((short) 63, "application/pkixcmp"); + addMIMEType((short) 64, "application/postscript", "ps ai eps"); + addMIMEType((short) 65, "application/prs.alvestrand.titrax-sheet"); + addMIMEType((short) 66, "application/prs.cww"); + addMIMEType((short) 67, "application/prs.nprend"); + addMIMEType((short) 68, "application/qsig"); + addMIMEType((short) 69, "application/rar", "rar"); + addMIMEType((short) 70, "application/rdf+xml", "rdf"); + addMIMEType((short) 71, "application/remote-printing"); + addMIMEType((short) 72, "application/riscos"); + addMIMEType((short) 73, "application/rss+xml", "rss"); + addMIMEType((short) 74, "application/rtf"); + addMIMEType((short) 75, "application/sdp"); + addMIMEType((short) 76, "application/set-payment"); + addMIMEType((short) 77, "application/set-payment-initiation"); + addMIMEType((short) 78, "application/set-registration"); + addMIMEType((short) 79, "application/set-registration-initiation"); + addMIMEType((short) 80, "application/sgml"); + addMIMEType((short) 81, "application/sgml-open-catalog"); + addMIMEType((short) 82, "application/sieve"); + addMIMEType((short) 83, "application/slate"); + addMIMEType((short) 84, "application/smil", "smi smil"); + addMIMEType((short) 85, "application/timestamp-query"); + addMIMEType((short) 86, "application/timestamp-reply"); + addMIMEType((short) 87, "application/vemmi"); + addMIMEType((short) 88, "application/whoispp-query"); + addMIMEType((short) 89, "application/whoispp-response"); + addMIMEType((short) 90, "application/wita"); + addMIMEType((short) 91, "application/wordperfect", "wpd"); + addMIMEType((short) 92, "application/wordperfect5.1", "wp5"); + addMIMEType((short) 93, "application/x400-bp"); + addMIMEType((short) 94, "application/xhtml+xml", "xhtml xht"); + addMIMEType((short) 95, "application/xml", "xml xsl"); + addMIMEType((short) 96, "application/xml-dtd"); + addMIMEType((short) 97, "application/xml-external-parsed-entity"); + addMIMEType((short) 98, "application/zip", "zip"); + addMIMEType((short) 99, "application/vnd.3M.Post-it-Notes"); + addMIMEType((short) 100, "application/vnd.accpac.simply.aso"); + addMIMEType((short) 101, "application/vnd.accpac.simply.imp"); + addMIMEType((short) 102, "application/vnd.acucobol"); + addMIMEType((short) 103, "application/vnd.aether.imp"); + addMIMEType((short) 104, "application/vnd.anser-web-certificate-issue-initiation"); + addMIMEType((short) 105, "application/vnd.anser-web-funds-transfer-initiation"); + addMIMEType((short) 106, "application/vnd.audiograph"); + addMIMEType((short) 107, "application/vnd.bmi"); + addMIMEType((short) 108, "application/vnd.businessobjects"); + addMIMEType((short) 109, "application/vnd.canon-cpdl"); + addMIMEType((short) 110, "application/vnd.canon-lips"); + addMIMEType((short) 111, "application/vnd.cinderella", "cdy"); + addMIMEType((short) 112, "application/vnd.claymore"); + addMIMEType((short) 113, "application/vnd.commerce-battelle"); + addMIMEType((short) 114, "application/vnd.commonspace"); + addMIMEType((short) 115, "application/vnd.comsocaller"); + addMIMEType((short) 116, "application/vnd.contact.cmsg"); + addMIMEType((short) 117, "application/vnd.cosmocaller"); + addMIMEType((short) 118, "application/vnd.ctc-posml"); + addMIMEType((short) 119, "application/vnd.cups-postscript"); + addMIMEType((short) 120, "application/vnd.cups-raster"); + addMIMEType((short) 121, "application/vnd.cups-raw"); + addMIMEType((short) 122, "application/vnd.cybank"); + addMIMEType((short) 123, "application/vnd.dna"); + addMIMEType((short) 124, "application/vnd.dpgraph"); + addMIMEType((short) 125, "application/vnd.dxr"); + addMIMEType((short) 126, "application/vnd.ecdis-update"); + addMIMEType((short) 127, "application/vnd.ecowin.chart"); + addMIMEType((short) 128, "application/vnd.ecowin.filerequest"); + addMIMEType((short) 129, "application/vnd.ecowin.fileupdate"); + addMIMEType((short) 130, "application/vnd.ecowin.series"); + addMIMEType((short) 131, "application/vnd.ecowin.seriesrequest"); + addMIMEType((short) 132, "application/vnd.ecowin.seriesupdate"); + addMIMEType((short) 133, "application/vnd.enliven"); + addMIMEType((short) 134, "application/vnd.epson.esf"); + addMIMEType((short) 135, "application/vnd.epson.msf"); + addMIMEType((short) 136, "application/vnd.epson.quickanime"); + addMIMEType((short) 137, "application/vnd.epson.salt"); + addMIMEType((short) 138, "application/vnd.epson.ssf"); + addMIMEType((short) 139, "application/vnd.ericsson.quickcall"); + addMIMEType((short) 140, "application/vnd.eudora.data"); + addMIMEType((short) 141, "application/vnd.fdf"); + addMIMEType((short) 142, "application/vnd.ffsns"); + addMIMEType((short) 143, "application/vnd.flographit"); + addMIMEType((short) 144, "application/vnd.framemaker"); + addMIMEType((short) 145, "application/vnd.fsc.weblaunch"); + addMIMEType((short) 146, "application/vnd.fujitsu.oasys"); + addMIMEType((short) 147, "application/vnd.fujitsu.oasys2"); + addMIMEType((short) 148, "application/vnd.fujitsu.oasys3"); + addMIMEType((short) 149, "application/vnd.fujitsu.oasysgp"); + addMIMEType((short) 150, "application/vnd.fujitsu.oasysprs"); + addMIMEType((short) 151, "application/vnd.fujixerox.ddd"); + addMIMEType((short) 152, "application/vnd.fujixerox.docuworks"); + addMIMEType((short) 153, "application/vnd.fujixerox.docuworks.binder"); + addMIMEType((short) 154, "application/vnd.fut-misnet"); + addMIMEType((short) 155, "application/vnd.grafeq"); + addMIMEType((short) 156, "application/vnd.groove-account"); + addMIMEType((short) 157, "application/vnd.groove-identity-message"); + addMIMEType((short) 158, "application/vnd.groove-injector"); + addMIMEType((short) 159, "application/vnd.groove-tool-message"); + addMIMEType((short) 160, "application/vnd.groove-tool-template"); + addMIMEType((short) 161, "application/vnd.groove-vcard"); + addMIMEType((short) 162, "application/vnd.hhe.lesson-player"); + addMIMEType((short) 163, "application/vnd.hp-HPGL"); + addMIMEType((short) 164, "application/vnd.hp-PCL"); + addMIMEType((short) 165, "application/vnd.hp-PCLXL"); + addMIMEType((short) 166, "application/vnd.hp-hpid"); + addMIMEType((short) 167, "application/vnd.hp-hps"); + addMIMEType((short) 168, "application/vnd.httphone"); + addMIMEType((short) 169, "application/vnd.hzn-3d-crossword"); + addMIMEType((short) 170, "application/vnd.ibm.MiniPay"); + addMIMEType((short) 171, "application/vnd.ibm.afplinedata"); + addMIMEType((short) 172, "application/vnd.ibm.modcap"); + addMIMEType((short) 173, "application/vnd.informix-visionary"); + addMIMEType((short) 174, "application/vnd.intercon.formnet"); + addMIMEType((short) 175, "application/vnd.intertrust.digibox"); + addMIMEType((short) 176, "application/vnd.intertrust.nncp"); + addMIMEType((short) 177, "application/vnd.intu.qbo"); + addMIMEType((short) 178, "application/vnd.intu.qfx"); + addMIMEType((short) 179, "application/vnd.irepository.package+xml"); + addMIMEType((short) 180, "application/vnd.is-xpr"); + addMIMEType((short) 181, "application/vnd.japannet-directory-service"); + addMIMEType((short) 182, "application/vnd.japannet-jpnstore-wakeup"); + addMIMEType((short) 183, "application/vnd.japannet-payment-wakeup"); + addMIMEType((short) 184, "application/vnd.japannet-registration"); + addMIMEType((short) 185, "application/vnd.japannet-registration-wakeup"); + addMIMEType((short) 186, "application/vnd.japannet-setstore-wakeup"); + addMIMEType((short) 187, "application/vnd.japannet-verification"); + addMIMEType((short) 188, "application/vnd.japannet-verification-wakeup"); + addMIMEType((short) 189, "application/vnd.koan"); + addMIMEType((short) 190, "application/vnd.lotus-1-2-3"); + addMIMEType((short) 191, "application/vnd.lotus-approach"); + addMIMEType((short) 192, "application/vnd.lotus-freelance"); + addMIMEType((short) 193, "application/vnd.lotus-notes"); + addMIMEType((short) 194, "application/vnd.lotus-organizer"); + addMIMEType((short) 195, "application/vnd.lotus-screencam"); + addMIMEType((short) 196, "application/vnd.lotus-wordpro"); + addMIMEType((short) 197, "application/vnd.mcd"); + addMIMEType((short) 198, "application/vnd.mediastation.cdkey"); + addMIMEType((short) 199, "application/vnd.meridian-slingshot"); + addMIMEType((short) 200, "application/vnd.mif"); + addMIMEType((short) 201, "application/vnd.minisoft-hp3000-save"); + addMIMEType((short) 202, "application/vnd.mitsubishi.misty-guard.trustweb"); + addMIMEType((short) 203, "application/vnd.mobius.daf"); + addMIMEType((short) 204, "application/vnd.mobius.dis"); + addMIMEType((short) 205, "application/vnd.mobius.msl"); + addMIMEType((short) 206, "application/vnd.mobius.plc"); + addMIMEType((short) 207, "application/vnd.mobius.txf"); + addMIMEType((short) 208, "application/vnd.motorola.flexsuite"); + addMIMEType((short) 209, "application/vnd.motorola.flexsuite.adsi"); + addMIMEType((short) 210, "application/vnd.motorola.flexsuite.fis"); + addMIMEType((short) 211, "application/vnd.motorola.flexsuite.gotap"); + addMIMEType((short) 212, "application/vnd.motorola.flexsuite.kmr"); + addMIMEType((short) 213, "application/vnd.motorola.flexsuite.ttc"); + addMIMEType((short) 214, "application/vnd.motorola.flexsuite.wem"); + addMIMEType((short) 215, "application/vnd.mozilla.xul+xml", "xul"); + addMIMEType((short) 216, "application/vnd.ms-artgalry"); + addMIMEType((short) 217, "application/vnd.ms-asf"); + addMIMEType((short) 218, "application/vnd.ms-excel", "xls xlb xlt"); + addMIMEType((short) 219, "application/vnd.ms-lrm"); + addMIMEType((short) 220, "application/vnd.ms-pki.seccat", "cat"); + addMIMEType((short) 221, "application/vnd.ms-pki.stl", "stl"); + addMIMEType((short) 222, "application/vnd.ms-powerpoint", "ppt pps"); + addMIMEType((short) 223, "application/vnd.ms-project"); + addMIMEType((short) 224, "application/vnd.ms-tnef"); + addMIMEType((short) 225, "application/vnd.ms-works"); + addMIMEType((short) 226, "application/vnd.mseq"); + addMIMEType((short) 227, "application/vnd.msign"); + addMIMEType((short) 228, "application/vnd.music-niff"); + addMIMEType((short) 229, "application/vnd.musician"); + addMIMEType((short) 230, "application/vnd.netfpx"); + addMIMEType((short) 231, "application/vnd.noblenet-directory"); + addMIMEType((short) 232, "application/vnd.noblenet-sealer"); + addMIMEType((short) 233, "application/vnd.noblenet-web"); + addMIMEType((short) 234, "application/vnd.novadigm.EDM"); + addMIMEType((short) 235, "application/vnd.novadigm.EDX"); + addMIMEType((short) 236, "application/vnd.novadigm.EXT"); + addMIMEType((short) 237, "application/vnd.oasis.opendocument.chart", "odc"); + addMIMEType((short) 238, "application/vnd.oasis.opendocument.database", "odb"); + addMIMEType((short) 239, "application/vnd.oasis.opendocument.formula", "odf"); + addMIMEType((short) 240, "application/vnd.oasis.opendocument.graphics", "odg"); + addMIMEType((short) 241, "application/vnd.oasis.opendocument.graphics-template", "otg"); + addMIMEType((short) 242, "application/vnd.oasis.opendocument.image", "odi"); + addMIMEType((short) 243, "application/vnd.oasis.opendocument.presentation", "odp"); + addMIMEType((short) 244, "application/vnd.oasis.opendocument.presentation-template", "otp"); + addMIMEType((short) 245, "application/vnd.oasis.opendocument.spreadsheet", "ods"); + addMIMEType((short) 246, "application/vnd.oasis.opendocument.spreadsheet-template", "ots"); + addMIMEType((short) 247, "application/vnd.oasis.opendocument.text", "odt"); + addMIMEType((short) 248, "application/vnd.oasis.opendocument.text-master", "odm"); + addMIMEType((short) 249, "application/vnd.oasis.opendocument.text-template", "ott"); + addMIMEType((short) 250, "application/vnd.oasis.opendocument.text-web", "oth"); + addMIMEType((short) 251, "application/vnd.osa.netdeploy"); + addMIMEType((short) 252, "application/vnd.palm"); + addMIMEType((short) 253, "application/vnd.pg.format"); + addMIMEType((short) 254, "application/vnd.pg.osasli"); + addMIMEType((short) 255, "application/vnd.powerbuilder6"); + addMIMEType((short) 256, "application/vnd.powerbuilder6-s"); + addMIMEType((short) 257, "application/vnd.powerbuilder7"); + addMIMEType((short) 258, "application/vnd.powerbuilder7-s"); + addMIMEType((short) 259, "application/vnd.powerbuilder75"); + addMIMEType((short) 260, "application/vnd.powerbuilder75-s"); + addMIMEType((short) 261, "application/vnd.previewsystems.box"); + addMIMEType((short) 262, "application/vnd.publishare-delta-tree"); + addMIMEType((short) 263, "application/vnd.pvi.ptid1"); + addMIMEType((short) 264, "application/vnd.pwg-xhtml-print+xml"); + addMIMEType((short) 265, "application/vnd.rapid"); + addMIMEType((short) 266, "application/vnd.rim.cod", "cod"); + addMIMEType((short) 267, "application/vnd.s3sms"); + addMIMEType((short) 268, "application/vnd.seemail"); + addMIMEType((short) 269, "application/vnd.shana.informed.formdata"); + addMIMEType((short) 270, "application/vnd.shana.informed.formtemplate"); + addMIMEType((short) 271, "application/vnd.shana.informed.interchange"); + addMIMEType((short) 272, "application/vnd.shana.informed.package"); + addMIMEType((short) 273, "application/vnd.smaf", "mmf"); + addMIMEType((short) 274, "application/vnd.sss-cod"); + addMIMEType((short) 275, "application/vnd.sss-dtf"); + addMIMEType((short) 276, "application/vnd.sss-ntf"); + addMIMEType((short) 277, "application/vnd.stardivision.calc", "sdc"); + addMIMEType((short) 278, "application/vnd.stardivision.draw", "sda"); + addMIMEType((short) 279, "application/vnd.stardivision.impress", "sdd sdp"); + addMIMEType((short) 280, "application/vnd.stardivision.math", "smf"); + addMIMEType((short) 281, "application/vnd.stardivision.writer", "sdw vor"); + addMIMEType((short) 282, "application/vnd.stardivision.writer-global", "sgl"); + addMIMEType((short) 283, "application/vnd.street-stream"); + addMIMEType((short) 284, "application/vnd.sun.xml.calc", "sxc"); + addMIMEType((short) 285, "application/vnd.sun.xml.calc.template", "stc"); + addMIMEType((short) 286, "application/vnd.sun.xml.draw", "sxd"); + addMIMEType((short) 287, "application/vnd.sun.xml.draw.template", "std"); + addMIMEType((short) 288, "application/vnd.sun.xml.impress", "sxi"); + addMIMEType((short) 289, "application/vnd.sun.xml.impress.template", "sti"); + addMIMEType((short) 290, "application/vnd.sun.xml.math", "sxm"); + addMIMEType((short) 291, "application/vnd.sun.xml.writer", "sxw"); + addMIMEType((short) 292, "application/vnd.sun.xml.writer.global", "sxg"); + addMIMEType((short) 293, "application/vnd.sun.xml.writer.template", "stw"); + addMIMEType((short) 294, "application/vnd.svd"); + addMIMEType((short) 295, "application/vnd.swiftview-ics"); + addMIMEType((short) 296, "application/vnd.symbian.install", "sis"); + addMIMEType((short) 297, "application/vnd.triscape.mxs"); + addMIMEType((short) 298, "application/vnd.trueapp"); + addMIMEType((short) 299, "application/vnd.truedoc"); + addMIMEType((short) 300, "application/vnd.tve-trigger"); + addMIMEType((short) 301, "application/vnd.ufdl"); + addMIMEType((short) 302, "application/vnd.uplanet.alert"); + addMIMEType((short) 303, "application/vnd.uplanet.alert-wbxml"); + addMIMEType((short) 304, "application/vnd.uplanet.bearer-choice"); + addMIMEType((short) 305, "application/vnd.uplanet.bearer-choice-wbxml"); + addMIMEType((short) 306, "application/vnd.uplanet.cacheop"); + addMIMEType((short) 307, "application/vnd.uplanet.cacheop-wbxml"); + addMIMEType((short) 308, "application/vnd.uplanet.channel"); + addMIMEType((short) 309, "application/vnd.uplanet.channel-wbxml"); + addMIMEType((short) 310, "application/vnd.uplanet.list"); + addMIMEType((short) 311, "application/vnd.uplanet.list-wbxml"); + addMIMEType((short) 312, "application/vnd.uplanet.listcmd"); + addMIMEType((short) 313, "application/vnd.uplanet.listcmd-wbxml"); + addMIMEType((short) 314, "application/vnd.uplanet.signal"); + addMIMEType((short) 315, "application/vnd.vcx"); + addMIMEType((short) 316, "application/vnd.vectorworks"); + addMIMEType((short) 317, "application/vnd.vidsoft.vidconference"); + addMIMEType((short) 318, "application/vnd.visio", "vsd"); + addMIMEType((short) 319, "application/vnd.vividence.scriptfile"); + addMIMEType((short) 320, "application/vnd.wap.sic"); + addMIMEType((short) 321, "application/vnd.wap.slc"); + addMIMEType((short) 322, "application/vnd.wap.wbxml", "wbxml"); + addMIMEType((short) 323, "application/vnd.wap.wmlc", "wmlc"); + addMIMEType((short) 324, "application/vnd.wap.wmlscriptc", "wmlsc"); + addMIMEType((short) 325, "application/vnd.webturbo"); + addMIMEType((short) 326, "application/vnd.wrq-hp3000-labelled"); + addMIMEType((short) 327, "application/vnd.wt.stf"); + addMIMEType((short) 328, "application/vnd.xara"); + addMIMEType((short) 329, "application/vnd.xfdl"); + addMIMEType((short) 330, "application/vnd.yellowriver-custom-menu"); + addMIMEType((short) 331, "application/x-123", "wk"); + addMIMEType((short) 332, "application/x-abiword", "abw"); + addMIMEType((short) 333, "application/x-apple-diskimage", "dmg"); + addMIMEType((short) 334, "application/x-bcpio", "bcpio"); + addMIMEType((short) 335, "application/x-bittorrent", "torrent"); + addMIMEType((short) 336, "application/x-cdf", "cdf"); + addMIMEType((short) 337, "application/x-cdlink", "vcd"); + addMIMEType((short) 338, "application/x-chess-pgn", "pgn"); + addMIMEType((short) 339, "application/x-core"); + addMIMEType((short) 340, "application/x-cpio", "cpio"); + addMIMEType((short) 341, "application/x-csh", "csh"); + addMIMEType((short) 342, "application/x-debian-package", "deb udeb"); + addMIMEType((short) 343, "application/x-director", "dcr dir dxr"); + addMIMEType((short) 344, "application/x-dms", "dms"); + addMIMEType((short) 345, "application/x-doom", "wad"); + addMIMEType((short) 346, "application/x-dvi", "dvi"); + addMIMEType((short) 347, "application/x-executable"); + addMIMEType((short) 348, "application/x-flac", "flac"); + addMIMEType((short) 349, "application/x-font", "pfa pfb gsf pcf pcf.Z"); + addMIMEType((short) 350, "application/x-freemind", "mm"); + addMIMEType((short) 351, "application/x-futuresplash", "spl"); + addMIMEType((short) 352, "application/x-gnumeric", "gnumeric"); + addMIMEType((short) 353, "application/x-go-sgf", "sgf"); + addMIMEType((short) 354, "application/x-graphing-calculator", "gcf"); + addMIMEType((short) 355, "application/x-gtar", "gtar tgz taz"); + addMIMEType((short) 356, "application/x-hdf", "hdf"); + addMIMEType((short) 357, "application/x-httpd-php", "phtml pht php"); + addMIMEType((short) 358, "application/x-httpd-php-source", "phps"); + addMIMEType((short) 359, "application/x-httpd-php3", "php3"); + addMIMEType((short) 360, "application/x-httpd-php3-preprocessed", "php3p"); + addMIMEType((short) 361, "application/x-httpd-php4", "php4"); + addMIMEType((short) 362, "application/x-ica", "ica"); + addMIMEType((short) 363, "application/x-internet-signup", "ins isp"); + addMIMEType((short) 364, "application/x-iphone", "iii"); + addMIMEType((short) 365, "application/x-iso9660-image", "iso"); + addMIMEType((short) 366, "application/x-java-applet"); + addMIMEType((short) 367, "application/x-java-bean"); + addMIMEType((short) 368, "application/x-java-jnlp-file", "jnlp"); + addMIMEType((short) 369, "application/x-javascript", "js"); + addMIMEType((short) 370, "application/x-jmol", "jmz"); + addMIMEType((short) 371, "application/x-kchart", "chrt"); + addMIMEType((short) 372, "application/x-kdelnk"); + addMIMEType((short) 373, "application/x-killustrator", "kil"); + addMIMEType((short) 374, "application/x-koan", "skp skd skt skm"); + addMIMEType((short) 375, "application/x-kpresenter", "kpr kpt"); + addMIMEType((short) 376, "application/x-kspread", "ksp"); + addMIMEType((short) 377, "application/x-kword", "kwd kwt"); + addMIMEType((short) 378, "application/x-latex", "latex"); + addMIMEType((short) 379, "application/x-lha", "lha"); + addMIMEType((short) 380, "application/x-lzh", "lzh"); + addMIMEType((short) 381, "application/x-lzx", "lzx"); + addMIMEType((short) 382, "application/x-maker", "frm maker frame fm fb book fbdoc"); + addMIMEType((short) 383, "application/x-mif", "mif"); + addMIMEType((short) 384, "application/x-ms-wmd", "wmd"); + addMIMEType((short) 385, "application/x-ms-wmz", "wmz"); + addMIMEType((short) 386, "application/x-msdos-program", "com exe bat dll"); + addMIMEType((short) 387, "application/x-msi", "msi"); + addMIMEType((short) 388, "application/x-netcdf", "nc"); + addMIMEType((short) 389, "application/x-ns-proxy-autoconfig", "pac"); + addMIMEType((short) 390, "application/x-nwc", "nwc"); + addMIMEType((short) 391, "application/x-object", "o"); + addMIMEType((short) 392, "application/x-oz-application", "oza"); + addMIMEType((short) 393, "application/x-pkcs7-certreqresp", "p7r"); + addMIMEType((short) 394, "application/x-pkcs7-crl", "crl"); + addMIMEType((short) 395, "application/x-python-code", "pyc pyo"); + addMIMEType((short) 396, "application/x-quicktimeplayer", "qtl"); + addMIMEType((short) 397, "application/x-redhat-package-manager", "rpm"); + addMIMEType((short) 398, "application/x-rx"); + addMIMEType((short) 399, "application/x-sh", "sh"); + addMIMEType((short) 400, "application/x-shar", "shar"); + addMIMEType((short) 401, "application/x-shellscript"); + addMIMEType((short) 402, "application/x-shockwave-flash", "swf swfl"); + addMIMEType((short) 403, "application/x-stuffit", "sit"); + addMIMEType((short) 404, "application/x-sv4cpio", "sv4cpio"); + addMIMEType((short) 405, "application/x-sv4crc", "sv4crc"); + addMIMEType((short) 406, "application/x-tar", "tar"); + addMIMEType((short) 407, "application/x-tcl", "tcl"); + addMIMEType((short) 408, "application/x-tex-gf", "gf"); + addMIMEType((short) 409, "application/x-tex-pk", "pk"); + addMIMEType((short) 410, "application/x-texinfo", "texinfo texi"); + addMIMEType((short) 411, "application/x-trash", "~ % bak old sik"); + addMIMEType((short) 412, "application/x-troff", "t tr roff"); + addMIMEType((short) 413, "application/x-troff-man", "man"); + addMIMEType((short) 414, "application/x-troff-me", "me"); + addMIMEType((short) 415, "application/x-troff-ms", "ms"); + addMIMEType((short) 416, "application/x-ustar", "ustar"); + addMIMEType((short) 417, "application/x-videolan"); + addMIMEType((short) 418, "application/x-wais-source", "src"); + addMIMEType((short) 419, "application/x-wingz", "wz"); + addMIMEType((short) 420, "application/x-x509-ca-cert", "crt"); + addMIMEType((short) 421, "application/x-xcf", "xcf"); + addMIMEType((short) 422, "application/x-xfig", "fig"); + addMIMEType((short) 423, "application/x-xpinstall", "xpi"); + addMIMEType((short) 424, "audio/32kadpcm"); + addMIMEType((short) 425, "audio/basic", "au snd"); + addMIMEType((short) 426, "audio/g.722.1"); + addMIMEType((short) 427, "audio/l16"); + addMIMEType((short) 428, "audio/midi", "mid midi kar"); + addMIMEType((short) 429, "audio/mp4a-latm"); + addMIMEType((short) 430, "audio/mpa-robust"); + addMIMEType((short) 431, "audio/mpeg", "mpga mpega mp2 mp3 m4a"); + addMIMEType((short) 432, "audio/mpegurl", "m3u"); + addMIMEType((short) 433, "audio/parityfec"); + addMIMEType((short) 434, "audio/prs.sid", "sid"); + addMIMEType((short) 435, "audio/telephone-event"); + addMIMEType((short) 436, "audio/tone"); + addMIMEType((short) 437, "audio/vnd.cisco.nse"); + addMIMEType((short) 438, "audio/vnd.cns.anp1"); + addMIMEType((short) 439, "audio/vnd.cns.inf1"); + addMIMEType((short) 440, "audio/vnd.digital-winds"); + addMIMEType((short) 441, "audio/vnd.everad.plj"); + addMIMEType((short) 442, "audio/vnd.lucent.voice"); + addMIMEType((short) 443, "audio/vnd.nortel.vbk"); + addMIMEType((short) 444, "audio/vnd.nuera.ecelp4800"); + addMIMEType((short) 445, "audio/vnd.nuera.ecelp7470"); + addMIMEType((short) 446, "audio/vnd.nuera.ecelp9600"); + addMIMEType((short) 447, "audio/vnd.octel.sbc"); + addMIMEType((short) 448, "audio/vnd.qcelp"); + addMIMEType((short) 449, "audio/vnd.rhetorex.32kadpcm"); + addMIMEType((short) 450, "audio/vnd.vmx.cvsd"); + addMIMEType((short) 451, "audio/x-aiff", "aif aiff aifc"); + addMIMEType((short) 452, "audio/x-gsm", "gsm"); + addMIMEType((short) 453, "audio/x-mpegurl", "m3u"); + addMIMEType((short) 454, "audio/x-ms-wma", "wma"); + addMIMEType((short) 455, "audio/x-ms-wax", "wax"); + addMIMEType((short) 456, "audio/x-pn-realaudio-plugin"); + addMIMEType((short) 457, "audio/x-pn-realaudio", "ra rm ram"); + addMIMEType((short) 458, "audio/x-realaudio", "ra"); + addMIMEType((short) 459, "audio/x-scpls", "pls"); + addMIMEType((short) 460, "audio/x-sd2", "sd2"); + addMIMEType((short) 461, "audio/x-wav", "wav"); + addMIMEType((short) 462, "chemical/x-alchemy", "alc"); + addMIMEType((short) 463, "chemical/x-cache", "cac cache"); + addMIMEType((short) 464, "chemical/x-cache-csf", "csf"); + addMIMEType((short) 465, "chemical/x-cactvs-binary", "cbin cascii ctab"); + addMIMEType((short) 466, "chemical/x-cdx", "cdx"); + addMIMEType((short) 467, "chemical/x-cerius", "cer"); + addMIMEType((short) 468, "chemical/x-chem3d", "c3d"); + addMIMEType((short) 469, "chemical/x-chemdraw", "chm"); + addMIMEType((short) 470, "chemical/x-cif", "cif"); + addMIMEType((short) 471, "chemical/x-cmdf", "cmdf"); + addMIMEType((short) 472, "chemical/x-cml", "cml"); + addMIMEType((short) 473, "chemical/x-compass", "cpa"); + addMIMEType((short) 474, "chemical/x-crossfire", "bsd"); + addMIMEType((short) 475, "chemical/x-csml", "csml csm"); + addMIMEType((short) 476, "chemical/x-ctx", "ctx"); + addMIMEType((short) 477, "chemical/x-cxf", "cxf cef"); + addMIMEType((short) 478, "chemical/x-embl-dl-nucleotide", "emb embl"); + addMIMEType((short) 479, "chemical/x-galactic-spc", "spc"); + addMIMEType((short) 480, "chemical/x-gamess-input", "inp gam gamin"); + addMIMEType((short) 481, "chemical/x-gaussian-checkpoint", "fch fchk"); + addMIMEType((short) 482, "chemical/x-gaussian-cube", "cub"); + addMIMEType((short) 483, "chemical/x-gaussian-input", "gau gjc gjf"); + addMIMEType((short) 484, "chemical/x-gaussian-log", "gal"); + addMIMEType((short) 485, "chemical/x-gcg8-sequence", "gcg"); + addMIMEType((short) 486, "chemical/x-genbank", "gen"); + addMIMEType((short) 487, "chemical/x-hin", "hin"); + addMIMEType((short) 488, "chemical/x-isostar", "istr ist"); + addMIMEType((short) 489, "chemical/x-jcamp-dx", "jdx dx"); + addMIMEType((short) 490, "chemical/x-kinemage", "kin"); + addMIMEType((short) 491, "chemical/x-macmolecule", "mcm"); + addMIMEType((short) 492, "chemical/x-macromodel-input", "mmd mmod"); + addMIMEType((short) 493, "chemical/x-mdl-molfile", "mol"); + addMIMEType((short) 494, "chemical/x-mdl-rdfile", "rd"); + addMIMEType((short) 495, "chemical/x-mdl-rxnfile", "rxn"); + addMIMEType((short) 496, "chemical/x-mdl-sdfile", "sd sdf"); + addMIMEType((short) 497, "chemical/x-mdl-tgf", "tgf"); + addMIMEType((short) 498, "chemical/x-mmcif", "mcif"); + addMIMEType((short) 499, "chemical/x-mol2", "mol2"); + addMIMEType((short) 500, "chemical/x-molconn-Z", "b"); + addMIMEType((short) 501, "chemical/x-mopac-graph", "gpt"); + addMIMEType((short) 502, "chemical/x-mopac-input", "mop mopcrt mpc dat zmt"); + addMIMEType((short) 503, "chemical/x-mopac-out", "moo"); + addMIMEType((short) 504, "chemical/x-mopac-vib", "mvb"); + addMIMEType((short) 505, "chemical/x-ncbi-asn1", "asn"); + addMIMEType((short) 506, "chemical/x-ncbi-asn1-ascii", "prt ent"); + addMIMEType((short) 507, "chemical/x-ncbi-asn1-binary", "val aso"); + addMIMEType((short) 508, "chemical/x-ncbi-asn1-spec", "asn"); + addMIMEType((short) 509, "chemical/x-pdb", "pdb ent"); + addMIMEType((short) 510, "chemical/x-rosdal", "ros"); + addMIMEType((short) 511, "chemical/x-swissprot", "sw"); + addMIMEType((short) 512, "chemical/x-vamas-iso14976", "vms"); + addMIMEType((short) 513, "chemical/x-vmd", "vmd"); + addMIMEType((short) 514, "chemical/x-xtel", "xtel"); + addMIMEType((short) 515, "chemical/x-xyz", "xyz"); + addMIMEType((short) 516, "image/cgm"); + addMIMEType((short) 517, "image/g3fax"); + addMIMEType((short) 518, "image/gif", "gif"); + addMIMEType((short) 519, "image/ief", "ief"); + addMIMEType((short) 520, "image/jpeg", "jpeg jpg jpe"); + addMIMEType((short) 521, "image/naplps"); + addMIMEType((short) 522, "image/pcx", "pcx"); + addMIMEType((short) 523, "image/png", "png"); + addMIMEType((short) 524, "image/prs.btif"); + addMIMEType((short) 525, "image/prs.pti"); + addMIMEType((short) 526, "image/svg+xml", "svg svgz"); + addMIMEType((short) 527, "image/tiff", "tiff tif"); + addMIMEType((short) 528, "image/vnd.cns.inf2"); + addMIMEType((short) 529, "image/vnd.djvu", "djvu djv"); + addMIMEType((short) 530, "image/vnd.dwg"); + addMIMEType((short) 531, "image/vnd.dxf"); + addMIMEType((short) 532, "image/vnd.fastbidsheet"); + addMIMEType((short) 533, "image/vnd.fpx"); + addMIMEType((short) 534, "image/vnd.fst"); + addMIMEType((short) 535, "image/vnd.fujixerox.edmics-mmr"); + addMIMEType((short) 536, "image/vnd.fujixerox.edmics-rlc"); + addMIMEType((short) 537, "image/vnd.mix"); + addMIMEType((short) 538, "image/vnd.net-fpx"); + addMIMEType((short) 539, "image/vnd.svf"); + addMIMEType((short) 540, "image/vnd.wap.wbmp", "wbmp"); + addMIMEType((short) 541, "image/vnd.xiff"); + addMIMEType((short) 542, "image/x-cmu-raster", "ras"); + addMIMEType((short) 543, "image/x-coreldraw", "cdr"); + addMIMEType((short) 544, "image/x-coreldrawpattern", "pat"); + addMIMEType((short) 545, "image/x-coreldrawtemplate", "cdt"); + addMIMEType((short) 546, "image/x-corelphotopaint", "cpt"); + addMIMEType((short) 547, "image/x-icon", "ico"); + addMIMEType((short) 548, "image/x-jg", "art"); + addMIMEType((short) 549, "image/x-jng", "jng"); + addMIMEType((short) 550, "image/x-ms-bmp", "bmp"); + addMIMEType((short) 551, "image/x-photoshop", "psd"); + addMIMEType((short) 552, "image/x-portable-anymap", "pnm"); + addMIMEType((short) 553, "image/x-portable-bitmap", "pbm"); + addMIMEType((short) 554, "image/x-portable-graymap", "pgm"); + addMIMEType((short) 555, "image/x-portable-pixmap", "ppm"); + addMIMEType((short) 556, "image/x-rgb", "rgb"); + addMIMEType((short) 557, "image/x-xbitmap", "xbm"); + addMIMEType((short) 558, "image/x-xpixmap", "xpm"); + addMIMEType((short) 559, "image/x-xwindowdump", "xwd"); + addMIMEType((short) 560, "inode/chardevice"); + addMIMEType((short) 561, "inode/blockdevice"); + addMIMEType((short) 562, "inode/directory-locked"); + addMIMEType((short) 563, "inode/directory"); + addMIMEType((short) 564, "inode/fifo"); + addMIMEType((short) 565, "inode/socket"); + addMIMEType((short) 566, "message/delivery-status"); + addMIMEType((short) 567, "message/disposition-notification"); + addMIMEType((short) 568, "message/external-body"); + addMIMEType((short) 569, "message/http"); + addMIMEType((short) 570, "message/s-http"); + addMIMEType((short) 571, "message/news"); + addMIMEType((short) 572, "message/partial"); + addMIMEType((short) 573, "message/rfc822"); + addMIMEType((short) 574, "model/iges", "igs iges"); + addMIMEType((short) 575, "model/mesh", "msh mesh silo"); + addMIMEType((short) 576, "model/vnd.dwf"); + addMIMEType((short) 577, "model/vnd.flatland.3dml"); + addMIMEType((short) 578, "model/vnd.gdl"); + addMIMEType((short) 579, "model/vnd.gs-gdl"); + addMIMEType((short) 580, "model/vnd.gtw"); + addMIMEType((short) 581, "model/vnd.mts"); + addMIMEType((short) 582, "model/vnd.vtu"); + addMIMEType((short) 583, "model/vrml", "wrl vrml"); + addMIMEType((short) 584, "multipart/alternative"); + addMIMEType((short) 585, "multipart/appledouble"); + addMIMEType((short) 586, "multipart/byteranges"); + addMIMEType((short) 587, "multipart/digest"); + addMIMEType((short) 588, "multipart/encrypted"); + addMIMEType((short) 589, "multipart/form-data"); + addMIMEType((short) 590, "multipart/header-set"); + addMIMEType((short) 591, "multipart/mixed"); + addMIMEType((short) 592, "multipart/parallel"); + addMIMEType((short) 593, "multipart/related"); + addMIMEType((short) 594, "multipart/report"); + addMIMEType((short) 595, "multipart/signed"); + addMIMEType((short) 596, "multipart/voice-message"); + addMIMEType((short) 597, "text/calendar", "ics icz"); + addMIMEType((short) 598, "text/comma-separated-values", "csv"); + addMIMEType((short) 599, "text/css", "css"); + addMIMEType((short) 600, "text/directory"); + addMIMEType((short) 601, "text/english"); + addMIMEType((short) 602, "text/enriched"); + addMIMEType((short) 603, "text/h323", "323"); + addMIMEType((short) 604, "text/html", "html htm shtml"); + addMIMEType((short) 605, "text/iuls", "uls"); + addMIMEType((short) 606, "text/mathml", "mml"); + addMIMEType((short) 607, "text/parityfec"); + addMIMEType((short) 608, "text/plain", "asc txt text diff pot"); + addMIMEType((short) 609, "text/prs.lines.tag"); + addMIMEType((short) 610, "text/x-psp", "psp"); + addMIMEType((short) 611, "text/rfc822-headers"); + addMIMEType((short) 612, "text/richtext", "rtx"); + addMIMEType((short) 613, "text/rtf", "rtf"); + addMIMEType((short) 614, "text/scriptlet", "sct wsc"); + addMIMEType((short) 615, "text/t140"); + addMIMEType((short) 616, "text/texmacs", "tm ts"); + addMIMEType((short) 617, "text/tab-separated-values", "tsv"); + addMIMEType((short) 618, "text/uri-list"); + addMIMEType((short) 619, "text/vnd.abc"); + addMIMEType((short) 620, "text/vnd.curl"); + addMIMEType((short) 621, "text/vnd.DMClientScript"); + addMIMEType((short) 622, "text/vnd.flatland.3dml"); + addMIMEType((short) 623, "text/vnd.fly"); + addMIMEType((short) 624, "text/vnd.fmi.flexstor"); + addMIMEType((short) 625, "text/vnd.in3d.3dml"); + addMIMEType((short) 626, "text/vnd.in3d.spot"); + addMIMEType((short) 627, "text/vnd.IPTC.NewsML"); + addMIMEType((short) 628, "text/vnd.IPTC.NITF"); + addMIMEType((short) 629, "text/vnd.latex-z"); + addMIMEType((short) 630, "text/vnd.motorola.reflex"); + addMIMEType((short) 631, "text/vnd.ms-mediapackage"); + addMIMEType((short) 632, "text/vnd.sun.j2me.app-descriptor", "jad"); + addMIMEType((short) 633, "text/vnd.wap.si"); + addMIMEType((short) 634, "text/vnd.wap.sl"); + addMIMEType((short) 635, "text/vnd.wap.wml", "wml"); + addMIMEType((short) 636, "text/vnd.wap.wmlscript", "wmls"); + addMIMEType((short) 637, "text/x-bibtex", "bib"); + addMIMEType((short) 638, "text/x-c++hdr", "h++ hpp hxx hh"); + addMIMEType((short) 639, "text/x-c++src", "c++ cpp cxx cc"); + addMIMEType((short) 640, "text/x-chdr", "h"); + addMIMEType((short) 641, "text/x-crontab"); + addMIMEType((short) 642, "text/x-csh", "csh"); + addMIMEType((short) 643, "text/x-csrc", "c"); + addMIMEType((short) 644, "text/x-haskell", "hs"); + addMIMEType((short) 645, "text/x-java", "java"); + addMIMEType((short) 646, "text/x-literate-haskell", "lhs"); + addMIMEType((short) 647, "text/x-makefile"); + addMIMEType((short) 648, "text/x-moc", "moc"); + addMIMEType((short) 649, "text/x-pascal", "p pas"); + addMIMEType((short) 650, "text/x-pcs-gcd", "gcd"); + addMIMEType((short) 651, "text/x-perl", "pl pm"); + addMIMEType((short) 652, "text/x-python", "py"); + addMIMEType((short) 653, "text/x-server-parsed-html"); + addMIMEType((short) 654, "text/x-setext", "etx"); + addMIMEType((short) 655, "text/x-sh", "sh"); + addMIMEType((short) 656, "text/x-tcl", "tcl tk"); + addMIMEType((short) 657, "text/x-tex", "tex ltx sty cls"); + addMIMEType((short) 658, "text/x-vcalendar", "vcs"); + addMIMEType((short) 659, "text/x-vcard", "vcf"); + addMIMEType((short) 660, "video/dl", "dl"); + addMIMEType((short) 661, "video/dv", "dif dv"); + addMIMEType((short) 662, "video/fli", "fli"); + addMIMEType((short) 663, "video/gl", "gl"); + addMIMEType((short) 664, "video/mpeg", "mpeg mpg mpe"); + addMIMEType((short) 665, "video/mp4", "mp4"); + addMIMEType((short) 666, "video/quicktime", "qt mov"); + addMIMEType((short) 667, "video/mp4v-es"); + addMIMEType((short) 668, "video/parityfec"); + addMIMEType((short) 669, "video/pointer"); + addMIMEType((short) 670, "video/vnd.fvt"); + addMIMEType((short) 671, "video/vnd.motorola.video"); + addMIMEType((short) 672, "video/vnd.motorola.videop"); + addMIMEType((short) 673, "video/vnd.mpegurl", "mxu"); + addMIMEType((short) 674, "video/vnd.mts"); + addMIMEType((short) 675, "video/vnd.nokia.interleaved-multimedia"); + addMIMEType((short) 676, "video/vnd.vivo"); + addMIMEType((short) 677, "video/x-la-asf", "lsf lsx"); + addMIMEType((short) 678, "video/x-mng", "mng"); + addMIMEType((short) 679, "video/x-ms-asf", "asf asx"); + addMIMEType((short) 680, "video/x-ms-wm", "wm"); + addMIMEType((short) 681, "video/x-ms-wmv", "wmv"); + addMIMEType((short) 682, "video/x-ms-wmx", "wmx"); + addMIMEType((short) 683, "video/x-ms-wvx", "wvx"); + addMIMEType((short) 684, "video/x-msvideo", "avi"); + addMIMEType((short) 685, "video/x-sgi-movie", "movie"); + addMIMEType((short) 686, "x-conference/x-cooltalk", "ice"); + addMIMEType((short) 687, "x-world/x-vrml", "vrm vrml wrl"); + } + + /** Guess a MIME type from a filename */ + public static String guessMIMEType(String arg) { + int x = arg.lastIndexOf('.'); + if(x == -1 || x == arg.length()-1) + return DEFAULT_MIME_TYPE; + String ext = arg.substring(x+1).toLowerCase(); + Short mimeIndexOb = mimeTypesByExtension.get(ext); + if(mimeIndexOb != null) { + return mimeTypesByNumber.get(mimeIndexOb.intValue()); + } + return DEFAULT_MIME_TYPE; + } + + public static String getExtension(String type) { + short typeNumber = byName(type); + if(typeNumber < 0) return null; + return primaryExtensionByMimeNumber.get(typeNumber); + } + + public static String[] getAllMIMETypes() { + return mimeTypesByNumber.toArray(new String[mimeTypesByNumber.size()]); + } + +} diff --git a/src/de/todesbaum/util/swing/SortedListModel.java b/src/de/todesbaum/util/swing/SortedListModel.java new file mode 100644 index 0000000..9d341dd --- /dev/null +++ b/src/de/todesbaum/util/swing/SortedListModel.java @@ -0,0 +1,248 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.swing; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import javax.swing.AbstractListModel; + + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: SortedListModel.java 338 2006-03-20 15:40:48Z bombe $ + */ +public class SortedListModel extends AbstractListModel implements List { + + private List elements = new ArrayList(); + + /** + * {@inheritDoc} + */ + public int getSize() { + return size(); + } + + /** + * {@inheritDoc} + */ + public Object getElementAt(int index) { + return elements.get(index); + } + + /** + * {@inheritDoc} + */ + public void add(int index, Object element) { + elements.add(index, element); + Collections.sort(elements); + fireContentsChanged(this, 0, size()); + } + + /** + * {@inheritDoc} + */ + public boolean add(Object o) { + boolean result = elements.add(o); + Collections.sort(elements); + fireContentsChanged(this, 0, size()); + return result; + } + + /** + * {@inheritDoc} + */ + public boolean addAll(Collection c) { + boolean result = elements.addAll(c); + Collections.sort(elements); + fireContentsChanged(this, 0, size()); + return result; + } + + /** + * {@inheritDoc} + */ + public boolean addAll(int index, Collection c) { + boolean result = elements.addAll(index, c); + Collections.sort(elements); + fireContentsChanged(this, 0, size()); + return result; + } + + /** + * {@inheritDoc} + */ + public void clear() { + elements.clear(); + fireContentsChanged(this, 0, size()); + } + + /** + * {@inheritDoc} + */ + public boolean contains(Object o) { + return elements.contains(o); + } + + /** + * {@inheritDoc} + */ + public boolean containsAll(Collection c) { + return elements.containsAll(c); + } + + /** + * {@inheritDoc} + */ + public boolean equals(Object o) { + return elements.equals(o); + } + + /** + * {@inheritDoc} + */ + public Object get(int index) { + return elements.get(index); + } + + /** + * {@inheritDoc} + */ + public int hashCode() { + return elements.hashCode(); + } + + /** + * {@inheritDoc} + */ + public int indexOf(Object o) { + return elements.indexOf(o); + } + + /** + * {@inheritDoc} + */ + public boolean isEmpty() { + return elements.isEmpty(); + } + + /** + * {@inheritDoc} + */ + public Iterator iterator() { + return elements.iterator(); + } + + /** + * {@inheritDoc} + */ + public int lastIndexOf(Object o) { + return elements.lastIndexOf(o); + } + + /** + * {@inheritDoc} + */ + public ListIterator listIterator() { + return elements.listIterator(); + } + + /** + * {@inheritDoc} + */ + public ListIterator listIterator(int index) { + return elements.listIterator(index); + } + + /** + * {@inheritDoc} + */ + public Object remove(int index) { + fireContentsChanged(this, 0, size()); + return elements.remove(index); + } + + /** + * {@inheritDoc} + */ + public boolean remove(Object o) { + fireContentsChanged(this, 0, size()); + return elements.remove(o); + } + + /** + * {@inheritDoc} + */ + public boolean removeAll(Collection c) { + fireContentsChanged(this, 0, size()); + return elements.removeAll(c); + } + + /** + * {@inheritDoc} + */ + public boolean retainAll(Collection c) { + fireContentsChanged(this, 0, size()); + return elements.retainAll(c); + } + + /** + * {@inheritDoc} + */ + public Object set(int index, Object element) { + Object result = elements.set(index, element); + Collections.sort(elements); + fireContentsChanged(this, 0, size()); + return result; + } + + /** + * {@inheritDoc} + */ + public int size() { + return elements.size(); + } + + /** + * {@inheritDoc} + */ + public List subList(int fromIndex, int toIndex) { + return elements.subList(fromIndex, toIndex); + } + + /** + * {@inheritDoc} + */ + public Object[] toArray() { + return elements.toArray(); + } + + /** + * {@inheritDoc} + */ + public Object[] toArray(Object[] a) { + return elements.toArray(a); + } + +} diff --git a/src/de/todesbaum/util/swing/TLabel.java b/src/de/todesbaum/util/swing/TLabel.java new file mode 100644 index 0000000..617f1d7 --- /dev/null +++ b/src/de/todesbaum/util/swing/TLabel.java @@ -0,0 +1,94 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.swing; + +import java.awt.Component; + +import javax.swing.Icon; +import javax.swing.JLabel; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: TLabel.java 280 2006-03-17 20:24:27Z bombe $ + */ +public class TLabel extends JLabel { + + public TLabel() { + super(); + } + + public TLabel(int mnemonic, Component labelFor) { + super(); + setDisplayedMnemonic(mnemonic); + setLabelFor(labelFor); + } + + public TLabel(Icon image) { + super(image); + } + + public TLabel(Icon image, int mnemonic, Component labelFor) { + super(image); + setDisplayedMnemonic(mnemonic); + setLabelFor(labelFor); + } + + public TLabel(Icon image, int horizontalAlignment) { + super(image); + } + + public TLabel(Icon image, int horizontalAlignment, int mnemonic, Component labelFor) { + super(image); + setDisplayedMnemonic(mnemonic); + setLabelFor(labelFor); + } + + public TLabel(String text) { + super(text); + } + + public TLabel(String text, int mnemonic, Component labelFor) { + super(text); + setDisplayedMnemonic(mnemonic); + setLabelFor(labelFor); + setAlignmentX(0.0f); + } + + public TLabel(String text, Icon icon, int horizontalAlignment) { + super(text, icon, horizontalAlignment); + } + + public TLabel(String text, Icon icon, int horizontalAlignment, int mnemonic, Component labelFor) { + super(text, icon, horizontalAlignment); + setDisplayedMnemonic(mnemonic); + setLabelFor(labelFor); + } + + public TLabel(String text, int horizontalAlignment) { + super(text, horizontalAlignment); + } + + public TLabel(String text, int horizontalAlignment, int mnemonic, Component labelFor) { + super(text, horizontalAlignment); + setDisplayedMnemonic(mnemonic); + setLabelFor(labelFor); + } + +} diff --git a/src/de/todesbaum/util/swing/TWizard.java b/src/de/todesbaum/util/swing/TWizard.java new file mode 100644 index 0000000..234f969 --- /dev/null +++ b/src/de/todesbaum/util/swing/TWizard.java @@ -0,0 +1,260 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.swing; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.Icon; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.border.EmptyBorder; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: TWizard.java 426 2006-03-29 18:02:50Z bombe $ + */ +public class TWizard extends JFrame implements WindowListener { + + protected List wizardListeners = new ArrayList(); + + private Action previousAction; + private Action nextAction; + private Action quitAction; + private JLabel pageIcon; + private JPanel pagePanel; + private JLabel pageHeading; + private JLabel pageDescription; + + protected void frameInit() { + super.frameInit(); + setResizable(false); + addWindowListener(this); + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + createActions(); + + pageIcon = new JLabel(); + pageIcon.setVerticalAlignment(SwingConstants.TOP); + pageHeading = new JLabel(); + pageHeading.setFont(pageHeading.getFont().deriveFont(pageHeading.getFont().getSize() * 2.0f).deriveFont(Font.BOLD)); + pageDescription = new JLabel(); + + JPanel contentPane = new JPanel(new BorderLayout(12, 12)); + contentPane.setBorder(new EmptyBorder(12, 12, 12, 12)); + + JPanel topPanel = new JPanel(new BorderLayout(12, 12)); + contentPane.add(topPanel, BorderLayout.PAGE_START); + + topPanel.add(pageIcon, BorderLayout.LINE_START); + + JPanel textPanel = new JPanel(new BorderLayout(12, 12)); + topPanel.add(textPanel, BorderLayout.CENTER); + textPanel.add(pageHeading, BorderLayout.PAGE_START); + textPanel.add(pageDescription, BorderLayout.CENTER); + + pagePanel = new JPanel(new BorderLayout(12, 12)); + contentPane.add(pagePanel, BorderLayout.CENTER); + + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 12, 12)); + buttonPanel.setBorder(new EmptyBorder(-12, -12, -12, -12)); + buttonPanel.add(new JButton(previousAction)); + buttonPanel.add(new JButton(nextAction)); + buttonPanel.add(new JButton(quitAction)); + contentPane.add(buttonPanel, BorderLayout.PAGE_END); + + setContentPane(contentPane); + } + + @Override + public void pack() { + super.pack(); + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + setLocation((screenSize.width - getWidth()) / 2, (screenSize.height - getHeight()) / 2); + // System.out.println("resized to: " + getWidth() + "x" + getHeight()); + } + + private void createActions() { + previousAction = new AbstractAction("Previous") { + public void actionPerformed(ActionEvent actionEvent) { + actionPrevious(); + } + }; + + nextAction = new AbstractAction("Next") { + public void actionPerformed(ActionEvent actionEvent) { + actionNext(); + } + }; + + quitAction = new AbstractAction("Quit") { + public void actionPerformed(ActionEvent actionEvent) { + actionQuit(); + } + }; + } + + public void addWizardListener(WizardListener wizardListener) { + wizardListeners.add(wizardListener); + } + + public void removeWizardListener(WizardListener wizardListener) { + wizardListeners.remove(wizardListener); + } + + protected void fireWizardPreviousPressed() { + for (WizardListener wizardListener: wizardListeners) { + wizardListener.wizardPreviousPressed(this); + } + } + + protected void fireWizardNextPressed() { + for (WizardListener wizardListener: wizardListeners) { + wizardListener.wizardNextPressed(this); + } + } + + protected void fireWizardQuitPressed() { + for (WizardListener wizardListener: wizardListeners) { + wizardListener.wizardQuitPressed(this); + } + } + + public void setIcon(Icon icon) { + pageIcon.setIcon(icon); + } + + public void setPage(TWizardPage page) { + setVisible(false); + pageHeading.setText(page.getHeading()); + pageDescription.setText(page.getDescription()); + if (pagePanel.getComponentCount() > 0) { + if (pagePanel.getComponent(0) instanceof TWizardPage) { + ((TWizardPage) pagePanel.getComponent(0)).pageDeleted(this); + } + } + pagePanel.removeAll(); + pagePanel.add(page, BorderLayout.CENTER); + page.pageAdded(this); + pack(); + setTitle(page.getHeading()); + setVisible(true); + } + + public TWizardPage getPage() { + return (TWizardPage) pagePanel.getComponent(0); + } + + public void setPreviousEnabled(boolean previousEnabled) { + previousAction.setEnabled(previousEnabled); + } + + public void setPreviousName(String previousName) { + previousAction.putValue(Action.NAME, previousName); + } + + public void setNextEnabled(boolean nextEnabled) { + nextAction.setEnabled(nextEnabled); + } + + public void setNextName(String nextName) { + nextAction.putValue(Action.NAME, nextName); + } + + public void setQuitEnabled(boolean quitEnabled) { + quitAction.setEnabled(quitEnabled); + } + + public void setQuitName(String quitName) { + quitAction.putValue(Action.NAME, quitName); + } + + protected void actionPrevious() { + fireWizardPreviousPressed(); + } + + protected void actionNext() { + fireWizardNextPressed(); + } + + protected void actionQuit() { + fireWizardQuitPressed(); + } + + // + // INTERFACE WindowListener + // + + /** + * {@inheritDoc} + */ + public void windowOpened(WindowEvent e) { + } + + /** + * {@inheritDoc} + */ + public void windowClosing(WindowEvent e) { + fireWizardQuitPressed(); + } + + /** + * {@inheritDoc} + */ + public void windowClosed(WindowEvent e) { + } + + /** + * {@inheritDoc} + */ + public void windowIconified(WindowEvent e) { + } + + /** + * {@inheritDoc} + */ + public void windowDeiconified(WindowEvent e) { + } + + /** + * {@inheritDoc} + */ + public void windowActivated(WindowEvent e) { + } + + /** + * {@inheritDoc} + */ + public void windowDeactivated(WindowEvent e) { + } + +} diff --git a/src/de/todesbaum/util/swing/TWizardPage.java b/src/de/todesbaum/util/swing/TWizardPage.java new file mode 100644 index 0000000..ec5942e --- /dev/null +++ b/src/de/todesbaum/util/swing/TWizardPage.java @@ -0,0 +1,81 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.swing; + +import javax.swing.JPanel; + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: TWizardPage.java 427 2006-03-29 18:03:06Z bombe $ + */ +public class TWizardPage extends JPanel { + + protected String heading; + protected String description; + + public TWizardPage() { + } + + public TWizardPage(String heading) { + this.heading = heading; + } + + public TWizardPage(String heading, String description) { + this(heading); + this.description = description; + } + + /** + * @return Returns the description. + */ + public String getDescription() { + return description; + } + + /** + * @param description + * The description to set. + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * @return Returns the heading. + */ + public String getHeading() { + return heading; + } + + /** + * @param heading + * The heading to set. + */ + public void setHeading(String heading) { + this.heading = heading; + } + + public void pageAdded(TWizard wizard) { + } + + public void pageDeleted(TWizard wizard) { + } + +} diff --git a/src/de/todesbaum/util/swing/WizardListener.java b/src/de/todesbaum/util/swing/WizardListener.java new file mode 100644 index 0000000..b4328fc --- /dev/null +++ b/src/de/todesbaum/util/swing/WizardListener.java @@ -0,0 +1,35 @@ +/* + * todesbaum-lib - + * Copyright (C) 2006 David Roden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.swing; + +import java.util.EventListener; + + +/** + * @author David Roden <droden@gmail.com> + * @version $Id: WizardListener.java 280 2006-03-17 20:24:27Z bombe $ + */ +public interface WizardListener extends EventListener { + + public void wizardNextPressed(TWizard wizard); + public void wizardPreviousPressed(TWizard wizard); + public void wizardQuitPressed(TWizard wizard); + +} diff --git a/src/de/todesbaum/util/xml/SimpleXML.java b/src/de/todesbaum/util/xml/SimpleXML.java new file mode 100644 index 0000000..d400ed8 --- /dev/null +++ b/src/de/todesbaum/util/xml/SimpleXML.java @@ -0,0 +1,308 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.xml; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +/** + * SimpleXML is a helper class to construct XML trees in a fast and simple way. Construct a new XML tree by calling {@link #SimpleXML(String)} and + * append new nodes by calling {@link #append(String)}. + * + * @author David Roden <droden@gmail.com> + * @version $Id:SimpleXML.java 221 2006-03-06 14:46:49Z bombe $ + */ +public class SimpleXML { + + /** + * A {@link List} containing all child nodes of this node. + */ + private List children = new ArrayList(); + + /** + * The name of this node. + */ + private String name = null; + + /** + * The value of this node. + */ + private String value = null; + + /** + * Constructs a new XML node without a name. + */ + public SimpleXML() { + super(); + } + + /** + * Constructs a new XML node with the specified name. + * + * @param name + * The name of the new node + */ + public SimpleXML(String name) { + this.name = name; + } + + /** + * Returns the child node of this node with the specified name. If there are several child nodes with the specified name only the first node is + * returned. + * + * @param nodeName + * The name of the child node + * @return The child node, or null if there is no child node with the specified name + */ + public SimpleXML getNode(String nodeName) { + for (int index = 0, count = children.size(); index < count; index++) { + if (children.get(index).name.equals(nodeName)) { + return children.get(index); + } + } + return null; + } + + /** + * Returns the child node that is specified by the names. The first element of nodeNames is the name of the child node of this + * node, the second element of nodeNames is the name of a child node's child node, and so on. By using this method you can descend + * into an XML tree pretty fast. + * + *

+	 * SimpleXML deepNode = topNode.getNodes(new String[] { "person", "address", "number" });
+	 * 
+ * + * @param nodeNames + * @return A node that is a deep child of this node, or null if the specified node does not eixst + */ + public SimpleXML getNode(String[] nodeNames) { + SimpleXML node = this; + for (String nodeName: nodeNames) { + node = node.getNode(nodeName); + } + return node; + } + + /** + * Returns all child nodes of this node. + * + * @return All child nodes of this node + */ + public SimpleXML[] getNodes() { + return getNodes(null); + } + + /** + * Returns all child nodes of this node with the specified name. If there are no child nodes with the specified name an empty array is returned. + * + * @param nodeName + * The name of the nodes to retrieve, or null to retrieve all nodes + * @return All child nodes with the specified name + */ + public SimpleXML[] getNodes(String nodeName) { + List resultList = new ArrayList(); + for (SimpleXML child: children) { + if ((nodeName == null) || child.name.equals(nodeName)) { + resultList.add(child); + } + } + return resultList.toArray(new SimpleXML[resultList.size()]); + } + + /** + * Appends a new XML node with the specified name and returns the new node. With this method you can create deep structures very fast. + * + *
+	 * SimpleXML mouseNode = topNode.append("computer").append("bus").append("usb").append("mouse");
+	 * 
+ * + * @param nodeName + * The name of the node to append as a child to this node + * @return The new node + */ + public SimpleXML append(String nodeName) { + return append(new SimpleXML(nodeName)); + } + + /** + * Appends a new XML node with the specified name and value and returns the new node. + * + * @param nodeName + * The name of the node to append + * @param nodeValue + * The value of the node to append + * @return The newly appended node + */ + public SimpleXML append(String nodeName, String nodeValue) { + return append(nodeName).setValue(nodeValue); + } + + /** + * Appends the node with all its child nodes to this node and returns the child node. + * + * @param newChild + * The node to append as a child + * @return The child node that was appended + */ + public SimpleXML append(SimpleXML newChild) { + children.add(newChild); + return newChild; + } + + public void remove(SimpleXML child) { + children.remove(child); + } + + public void remove(String childName) { + SimpleXML child = getNode(childName); + if (child != null) { + remove(child); + } + } + + public void replace(String childName, String value) { + remove(childName); + append(childName, value); + } + + public void replace(SimpleXML childNode) { + remove(childNode.getName()); + append(childNode); + } + + public void removeAll() { + children.clear(); + } + + /** + * Sets the value of this node. + * + * @param nodeValue + * The new value of this node + * @return This node + */ + public SimpleXML setValue(String nodeValue) { + value = nodeValue; + return this; + } + + /** + * Returns the name of this node. + * + * @return The name of this node + */ + public String getName() { + return name; + } + + /** + * Returns the value of this node. + * + * @return The value of this node + */ + public String getValue() { + return value; + } + + /** + * Creates a {@link Document} from this node and all its child nodes. + * + * @return The {@link Document} created from this node + */ + public Document getDocument() { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + try { + DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); + Document document = documentBuilder.newDocument(); + Element rootElement = document.createElement(name); + document.appendChild(rootElement); + addChildren(rootElement); + return document; + } catch (ParserConfigurationException e) { + } + return null; + } + + /** + * Appends all children of this node to the specified {@link Element}. If a node has a value that is not null the value is + * appended as a text node. + * + * @param rootElement + * The element to attach this node's children to + */ + private void addChildren(Element rootElement) { + for (SimpleXML child: children) { + Element childElement = rootElement.getOwnerDocument().createElement(child.name); + rootElement.appendChild(childElement); + if (child.value != null) { + Text childText = rootElement.getOwnerDocument().createTextNode(child.value); + childElement.appendChild(childText); + } else { + child.addChildren(childElement); + } + } + } + + /** + * Creates a SimpleXML node from the specified {@link Document}. The SimpleXML node of the document's top-level node is returned. + * + * @param document + * The {@link Document} to create a SimpleXML node from + * @return The SimpleXML node created from the document's top-level node + */ + public static SimpleXML fromDocument(Document document) { + SimpleXML xmlDocument = new SimpleXML(document.getFirstChild().getNodeName()); + document.normalizeDocument(); + return addDocumentChildren(xmlDocument, document.getFirstChild()); + } + + /** + * Appends the child nodes of the specified {@link Document} to this node. Text nodes are converted into a node's value. + * + * @param xmlDocument + * The SimpleXML node to append the child nodes to + * @param document + * The document whose child nodes to append + * @return The SimpleXML node the child nodes were appended to + */ + private static SimpleXML addDocumentChildren(SimpleXML xmlDocument, Node document) { + NodeList childNodes = document.getChildNodes(); + for (int childIndex = 0, childCount = childNodes.getLength(); childIndex < childCount; childIndex++) { + Node childNode = childNodes.item(childIndex); + if ((childNode.getChildNodes().getLength() == 1) && (childNode.getFirstChild().getNodeName().equals("#text")) /*&& (childNode.getFirstChild().getNodeValue().trim().length() != 0)*/) { + xmlDocument.append(childNode.getNodeName(), childNode.getFirstChild().getNodeValue()); + } else { + if (!childNode.getNodeName().equals("#text") || (childNode.getChildNodes().getLength() != 0)) { + SimpleXML newXML = xmlDocument.append(childNode.getNodeName()); + addDocumentChildren(newXML, childNode); + } + } + } + return xmlDocument; + } + +} diff --git a/src/de/todesbaum/util/xml/XML.java b/src/de/todesbaum/util/xml/XML.java new file mode 100644 index 0000000..d84fd75 --- /dev/null +++ b/src/de/todesbaum/util/xml/XML.java @@ -0,0 +1,177 @@ +/* + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package de.todesbaum.util.xml; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.w3c.dom.Document; + + +/** + * Contains method to transform DOM XML trees to byte arrays and vice versa. + * + * @author David Roden <droden@gmail.com> + * @version $Id:XML.java 221 2006-03-06 14:46:49Z bombe $ + */ +public class XML { + + /** Cached document builder factory. */ + private static DocumentBuilderFactory documentBuilderFactory = null; + + /** Cached document builder. */ + private static DocumentBuilder documentBuilder = null; + + /** Cached transformer factory. */ + private static TransformerFactory transformerFactory = null; + + /** Does nothing. */ + private XML() { + } + + /** + * Returns a document builder factory. If possible the cached instance will be returned. + * + * @return A document builder factory + */ + private static DocumentBuilderFactory getDocumentBuilderFactory() { + if (documentBuilderFactory != null) { + return documentBuilderFactory; + } + documentBuilderFactory = DocumentBuilderFactory.newInstance(); + return documentBuilderFactory; + } + + /** + * Returns a document builder. If possible the cached instance will be returned. + * + * @return A document builder + */ + private static DocumentBuilder getDocumentBuilder() { + if (documentBuilder != null) { + return documentBuilder; + } + try { + documentBuilder = getDocumentBuilderFactory().newDocumentBuilder(); + } catch (ParserConfigurationException e) { + } + return documentBuilder; + } + + /** + * Returns a transformer factory. If possible the cached instance will be returned. + * + * @return A transformer factory + */ + private static TransformerFactory getTransformerFactory() { + if (transformerFactory != null) { + return transformerFactory; + } + transformerFactory = TransformerFactory.newInstance(); + return transformerFactory; + } + + /** + * Creates a new XML document. + * + * @return A new XML document + */ + public static Document createDocument() { + return getDocumentBuilder().newDocument(); + } + + /** + * Transforms the DOM XML document into a byte array. + * + * @param document + * The document to transform + * @return The byte array containing the XML representation + */ + public static byte[] transformToByteArray(Document document) { + ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(); + OutputStreamWriter converter = new OutputStreamWriter(byteOutput, Charset.forName("UTF-8")); + Result transformResult = new StreamResult(converter); + Source documentSource = new DOMSource(document); + try { + Transformer transformer = getTransformerFactory().newTransformer(); + transformer.transform(documentSource, transformResult); + byteOutput.close(); + return byteOutput.toByteArray(); + } catch (IOException ioe1) { + } catch (TransformerConfigurationException tce1) { + } catch (TransformerException te1) { + } finally { + try { + byteOutput.close(); + } catch (IOException ioe1) { + } + } + return null; + } + + /** + * Transforms the byte array into a DOM XML document. + * + * @param data + * The byte array to parse + * @return The DOM XML document + */ + public static Document transformToDocument(byte[] data) { + ByteArrayInputStream byteInput = new ByteArrayInputStream(data); + InputStreamReader converter = new InputStreamReader(byteInput, Charset.forName("UTF-8")); + Source xmlSource = new StreamSource(converter); + Result xmlResult = new DOMResult(); + try { + Transformer transformer = getTransformerFactory().newTransformer(); + transformer.transform(xmlSource, xmlResult); + return (Document) ((DOMResult) xmlResult).getNode(); + } catch (TransformerConfigurationException tce1) { + } catch (TransformerException te1) { + } finally { + if (byteInput != null) + try { + byteInput.close(); + } catch (IOException ioe1) { + } + if (converter != null) + try { + converter.close(); + } catch (IOException ioe1) { + } + } + return null; + } + +} -- 2.7.4