rapache-devel team mailing list archive
-
rapache-devel team
-
Mailing list archive
-
Message #00308
[Merge] lp:~alfred-maghi/rapache/ubuntu-10.04 into lp:rapache
Alfred Maghi has proposed merging lp:~alfred-maghi/rapache/ubuntu-10.04 into lp:rapache.
Requested reviews:
Rapache Developers (rapache-devel)
fix rapache for ubuntu-10.04
--
https://code.launchpad.net/~alfred-maghi/rapache/ubuntu-10.04/+merge/25398
Your team Rapache Developers is requested to review the proposed merge of lp:~alfred-maghi/rapache/ubuntu-10.04 into lp:rapache.
=== added file 'AUTHORS'
--- AUTHORS 1970-01-01 00:00:00 +0000
+++ AUTHORS 2010-05-16 16:14:24 +0000
@@ -0,0 +1,39 @@
+ Copyright (C) Rapache Developers 2008 <rapache-devel@xxxxxxxxxxxxxxxxxxx>
+
+ This file is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ main.py is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+Rapache Developers Team:
+
+ * Stefano Forenza <tacone@xxxxxxxxx>
+ * Emanuele Gentili <emgent@xxxxxxxxxx>
+ * Damiano Di Carlo <damianodicarlo@xxxxxxxxx>
+ * Luana Polleggioni <luana@xxxxxxxxxxxxxx>
+ * Jason Tyler <killerkiwi2005@xxxxxxxxx>
+
+Special thanks to (contributors):
+
+ * Andrew H (rugby471)
+ * Sense Hofstede (qense)
+
+Other credits:
+
+glade/browser.png icon taken from browser.svg in Neu theme:
+License: GPL-2
+Homepage: http://www.silvestre.com.ar/
+Name: Silvestre Herrera
+Nickname: ertz
+Location: La Plata, Buenos Aires. ARGENTINA.
+E-mail: silvestre.herrera(at)gmail.com
+Website(s): http://www.silvestre.com.ar/
\ No newline at end of file
=== renamed file 'AUTHORS' => 'AUTHORS.moved'
=== added file 'COPYING'
--- COPYING 1970-01-01 00:00:00 +0000
+++ COPYING 2010-05-16 16:14:24 +0000
@@ -0,0 +1,676 @@
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. 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.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ 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
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU 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 Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
=== renamed file 'COPYING' => 'COPYING.moved'
=== added directory 'Glade'
=== renamed directory 'Glade' => 'Glade.moved'
=== added file 'Glade/apache.lang'
--- Glade/apache.lang 1970-01-01 00:00:00 +0000
+++ Glade/apache.lang 2010-05-16 16:14:24 +0000
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Original version (Ini file highlighting)
+ Author: Antonio Ognio <gnrfan@xxxxxxxxxx>
+ Copyright (C) 2005 Antonio Ognio <gnrfan@xxxxxxxxxx>
+
+ Hacks to support Apache Conf files (adding tag context, support of identation, changing comment char to "#")
+ Author: Stefano Forenza <tacone@xxxxxxxxx>
+ Copyright (C) 2008 Stefano Forenza <tacone@xxxxxxxxx>
+
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 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
+
+-->
+<language id="apache" _name="Apache Confs" version="2.0" _section="Others">
+ <metadata>
+ <property name="mimetypes">text/plain</property>
+ <property name="globs">*.*</property>
+ <property name="line-comment-start">#</property>
+ </metadata>
+
+ <styles>
+ <style id="comment" _name="Comment" map-to="def:comment"/>
+ <style id="floating-point" _name="Floating Point" map-to="def:floating-point"/>
+ <style id="string" _name="String" map-to="def:string"/>
+ <style id="keyword" _name="Keyword" map-to="def:keyword"/>
+ <style id="tag" _name="Tag" map-to="def:keyword"/>
+ <style id="decimal" _name="Decimal" map-to="def:decimal"/>
+ <style id="variable" _name="Variable" map-to="def:type"/>
+ <style id="non-standard-key" _name="Data Type" map-to="def:type"/>
+ <style id="boolean-value" _name="Boolean value" map-to="def:boolean"/>
+ </styles>
+ <default-regex-options case-sensitive="false" />
+
+ <definitions>
+ <context id="line-comment" style-ref="comment" end-at-line-end="true">
+ <start>#</start>
+ </context>
+ <context id="group" style-ref="keyword">
+ <start>^\[</start>
+ <end>\]$</end>
+ </context>
+ <context id="tag">
+ <start><\s*/?\s*[a-zA-Z0-9_]+</start>
+ <end>/?\s*></end>
+ <include>
+ <context sub-pattern="0" where="start" style-ref="tag"/>
+ <context ref="tag_attributes"/>
+ <context sub-pattern="0" where="end" style-ref="tag"/>
+ </include>
+ </context>
+ <context id="tag_attributes" style-ref="string">
+ <match>[^>]+</match>
+ </context>
+ <context id="non-standard-key" style-ref="non-standard-key">
+ <match>^_?X\-[a-zA-Z\-]+</match>
+ </context>
+ <context id="language" style-ref="decimal">
+ <match>\[[a-zA-Z_]+\]</match>
+ </context>
+ <context id="variable" style-ref="variable">
+ <match>^\s*[a-zA-Z_][a-zA-Z0-9_.]*</match>
+ </context>
+ <context id="boolean-value" style-ref="boolean-value">
+ <keyword>on</keyword>
+ <keyword>off</keyword>
+
+ </context>
+ <context id="single-quoted-string" style-ref="string">
+ <start>'</start>
+ <end>'</end>
+ </context>
+ <context id="double-quoted-string" style-ref="string">
+ <start>"</start>
+ <end>"</end>
+ </context>
+ <context id="integer" style-ref="decimal">
+ <match>\b[0-9]+\b</match>
+ </context>
+ <context id="decimal-number" style-ref="floating-point">
+ <match>(\b[0-9]+(\.[0-9]+)?|\.[0-9]+)([Ee][\+-]?[0-9]+)?\b</match>
+ </context>
+ <context id="apache">
+ <include>
+ <context ref="line-comment"/>
+ <context ref="group"/>
+ <context ref="non-standard-key"/>
+ <context ref="language"/>
+ <context ref="variable"/>
+ <context ref="boolean-value"/>
+ <context ref="single-quoted-string"/>
+ <context ref="double-quoted-string"/>
+ <context ref="decimal-number"/>
+ <context ref="integer"/>
+ <context ref="tag"/>
+ </include>
+ </context>
+ </definitions>
+</language>
=== added file 'Glade/browser.png'
Binary files Glade/browser.png 1970-01-01 00:00:00 +0000 and Glade/browser.png 2010-05-16 16:14:24 +0000 differ
=== added file 'Glade/confirmation.glade'
--- Glade/confirmation.glade 1970-01-01 00:00:00 +0000
+++ Glade/confirmation.glade 2010-05-16 16:14:24 +0000
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Sat Jul 26 17:53:35 2008 -->
+<glade-interface>
+ <widget class="GtkDialog" id="confirmation_window">
+ <property name="border_width">5</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="has_separator">False</property>
+ <signal name="destroy" handler="on_destroy"/>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="question_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Do you want to proceed ?</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ </widget>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="cancel_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_cancel_button_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="ok_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_ok_button_clicked"/>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
=== added file 'Glade/edit_domain_name.glade'
--- Glade/edit_domain_name.glade 1970-01-01 00:00:00 +0000
+++ Glade/edit_domain_name.glade 2010-05-16 16:14:24 +0000
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Thu Jul 3 04:38:32 2008 -->
+<glade-interface>
+ <widget class="GtkDialog" id="dialog_edit_domain_name">
+ <property name="border_width">5</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="default_width">400</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="urgency_hint">True</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkHBox" id="hbox8">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image_icon">
+ <property name="visible">True</property>
+ <property name="stock">gtk-edit</property>
+ <property name="icon_size">5</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="label_heading">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Enter your domain name</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entry_domain">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">8</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="button_cancel">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_button_cancel_clicked"/>
+ <accelerator key="Escape" modifiers="" signal="clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_ok">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_button_ok_clicked"/>
+ <accelerator key="Return" modifiers="" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
=== added file 'Glade/edit_module.glade'
--- Glade/edit_module.glade 1970-01-01 00:00:00 +0000
+++ Glade/edit_module.glade 2010-05-16 16:14:24 +0000
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Mon Jul 21 21:16:58 2008 -->
+<glade-interface>
+ <widget class="GtkDialog" id="dialog_edit_module">
+ <property name="width_request">600</property>
+ <property name="height_request">400</property>
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Module Configuration Editor</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkHBox" id="error_area">
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-error</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="message_text">
+ <property name="visible">True</property>
+ <property name="ypad">10</property>
+ <property name="label" translatable="yes">Error: Unknown error.</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkNotebook" id="notebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="text_view_module_conf_area">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image6">
+ <property name="visible">True</property>
+ <property name="stock">gtk-file</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Definition File</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">8</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="module_doc_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-help</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_module_doc_button_clicked"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_cancel">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_button_cancel_clicked"/>
+ <accelerator key="Escape" modifiers="" signal="activate"/>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_save">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="is_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-save</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_button_save_clicked"/>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
=== added file 'Glade/edit_vhost.glade'
--- Glade/edit_vhost.glade 1970-01-01 00:00:00 +0000
+++ Glade/edit_vhost.glade 2010-05-16 16:14:24 +0000
@@ -0,0 +1,944 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Tue Jul 22 13:54:02 2008 -->
+<glade-interface>
+ <widget class="GtkWindow" id="vhost_edit_window">
+ <property name="border_width">10</property>
+ <property name="title" translatable="yes">New Virtual Host</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <signal name="destroy" handler="quit"/>
+ <child>
+ <widget class="GtkNotebook" id="notebook_old">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkVPaned" id="vpaned1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">10</property>
+ <property name="row_spacing">10</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkCheckButton" id="set_custom_folder">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Let me choose custom _folder</property>
+ <property name="use_underline">True</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="custom_folder_toggled"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkFileChooserButton" id="custom_folder">
+ <property name="title" translatable="yes">Select A Folder</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="default_folder">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="truncate_multiline">True</property>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="create_hosts_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Add an entry to /etc/_hosts</property>
+ <property name="use_underline">True</property>
+ <property name="response_id">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="create_hosts_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">To access your Virtual Host
+you either need a registered
+domain name or an entry in
+<b>/etc/hosts</b>.</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Target folder:</property>
+ </widget>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="ok_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="is_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-save</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_ok"/>
+ <accelerator key="Return" modifiers="" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_EXPAND</property>
+ <property name="y_options">GTK_EXPAND</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="cancel_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_cancel"/>
+ <accelerator key="Escape" modifiers="" signal="activate"/>
+ </widget>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_EXPAND</property>
+ <property name="y_options">GTK_EXPAND</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Domain name:
+(no http:// or www)</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="has_www">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Create _www</property>
+ <property name="use_underline">True</property>
+ <property name="response_id">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="domain_name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="is_focus">True</property>
+ <signal name="delete_from_cursor" handler="domain_name_updated"/>
+ <signal name="changed" handler="domain_name_updated"/>
+ <signal name="delete_text" handler="domain_name_updated"/>
+ <signal name="insert_text" handler="domain_name_updated"/>
+ <signal name="activate" handler="domain_name_updated"/>
+ <signal name="paste_clipboard" handler="domain_name_updated"/>
+ <signal name="copy_clipboard" handler="domain_name_updated"/>
+ <signal name="cut_clipboard" handler="domain_name_updated"/>
+ <signal name="insert_at_cursor" handler="domain_name_updated"/>
+ <signal name="backspace" handler="domain_name_updated"/>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="stock">gtk-properties</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Details</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTextView" id="vhost_source">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="indent">1</property>
+ <property name="text" translatable="yes">Once created, the vhost definition will be visible here</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-file</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Virtual Host definition</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <widget class="GtkDialog" id="dialog_edit_vhost">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">VirtualHost Editor</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="has_separator">False</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkHBox" id="error_area">
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-error</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="message_text">
+ <property name="visible">True</property>
+ <property name="ypad">10</property>
+ <property name="label" translatable="yes">Error: Virtual Host creation aborted.</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkNotebook" id="notebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkTable" id="table2">
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">10</property>
+ <property name="row_spacing">10</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkEntry" id="entry_location">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="truncate_multiline">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_location">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_button_location_clicked"/>
+ <child>
+ <widget class="GtkHBox" id="hbox7">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image8">
+ <property name="visible">True</property>
+ <property name="stock">gtk-directory</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_location_clear">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_button_location_clear_clicked"/>
+ <child>
+ <widget class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="stock">gtk-clear</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ <property name="x_padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkViewport" id="viewport1">
+ <property name="visible">True</property>
+ <property name="resize_mode">GTK_RESIZE_QUEUE</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+ <child>
+ <widget class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkHBox" id="hbox6">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="label12">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Additional Domains</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolbar" id="toolbar2">
+ <property name="visible">True</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH_HORIZ</property>
+ <child>
+ <widget class="GtkToolButton" id="toolbutton_domain_add">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Add</property>
+ <property name="stock_id">gtk-add</property>
+ <signal name="clicked" handler="on_toolbutton_domain_add_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="toolbutton_domain_edit">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Edit</property>
+ <property name="stock_id">gtk-edit</property>
+ <signal name="clicked" handler="on_toolbutton_domain_edit_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="toolbutton_domain_delete">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Delete</property>
+ <property name="stock_id">gtk-delete</property>
+ <signal name="clicked" handler="on_toolbutton_domain_delete_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow4">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTreeView" id="treeview_domain">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">False</property>
+ <property name="headers_clickable">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_padding">8</property>
+ <property name="y_padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_hosts">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Add proper entries to /etc/_hosts</property>
+ <property name="use_underline">True</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="create_hosts_label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">If you have a domain that is not registered you will need an entry in your <b>/etc/hosts</b> file.</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ </widget>
+ <packing>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Location:</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ <property name="x_padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Domain name:</property>
+ </widget>
+ <packing>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ <property name="x_padding">8</property>
+ <property name="y_padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entry_domain">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="is_focus">True</property>
+ <signal name="changed" handler="on_entry_domain_changed"/>
+ <signal name="focus_out_event" handler="on_entry_domain_focus_out_event"/>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ <property name="x_padding">8</property>
+ <property name="y_padding">8</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="stock">gtk-properties</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Domain</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label17">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">basic security......</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox9">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image7">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-authentication</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Security</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkTable" id="table4">
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <child>
+ <widget class="GtkLabel" id="label14">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Log File Location</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ <property name="x_padding">8</property>
+ <property name="y_padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label13">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Server signature</property>
+ </widget>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="x_padding">8</property>
+ <property name="y_padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label11">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Server Admin Email</property>
+ </widget>
+ <packing>
+ <property name="y_options"></property>
+ <property name="x_padding">8</property>
+ <property name="y_padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entry_admin_email">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"></property>
+ <property name="x_padding">8</property>
+ <property name="y_padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkComboBox" id="combobox_log_level">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Emergencies - system is unusable
+Action must be taken immediately
+Critical Conditions
+Error conditions
+Warning conditions
+Normal but significant condition
+Informational
+Debug-level messages</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="x_padding">8</property>
+ <property name="y_padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label10">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Error Log Level</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="x_padding">8</property>
+ <property name="y_padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="checkbutton_server_signature">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Include server signature</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="x_padding">7</property>
+ <property name="y_padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox11">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkEntry" id="entry_log_location">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_log_location">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="response_id">0</property>
+ <child>
+ <widget class="GtkImage" id="image10">
+ <property name="visible">True</property>
+ <property name="stock">gtk-directory</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">8</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">GTK_FILL</property>
+ <property name="x_padding">8</property>
+ <property name="y_padding">8</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox10">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image9">
+ <property name="visible">True</property>
+ <property name="stock">gtk-edit</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Advanced</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">File: /var/www/config/whatever.host</property>
+ <property name="selectable">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">8</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox8">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="text_view_vhost_source_area">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_ETCHED_IN</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">8</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">8</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image6">
+ <property name="visible">True</property>
+ <property name="stock">gtk-file</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Definition File</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">3</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">8</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="button_cancel">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_button_cancel_clicked"/>
+ <accelerator key="Escape" modifiers="" signal="activate"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="button_save">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="is_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-save</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_button_save_clicked"/>
+ <accelerator key="Return" modifiers="" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
=== added file 'Glade/icon_cadsoft_eagle.svg'
--- Glade/icon_cadsoft_eagle.svg 1970-01-01 00:00:00 +0000
+++ Glade/icon_cadsoft_eagle.svg 2010-05-16 16:14:24 +0000
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg2244"
+ sodipodi:version="0.32"
+ inkscape:version="0.45.1"
+ width="256"
+ height="256"
+ version="1.0"
+ sodipodi:docbase="C:\Users\svo\Pictures"
+ sodipodi:docname="eaglev1.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="C:\Users\svo\Pictures\cadsoft_eagle.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <metadata
+ id="metadata2249">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs2247">
+ <linearGradient
+ id="linearGradient3351">
+ <stop
+ style="stop-color:#ff1616;stop-opacity:1;"
+ offset="0"
+ id="stop3353" />
+ <stop
+ id="stop3359"
+ offset="0.84745765"
+ style="stop-color:#fe1b1b;stop-opacity:0.77222222;" />
+ <stop
+ style="stop-color:#fc0000;stop-opacity:0.69999999;"
+ offset="1"
+ id="stop3355" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3351"
+ id="linearGradient3361"
+ x1="41.519562"
+ y1="126.612"
+ x2="217.06261"
+ y2="126.612"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ inkscape:window-height="691"
+ inkscape:window-width="1069"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ width="256px"
+ height="256px"
+ inkscape:zoom="1.1489362"
+ inkscape:cx="141.86443"
+ inkscape:cy="154.04182"
+ inkscape:window-x="94"
+ inkscape:window-y="20"
+ inkscape:current-layer="g2259" />
+ <g
+ id="g2259"
+ transform="translate(-3.0111111e-6,-1.8518517e-7)">
+ <g
+ id="g2357"
+ transform="translate(-610.12961,-12.277778)">
+ <path
+ style="opacity:1;fill:#010101"
+ d="M 759.54278,17.326388 C 748.11048,31.811337 743.26528,50.49121 733.82409,66.263887 C 730.67889,69.571656 727.95919,74.546797 725.88659,77.076387 C 724.36049,80.993521 720.29659,78.366198 715.60119,84.780336 C 712.06259,88.397654 708.86829,92.225456 706.07409,96.451386 C 706.75959,93.106686 706.67099,86.373303 701.57409,88.326387 C 696.05749,94.213176 693.82319,103.27019 689.66779,109.88889 C 690.04409,105.54812 692.95819,100.59003 690.26159,96.513886 C 684.02257,95.681976 683.50591,104.08909 680.66782,107.76389 C 675.94709,119.5509 668.33083,130.90077 667.91782,143.88889 C 667.81707,153.59339 676.17733,159.71374 683.26157,164.73264 C 685.72067,166.6766 685.23092,170.46469 681.51157,170.17014 C 668.52044,173.68863 659.01136,184.71317 652.91782,196.10764 C 650.99657,201.59319 651.56967,207.86036 649.35532,213.01389 C 650.23499,217.87253 657.47944,224.02339 661.41782,218.76389 C 662.18127,215.98023 661.13448,212.67366 664.48032,210.92014 C 669.63355,206.98131 677.66196,202.75363 684.13657,205.98264 C 687.62659,208.92365 691.55499,212.16613 694.60529,215.38889 C 694.72249,221.75271 695.53519,229.2592 693.57409,234.98264 C 687.00259,238.14468 678.87551,237.33995 673.91782,243.51389 C 671.51138,245.29557 673.56967,248.68938 670.01157,249.04514 C 665.66927,250.31745 666.72321,256.56446 671.29282,256.26389 C 673.85889,255.90755 674.84956,256.47146 675.23032,259.04514 C 676.49263,262.95857 680.57145,260.63059 681.29282,257.82639 C 684.27954,255.73528 688.2276,251.6877 691.69909,255.32639 C 695.09669,255.27642 694.97359,261.5318 698.51159,258.79514 C 701.14199,257.86809 699.91439,253.35785 700.48029,252.23264 C 703.23709,255.91833 708.02789,252.05157 706.13659,248.32639 C 707.59619,245.45134 711.58439,249.71807 714.04279,249.54514 C 718.27269,251.1571 719.07689,246.25678 721.98029,244.60764 C 724.93839,242.48899 726.03819,239.20098 727.13659,236.04514 C 731.48589,236.58521 737.19799,237.35988 739.63659,232.95139 C 743.02778,233.52963 745.81768,229.50029 743.16778,227.04514 C 745.84338,226.34096 746.38778,223.53443 747.35528,221.73264 C 751.78368,219.82541 757.99818,225.56373 761.29278,220.57639 C 763.09178,218.28761 764.46808,217.74857 767.57408,218.45139 C 771.73618,219.67501 774.62528,214.72053 771.54278,211.70139 C 770.88698,209.7168 764.51958,207.29714 769.10528,207.01389 C 774.36078,205.6766 779.69458,211.56993 784.26158,208.76389 C 785.50088,205.92029 784.01388,203.91799 788.88658,204.76389 C 799.24248,204.06933 810.05538,204.43855 819.98028,201.82639 C 823.81168,202.21722 831.47348,200.42144 828.54278,195.10764 C 825.45278,193.736 830.93548,191.38095 829.38658,188.67014 C 828.66168,185.04186 824.26808,185.27737 821.60528,185.23264 C 824.90398,182.22649 821.22798,177.75011 817.63658,178.67014 C 817.07648,175.8906 819.46268,173.04288 817.73028,170.42014 C 814.33138,167.77249 810.60058,170.01623 806.79278,169.23264 C 793.19058,173.56224 779.72028,178.45769 765.28068,179.66471 C 760.89998,181.38932 763.43728,175.77006 766.60528,176.73264 C 771.39538,174.87038 779.24718,178.07672 781.85528,172.48264 C 782.47028,170.23734 779.74748,167.65209 783.26158,166.82639 C 786.18848,166.00396 787.97528,163.45248 788.91778,160.88889 C 791.36308,159.94146 793.44118,157.20766 792.73028,154.82639 C 796.06648,155.43925 796.44948,150.86982 796.10528,149.85764 C 800.16798,150.45133 801.13908,145.36863 798.66778,143.29514 C 802.10538,141.37856 801.32558,135.82731 797.44908,135.29514 C 801.04088,131.58211 796.17078,127.19127 795.76158,123.85764 C 798.08098,121.63745 803.12878,121.88556 803.10528,117.63889 C 807.63048,113.76118 802.21208,109.00533 798.69908,107.17014 C 796.93588,105.63055 791.55638,103.74356 796.82408,104.13889 C 801.78478,104.74324 805.44028,98.338026 802.13658,95.451386 C 807.43558,93.715826 814.88738,94.194406 818.19908,89.045137 C 818.21068,83.11118 810.27278,83.666657 806.14028,82.834249 C 800.60178,82.119611 793.44928,82.476225 788.85528,82.295137 C 797.99558,77.20914 806.61968,71.007879 814.35528,64.232637 C 818.13088,61.040164 818.62268,55.924034 820.04278,51.482637 C 807.19198,55.739162 795.38368,62.193713 782.98028,67.482637 C 792.67148,59.153621 799.67928,48.503353 808.57408,39.420137 C 812.26418,37.31039 812.35178,30.386018 807.01158,31.451387 C 801.10998,32.852912 796.88008,37.724345 791.04278,39.076387 C 787.29158,41.040179 782.94098,44.598175 780.19908,46.420137 C 786.48348,37.760557 795.96408,31.468921 801.63658,22.388887 C 801.18298,16.643849 794.51338,18.983045 791.76158,21.576387 C 780.01878,30.352629 768.69638,39.758322 757.60528,49.201387 C 757.22318,41.369421 762.68078,35.196654 763.51158,27.545137 C 764.29338,23.945952 766.32568,16.266474 760.32408,16.763888 L 759.54278,17.326388 z "
+ id="path2372" />
+ </g>
+ <path
+ style="fill:url(#linearGradient3361);fill-opacity:1.0;stroke:#cca321;stroke-opacity:0.63636363;stroke-width:1.1;stroke-miterlimit:4;stroke-dasharray:none;opacity:1"
+ d="M 67.337805,244.81481 C 67.025655,243.98981 67.175275,242.52731 67.670305,241.56481 C 68.569635,239.81623 67.503625,239.14451 66.083325,240.56481 C 65.027085,241.62106 59.437175,241.50328 59.794165,240.43231 C 59.955955,239.94693 62.093455,238.80912 64.544165,237.90383 C 68.937785,236.28084 69.893025,234.08513 65.999995,234.55747 C 64.441275,234.74658 64.772225,234.14576 67.499995,231.83437 C 69.424995,230.2032 71.815445,228.85651 72.812095,228.84171 C 75.193985,228.80635 84.654445,225.77773 86.249995,224.53977 C 87.628275,223.47039 88.104355,200.84491 86.749995,200.77746 C 86.337495,200.75692 83.350215,198.28192 80.111595,195.27746 C 74.865465,190.41064 73.751545,189.81481 69.899105,189.81481 C 59.921445,189.81481 47.750275,197.75104 48.811815,203.56481 C 49.104685,205.16875 48.739975,205.81481 47.541655,205.81481 C 45.346795,205.81481 40.923995,200.78883 42.345665,199.91019 C 42.924865,199.55223 43.698785,196.12183 44.065485,192.28708 C 44.813345,184.46654 45.446735,183.20735 53.635155,173.26257 C 59.393205,166.26944 64.523485,162.96712 73.990285,160.16013 C 79.477025,158.53326 78.550935,152.1346 72.253365,148.15912 C 61.133295,141.13933 58.262955,133.42062 62.422015,121.72136 C 66.329445,110.72989 78.298235,85.018682 78.438545,87.314812 C 78.578625,89.607102 75.441205,103.77525 73.487665,109.67228 C 72.329335,113.16889 71.569115,116.21726 71.798295,116.44645 C 72.723845,117.37199 75.418285,112.68312 84.166395,94.923562 C 92.906115,77.181014 93.331675,76.524281 93.308915,80.814812 C 93.280455,86.177642 91.486555,92.960672 88.600665,98.617479 C 87.445295,100.88219 86.499995,102.99372 86.499995,103.30977 C 86.499995,104.89283 92.424905,96.493712 95.499995,90.551422 C 97.424995,86.831552 101.3872,81.206562 104.3049,78.051424 L 109.60981,72.314816 L 105.89062,79.314816 C 103.84507,83.164812 101.73124,86.888192 101.19321,87.588982 C 100.65519,88.289772 100.46205,89.110202 100.76401,89.412162 C 101.37591,90.024062 108.91476,80.046052 118.31173,66.186954 C 121.71568,61.166629 125.12832,56.538245 125.89537,55.901655 C 126.66241,55.265065 130.29593,48.122603 133.96985,40.029517 C 141.54994,23.331741 145.78124,14.962793 149.16297,9.9795277 C 151.32177,6.7983516 151.49728,6.7179516 151.46438,8.9252687 C 151.39644,13.482619 148.13431,25.093143 146.22994,27.55564 C 145.70216,28.238094 145.09343,31.061342 144.87721,33.829525 C 144.66099,36.597708 144.37516,39.358087 144.24204,39.963701 C 143.6445,42.682118 146.82988,41.594637 151.2159,37.582844 C 153.84716,35.176095 158.025,31.661673 160.5,29.773017 C 162.975,27.884362 168.825,23.13746 173.5,19.224346 C 182.22627,11.9202 188.5,7.9734757 188.5,9.7880367 C 188.5,10.351557 183.775,15.549085 178,21.3381 C 172.225,27.127115 167.5,32.302609 167.5,32.839199 C 167.5,33.375788 166.77686,33.814816 165.89301,33.814816 C 164.83155,33.814816 164.49421,34.357347 164.8993,35.412988 C 165.26645,36.369778 164.46105,38.260826 162.89242,40.125033 C 158.12955,45.785391 162.28257,44.106811 172.12985,36.39143 C 177.44844,32.224292 182.67144,28.814816 183.73653,28.814816 C 184.80161,28.814816 187.54661,27.504964 189.83652,25.904034 C 194.25574,22.814456 198.50824,21.139901 198.48753,22.497428 C 198.48067,22.946992 195.10567,26.887099 190.98753,31.253222 C 186.86939,35.619346 183.5,39.564104 183.5,40.019351 C 183.5,41.082856 168.79341,55.814816 167.73174,55.814816 C 167.29145,55.814816 166.13375,57.164816 165.15907,58.814816 C 164.18439,60.464816 163.62566,61.814816 163.91743,61.814816 C 165.15382,61.814816 179.64584,55.655591 187.43034,51.821648 C 192.06702,49.538033 198.0484,46.838349 200.72229,45.822351 L 205.58391,43.97508 L 204.94971,46.144948 C 204.24694,48.549405 200.09405,52.509729 194,56.586919 C 191.8,58.058818 188.2,60.672272 186,62.394595 C 183.8,64.116917 179.37277,66.709349 176.1617,68.155554 C 167.28433,72.153761 168.90086,73.374602 182.60097,73.018648 C 194.06638,72.720756 205.81768,74.361788 205.21283,76.176325 C 204.80828,77.389986 196.85799,79.663461 188.25,81.027042 C 184.5375,81.615132 181.5,82.455392 181.5,82.894282 C 181.5,83.333172 183.525,83.995932 186,84.367082 C 188.78027,84.784012 190.5,85.558302 190.5,86.393172 C 190.5,88.777222 187.16275,89.637702 180.11175,89.071722 C 174.50425,88.621602 173.31776,88.777672 173.68351,89.917262 C 173.9302,90.685912 176.12733,91.990102 178.56602,92.815452 C 182.66045,94.201172 190.01097,98.943389 191.73134,101.30912 C 192.13358,101.86225 191.75102,102.84737 190.8812,103.49828 C 190.01139,104.14918 189.56668,105.11368 189.89295,105.6416 C 190.21923,106.16953 189.30993,106.89668 187.87229,107.25751 C 184.85021,108.016 182.49836,110.09069 182.50374,111.99338 C 182.50579,112.72017 183.37363,114.73529 184.43226,116.47144 C 186.10715,119.21824 186.1757,119.86739 184.96032,121.47144 C 182.98394,124.07985 183.17594,125.81481 185.44098,125.81481 C 188.36747,125.81481 188.80694,127.48641 186.33555,129.21744 C 184.19537,130.71648 184.18587,130.81021 185.97381,132.78587 C 187.77856,134.7801 187.76027,134.81507 184.90499,134.83012 C 182.05466,134.84515 178.60125,136.31158 179.52896,137.11296 C 179.78803,137.33675 180.9,138.02253 182,138.63692 C 183.58808,139.52392 183.66479,139.76026 182.37244,139.7844 C 180.09943,139.82687 178.27811,142.19292 179.544,143.45881 C 180.20588,144.12069 179.69429,144.90805 178.02021,145.804 C 176.63409,146.54582 175.5,147.92213 175.5,148.86247 C 175.5,149.82411 174.17066,151.1228 172.46178,151.83064 C 168.92821,153.29429 167.2634,155.81394 168.50379,157.82095 C 169.85582,160.00857 168.72495,160.80976 164.19098,160.87647 C 157.81545,160.97027 147.19214,163.23839 146.73731,164.60289 C 146.5023,165.3079 147.3093,165.85076 148.66667,165.90076 C 150.86682,165.98181 150.84712,166.03286 148.32156,166.79514 C 146.84841,167.23978 144.65474,168.52438 143.44672,169.64982 L 141.25033,171.69607 L 147.12516,171.17407 C 161.37585,169.90784 174.32679,167.5255 182.34452,164.69543 C 191.17489,161.57851 196.62962,159.81481 197.43918,159.81481 C 197.68799,159.81481 195.77846,161.1549 193.19578,162.79279 C 186.4154,167.09278 187.42738,167.36861 195.08305,163.30719 C 201.04237,160.14571 205.5,158.89334 205.5,160.38055 C 205.5,160.69171 205.03417,161.81671 204.46482,162.88055 C 203.70658,164.29733 203.75321,164.81481 204.63913,164.81481 C 205.30435,164.81481 204.75769,165.99976 203.42431,167.44804 L 201,170.08127 L 205.66793,169.58013 C 209.21847,169.19895 210.21731,169.38792 209.84061,170.36958 C 209.56822,171.07941 208.70516,171.90584 207.92268,172.20611 C 204.21195,173.63005 208.39859,176.33434 213.75,175.97018 C 216.67174,175.77135 217.41408,177.50073 215.31012,179.60469 C 213.50244,181.41237 213.50733,183.60365 215.32061,184.29946 C 217.97679,185.31874 214.71722,186.7816 209.75,186.7995 C 207.4125,186.80792 205.5,187.20244 205.5,187.67621 C 205.5,188.14998 197.7375,188.86486 188.25,189.26483 C 178.7625,189.66481 170.79203,190.19764 170.53785,190.44891 C 170.28368,190.70018 170.62499,191.7853 171.29633,192.86029 C 172.76009,195.20415 172.83091,195.19567 167.5,193.31481 C 162.04807,191.39126 158.17262,191.41563 154.33998,193.39756 L 151.27928,194.98031 L 154.86467,197.41664 C 156.83663,198.75663 158.90764,200.70797 159.4669,201.75297 C 160.40125,203.4988 160.13957,203.62774 156.24187,203.34206 C 153.90884,203.17106 150.65,202.72195 149,202.34403 L 146,201.65689 L 148.5,203.71362 C 150.6108,205.45015 150.71837,205.7738 149.19098,205.79257 C 148.12627,205.80566 147.66344,206.27025 148.06609,206.92174 C 148.53176,207.67522 147.83216,207.85241 145.87511,207.47665 C 144.2938,207.17304 141.62267,206.65787 139.93927,206.33184 C 136.86268,205.73597 133.40517,207.98689 133.82126,210.31481 C 133.91957,210.86481 132.9875,211.75902 131.75,212.30194 C 129.24351,213.4016 128.89956,214.81437 130.7,216.61481 C 131.63333,217.54814 131.41893,217.81481 129.73518,217.81481 C 128.54453,217.81481 127.10332,218.6875 126.53248,219.75412 C 125.62991,221.44059 124.71306,221.62636 119.49989,221.17908 C 114.49502,220.74966 113.59856,220.9081 114.07075,222.13862 C 114.38182,222.94926 114.14832,223.91412 113.55185,224.28276 C 112.95539,224.65139 112.75711,225.42182 113.11124,225.99481 C 113.73262,227.00023 107.83775,232.80769 106.19097,232.81246 C 105.74601,232.81375 105.66007,233.26481 105.99999,233.81481 C 106.88685,235.24977 105.13239,235.05165 100.48467,233.192 C 96.719665,231.68555 96.295815,231.68962 94.572915,233.24882 C 93.396675,234.31331 92.910165,235.73166 93.244515,237.12163 C 93.676625,238.91798 93.530345,239.08864 92.436035,238.06481 C 91.701215,237.37731 90.452105,236.81481 89.660235,236.81481 C 88.868375,236.81481 87.673445,236.06669 87.004845,235.15233 C 86.240365,234.10683 85.135265,233.74079 84.027145,234.16602 C 82.459115,234.76773 82.553305,235.06891 84.882535,236.90108 C 86.794315,238.40488 87.468725,239.81662 87.383995,242.13739 C 87.320195,243.88497 87.071095,244.57349 86.830435,243.66744 C 86.589775,242.76138 85.629475,241.74169 84.696435,241.40145 C 83.763395,241.06122 81.920435,240.15261 80.600975,239.38232 C 78.434405,238.11749 77.735325,238.24016 73.386015,240.6483 C 70.737245,242.11488 68.420515,243.98981 68.237715,244.81481 C 67.942295,246.14814 67.842305,246.14814 67.337805,244.81481 z M 50.499995,188.81481 C 50.499995,186.52236 47.989225,186.09752 47.163165,188.2502 C 46.667815,189.54104 47.685065,190.5185 49.749995,190.73586 C 50.162495,190.77928 50.499995,189.91481 50.499995,188.81481 z "
+ id="path2261"
+ sodipodi:nodetypes="cssssssssssssssssssssssssssscccssssssssssssssssssssssssssssscccssssssssssssssssssssssssssssssssssscccssssssscccssssssssssscccsscccsssssssssssssssssssssssssssssccssc" />
+ <g
+ id="g2300"
+ transform="translate(155.79629,-17.407407)" />
+ </g>
+</svg>
=== added file 'Glade/main.glade'
--- Glade/main.glade 1970-01-01 00:00:00 +0000
+++ Glade/main.glade 2010-05-16 16:14:24 +0000
@@ -0,0 +1,644 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Wed Jul 23 00:55:33 2008 -->
+<glade-interface>
+ <requires lib="bonobo"/>
+ <requires lib="gnome"/>
+ <widget class="GnomeApp" id="MainWindow">
+ <property name="width_request">500</property>
+ <property name="height_request">400</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Rapache</property>
+ <property name="window_position">GTK_WIN_POS_MOUSE</property>
+ <property name="icon">icon_cadsoft_eagle.svg</property>
+ <property name="gravity">GDK_GRAVITY_CENTER</property>
+ <signal name="destroy" handler="on_MainWindow_destroy"/>
+ <child internal-child="dock">
+ <widget class="BonoboDock" id="app1-dock1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="BonoboDockItem" id="dockitem1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuBar" id="menubar1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkMenuItem" id="menuitem1">
+ <property name="label" translatable="yes">_File</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="menu1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImageMenuItem" id="imagemenuitem1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">gtk-new</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="imagemenuitem2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">gtk-open</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="imagemenuitem3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">gtk-save</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="imagemenuitem4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">gtk-save-as</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="toolsmenu">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Tools</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="menu2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImageMenuItem" id="menuitem2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Reload Apache</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="please_restart"/>
+ <child internal-child="image">
+ <widget class="GtkImage" id="menu-item-image1">
+ <property name="stock">gtk-refresh</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separatormenuitem2">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="browse_sites_available">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Browse sites-available folder as root</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="browse_sites_available"/>
+ <child internal-child="image">
+ <widget class="GtkImage" id="menu-item-image2">
+ <property name="stock">gtk-directory</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="separatormenuitem3">
+ <property name="visible">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkImageMenuItem" id="menu_quit">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">gtk-quit</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="on_MainWindow_destroy"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="menuitem4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Help</property>
+ <property name="use_underline">True</property>
+ <child>
+ <widget class="GtkMenu" id="menu3">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImageMenuItem" id="imagemenuitem10">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">gtk-about</property>
+ <property name="use_underline">True</property>
+ <property name="use_stock">True</property>
+ <signal name="activate" handler="about_clicked"/>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="behavior">BONOBO_DOCK_ITEM_BEH_EXCLUSIVE | BONOBO_DOCK_ITEM_BEH_NEVER_VERTICAL | BONOBO_DOCK_ITEM_BEH_LOCKED</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkHBox" id="restart_apache_notice">
+ <child>
+ <widget class="GtkVBox" id="vbox5">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkButton" id="restart_apache">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-refresh</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="please_restart"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">7</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">7</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Applied changes will not take effect until
+web server is restarted</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">True</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_END</property>
+ <property name="width_chars">0</property>
+ </widget>
+ <packing>
+ <property name="padding">4</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <widget class="GtkButton" id="button_hide_warning">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">GTK_RELIEF_NONE</property>
+ <property name="focus_on_click">False</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_button_hide_warning_clicked"/>
+ <child>
+ <widget class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-close</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">8</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkNotebook" id="notebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkVBox" id="vbox4">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH_HORIZ</property>
+ <child>
+ <widget class="GtkToolButton" id="new">
+ <property name="visible">True</property>
+ <property name="is_important">True</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-new</property>
+ <signal name="clicked" handler="new_button_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="edit_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="is_important">True</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-edit</property>
+ <signal name="clicked" handler="edit_button_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="delete_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="is_important">True</property>
+ <property name="stock_id">gtk-delete</property>
+ <signal name="clicked" handler="on_delete"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkSeparatorToolItem" id="toolbutton1">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="browse_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="is_important">True</property>
+ <property name="label" translatable="yes">Browse</property>
+ <property name="stock_id">gtk-open</property>
+ <signal name="clicked" handler="browse_button_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolButton" id="surf_this_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="is_important">True</property>
+ <property name="label" translatable="yes">Open Site</property>
+ <property name="icon_name">applications-internet</property>
+ <signal name="clicked" handler="surf_this_button_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="vhosts_scroll_box">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkViewport" id="viewport1">
+ <property name="visible">True</property>
+ <property name="resize_mode">GTK_RESIZE_QUEUE</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkVBox" id="vhost_container">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="icon_name">applications-internet</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Virtual Hosts</property>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkToolbar" id="toolbar2">
+ <property name="visible">True</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH_HORIZ</property>
+ <child>
+ <widget class="GtkToolButton" id="edit_module_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="is_important">True</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-edit</property>
+ <signal name="clicked" handler="edit_module_button_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkToolbar" id="toolbar3">
+ <property name="visible">True</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH_HORIZ</property>
+ <property name="show_arrow">False</property>
+ <child>
+ <widget class="GtkToolButton" id="open_doc_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="is_important">True</property>
+ <property name="label" translatable="yes">Module Documentation</property>
+ <property name="stock_id">gtk-help</property>
+ <signal name="clicked" handler="open_doc_button_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="modules_scroll_box">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkViewport" id="viewport2">
+ <property name="visible">True</property>
+ <property name="resize_mode">GTK_RESIZE_QUEUE</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkVBox" id="modules_container">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="pixbuf">modules.png</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Modules List</property>
+ </widget>
+ <packing>
+ <property name="padding">5</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkViewport" id="viewport3">
+ <property name="visible">True</property>
+ <property name="resize_mode">GTK_RESIZE_QUEUE</property>
+ <child>
+ <widget class="GtkVBox" id="problems_area">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkHBox" id="unnormalized_notice">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="xpad">10</property>
+ <property name="stock">gtk-dialog-warning</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ <property name="ypad">5</property>
+ <property name="label" translatable="yes"><small>The following Virtual Hosts are only present inside /etc/apache/sites-enabled. You have to normalize them in order to be able to manage them.</small></property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="fix_vhosts">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-execute</property>
+ <property name="use_stock">True</property>
+ <property name="yalign">0</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="fix_vhosts_clicked"/>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="padding">5</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-warning</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Problems</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">2</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ <child internal-child="appbar">
+ <widget class="GnomeAppBar" id="app1-appbar1">
+ <property name="visible">True</property>
+ <property name="spacing">4</property>
+ <property name="has_progress">True</property>
+ <property name="has_status">True</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+</glade-interface>
=== added file 'Glade/modules.png'
Binary files Glade/modules.png 1970-01-01 00:00:00 +0000 and Glade/modules.png 2010-05-16 16:14:24 +0000 differ
=== added file 'Glade/modules.xml'
--- Glade/modules.xml 1970-01-01 00:00:00 +0000
+++ Glade/modules.xml 2010-05-16 16:14:24 +0000
@@ -0,0 +1,211 @@
+<modules>
+ <module name='mod_access'>Provides access control based on client hostname, IP address, or other characteristics of the client request.</module>
+ <module name='mod_actions'>This module provides for executing CGI scripts based on media type or request method.</module>
+ <module name='mod_alias'>Provides for mapping different parts of the host filesystem in the document tree and for URL redirection</module>
+ <module name='mod_asis'>Sends files that contain their own HTTP headers</module>
+ <module name='mod_auth'>User authentication using text files</module>
+ <module name='mod_auth_anon'>Allows "anonymous" user access to authenticated areas</module>
+ <module name='mod_auth_dbm'>Provides for user authentication using DBM files</module>
+ <module name='mod_auth_digest'>User authentication using MD5 Digest Authentication.</module>
+ <module name='mod_auth_ldap'>Allows an LDAP directory to be used to store the database for HTTP Basic authentication.</module>
+ <module name='mod_autoindex'>Generates directory indexes, automatically, similar to the Unix ls command or the Win32 dir shell command</module>
+ <module name='mod_cache'>Content cache keyed to URIs.</module>
+ <module name='mod_cern_meta'>CERN httpd metafile semantics</module>
+ <module name='mod_cgi'>Execution of CGI scripts</module>
+ <module name='mod_cgid'>Execution of CGI scripts using an external CGI daemon</module>
+ <module name='mod_charset_lite'>Specify character set translation or recoding</module>
+ <module name='mod_dav'>Distributed Authoring and Versioning (WebDAV) functionality</module>
+ <module name='mod_dav_fs'>filesystem provider for mod_dav</module>
+ <module name='mod_deflate'>Compress content before it is delivered to the client</module>
+ <module name='mod_dir'>Provides for "trailing slash" redirects and serving directory index files</module>
+ <module name='mod_disk_cache'>Content cache storage manager keyed to URIs</module>
+ <module name='mod_dumpio'>Dumps all I/O to error log as desired.</module>
+ <module name='mod_echo'>A simple echo server to illustrate protocol modules</module>
+ <module name='mod_env'>Modifies the environment which is passed to CGI scripts and SSI pages</module>
+ <module name='mod_example'>Illustrates the Apache module API</module>
+ <module name='mod_expires'>Generation of Expires and Cache-Control HTTP headers according to user-specified criteria</module>
+ <module name='mod_ext_filter'>Pass the response body through an external program before delivery to the client</module>
+ <module name='mod_file_cache'>Caches a static list of files in memory</module>
+ <module name='mod_headers'>Customization of HTTP request and response headers</module>
+ <module name='mod_imap'>Server-side imagemap processing</module>
+ <module name='mod_include'>Server-parsed html documents (Server Side Includes)</module>
+ <module name='mod_info'>Provides a comprehensive overview of the server configuration</module>
+ <module name='mod_isapi'>ISAPI Extensions within Apache for Windows</module>
+ <module name='mod_ldap'>LDAP connection pooling and result caching services for use by other LDAP modules</module>
+ <module name='mod_log_config'>Logging of the requests made to the server</module>
+ <module name='mod_log_forensic'>Forensic Logging of the requests made to the server</module>
+ <module name='mod_logio'>Logging of input and output bytes per request</module>
+ <module name='mod_mem_cache'>Content cache keyed to URIs</module>
+ <module name='mod_mime'>Associates the requested filename's extensions with the file's behavior (handlers and filters) and content (mime-type, language, character set and encoding)</module>
+ <module name='mod_mime_magic'>Determines the MIME type of a file by looking at a few bytes of its contents</module>
+ <module name='mod_negotiation'>Provides for content negotiation</module>
+ <module name='mod_nw_ssl'>Enable SSL encryption for NetWare</module>
+ <module name='mod_proxy'>HTTP/1.1 proxy/gateway server</module>
+ <module name='mod_proxy_connect'>mod_proxy extension for CONNECT request handling</module>
+ <module name='mod_proxy_ftp'>FTP support module for mod_proxy</module>
+ <module name='mod_proxy_http'>HTTP support module for mod_proxy</module>
+ <module name='mod_rewrite'>Provides a rule-based rewriting engine to rewrite requested URLs on the fly</module>
+ <module name='mod_setenvif'>Allows the setting of environment variables based on characteristics of the request</module>
+ <module name='mod_so'>Loading of executable code and modules into the server at start-up or restart time</module>
+ <module name='mod_speling'>Attempts to correct mistaken URLs that users might have entered by ignoring capitalization and by allowing up to one misspelling</module>
+ <module name='mod_ssl'>Strong cryptography using the Secure Sockets Layer (SSL) and Transport Layer Security (TLS) protocols</module>
+ <module name='mod_status'>Provides information on server activity and performance</module>
+ <module name='mod_suexec'>Allows CGI scripts to run as a specified user and Group</module>
+ <module name='mod_unique_id'>Provides an environment variable with a unique identifier for each request</module>
+ <module name='mod_userdir'>User-specific directories</module>
+ <module name='mod_usertrack'>Clickstream logging of user activity on a site </module>
+ <module name='mod_version'>Version dependent configuration</module>
+ <module name='mod_vhost_alias'>Provides for dynamically configured mass virtual hosting </module>
+
+
+ <module name='anti-contraband'>anti-spam module</module>
+ <module name='Apache Proxy FastCGI'>proxy scheme module for FastCGI protocol...</module>
+ <module name='Auth MemCookie'>Apache Cookie Authentification Module</module>
+ <module name='Bandwidth Module'>Bandwidth and Connection control per Virtual Host or Directory</module>
+ <module name='CPPSERV'>application server/servlet container with apache module that provide Java Servlet-like API and C++ Servlet Pages implementation to C++ programmers</module>
+ <module name='DACS'>A light-weight, general-purpose authentication, authorization, and single sign-on system</module>
+ <module name='gbap-pool'>stl allocator for apache memory pools</module>
+ <module name='LDAP auth module'>HTTP basic authentication with LDAP</module>
+ <module name='mod-apache-snmp'>SNMP module for Apache</module>
+ <module name='mod-captcha'>mod-captcha is an Apache 2 module to prevent web sites from maliciosus software access. Developed in UNPSJB.</module>
+ <module name='mod-ipenv'>set/unset environment variables based on client IP addresses or client hostnames.</module>
+ <module name='mod-log-spread2'>rewrite from scratch to allow logging to use reliable messaging framework - spread</module>
+ <module name='mod-wiki'>mod-wiki is a wiki as a module</module>
+ <module name='modXLdapAuth'>X509 certificate authentication and LDAP authorization module</module>
+ <module name='mod_accessibility'>filter for server or proxy to improve accessibility of web contents on-the-fly</module>
+ <module name='mod_access_dnsbl '>Access control based on DNSBL blacklists and whitelists.</module>
+ <module name='mod_acronym'>Sample filter module for Acronyms</module>
+ <module name='mod_activex_filter'>Enable ActiveX filtering for Apache proxy</module>
+ <module name='mod_antispam'>by using this module, you can control referer spam accesses</module>
+ <module name='mod_athena'>load balancer plugin for mod_proxy</module>
+ <module name='mod_authnz_external'>Authentication provider using user provided scripts - secure authentication from Unix passwd file</module>
+ <module name='mod_authnz_ibmdb2'>mod_authnz_ibmdb2 is an Apache authentication module using IBM DB2 as database for storing user and group information.</module>
+ <module name='mod_authnz_sasl'>SASL socket based autnz module</module>
+ <module name='mod_authn_dbi'>For Apache 2.1+ that uses libdbi to provide access to database backends, including MySQL, PgSQL, Oracle, and others</module>
+ <module name='mod_authn_sasl'>Cyrus SASL authentication module</module>
+ <module name='mod_authz_unixgroup'>Check access control based on membership in Unix groups</module>
+ <module name='mod_auth_cookie_dbm'>Session authentication/expiration using (cryptographically strong) cookies. Cookie-to-username mapping with DBM database.</module>
+ <module name='mod_auth_form'> Form-based, authorization module using MySQL and session management.</module>
+ <module name='mod_auth_imap'>imap authentication module</module>
+ <module name='mod_auth_msfix'>When MS XP Clients connect to WebDAV they may have a problem sending the user's name to Apache. This mod can fix the user's name</module>
+ <module name='mod_auth_mysql'>MySQL-based authentication module with VirtualHost support (you need only one database for all VirtualHosts), now with SSL Support for the Connection to the MySQL-Server</module>
+ <module name='mod_auth_openpgp'>OpenPGP Signature Verification for signed HTTP requests (see Enigform, mod_access).</module>
+ <module name='mod_auth_oracle'>Authentication module for Apache 2.0 -> Oracle8/8i/9i</module>
+ <module name='mod_auth_pam'>Add PAM authentication</module>
+ <module name='mod_auth_pamacea'>Login form based auth module using PAM</module>
+ <module name='mod_auth_pamport'>Provides PAM authentication. Module uses pamport to provide a flexible interface to PAM services.</module>
+ <module name='mod_auth_phpbb'>auth by phpbb user and group</module>
+ <module name='mod_auth_sim'>Authentication Session ID Management using MySQL and cookies.</module>
+ <module name='mod_auth_timeout'>Idle timeout for basic auth/ldap auth.</module>
+ <module name='mod_auth_token'>Token-based authentication similar to mod_secdownload in LIGHTTPD. Have your script generate a token and let Apache handle the file transfer without having to pipe it through a script for security.</module>
+ <module name='mod_auth_useragent2'>Unsafe authentication for the Apache web server using the User-Agent</module>
+ <module name='mod_auth_user_dir'>User directory based authentication</module>
+ <module name='mod_auth_xradius'>RADIUS Authentication Module</module>
+ <module name='mod_bt'>BitTorrent tracker implementation with PHP and Perl language hooks</module>
+ <module name='mod_but V2.9 (Entry Server - SSO)'>MOD_BUT is a powerful entry server, including SSO, backend session hiding, shared memory session store, service authorization, authentication strengths and levels, login and logout features.</module>
+ <module name='mod_bwshare'>Bandwidth throttling and monitoring per client IP address.</module>
+ <module name='mod_caldav'>CalDAV RFC4791 module</module>
+ <module name='mod_cband'>A virtual host bandwidth-limiting module provided to solve the problem of limiting virtualhosts and users bandwidth usage</module>
+ <module name='mod_cbroker'>HTTP/CORBA gateway</module>
+ <module name='mod_cfg_ldap'>Module that provides Vhost lookups via LDAP</module>
+ <module name='mod_cguard'>simple and flexible connection limiter</module>
+ <module name='mod_clamav'>Virus Scanning module for Apache2</module>
+ <module name='mod_concat'>concatenate multiple files together in one URL request, similar to what perlbal does</module>
+ <module name='mod_countm'>Counter returning count via jpeg or png image.</module>
+ <module name='mod_cplusplus'>A C++ wrapper around apache-2.0</module>
+ <module name='mod_crowd'>CROWD is a web-based single sign-on (SSO) tool for provisioning and identity management developed by Atlassian. This module allows for Basic authentication calls from apache over to CROWD SSO.</module>
+ <module name='mod_csv'>Publishes CSV/spreadsheet data to the Web</module>
+ <module name='mod_dav_acl'>RFC3744 (Access Control Rights)</module>
+ <module name='mod_dav_svn'>Filesystem provider module distributed with Sub</module>
+ <module name='mod_daytime'>RFC-867-compliant Daytime service</module>
+ <module name='mod_dbd_mysql'>DBD Driver module for MySQL. To replace mod_mysql_pool</module>
+ <module name='mod_dbd_pgsql'>DBD Driver module for PostgreSQL. To replace mod_pg_pool</module>
+ <module name='mod_debug'>Gives an html-header with request-information</module>
+ <module name='mod_diagnostics.c'>Debug tool for filters; aid to tracing buckets</module>
+ <module name='mod_domaintree'>Mass virtual hosting module mapping host names to a directory tree</module>
+ <module name='mod_dsp'>DSP - Davor Server Pages: PL/SQL Server Scripting + ORACLE AUTHNZ</module>
+ <module name='mod_estraier'>mod_estraier is an apache module that registers web pages processed by the apache and search from them using the node API of Hyper Estraier.</module>
+ <module name='mod_example_ipc '>Sample code demonstrating shared memory and mutex usage in modules</module>
+ <module name='mod_expat'>Filter module to turn XML into SAX buckets. This module has been replaced by mod_xml2 and will be no longer maintained.</module>
+ <module name='mod_fcgid'>Apache2 module for FastCGI protocol</module>
+ <module name='mod_footer'>add footer to certain pages with certain vars</module>
+ <module name='mod_ftpd'>FTP Protocol module</module>
+ <module name='mod_globule'>A module for server-to-server document replication. Clients are automatically redirected to one of the replicas.</module>
+ <module name='mod_gridsite'>Grid authentication (GSI) and authorization (GACL, VOMS) in an Apache module</module>
+ <module name='mod_highlight'>Syntax Highlighting in an Apache 2.0 Output Filter</module>
+ <module name='mod_i18n'>Implements the i18n namespace to provide gettext translation as an output filter.</module>
+ <module name='mod_idcheck'>Cookie based web authentication and single sign on system designed for largish</module>
+ <module name='mod_ifier'>Apache2 request filtering and rejection</module>
+ <module name='mod_injection'>Inject text after the HTML body tag.</module>
+ <module name='mod_ip_count'>limit the number of requests to your server farm by incoming IP</module>
+ <module name='mod_itp'>Implements simputer transfer protocol : ITP</module>
+ <module name='mod_line_edit'>General-purpose fast text filter</module>
+ <module name='mod_log50x'>Log error 500 - 509 to logfiles</module>
+ <module name='mod_log_access'>customised, automatically rotated logs</module>
+ <module name='mod_log_firstbyte'>New in performance testing! Enables you to log the time between the request being read and the first byte served.</module>
+ <module name='mod_log_mysql'>Use one or more MySQL databases to log requests</module>
+ <module name='mod_lua'>Module support LUA Script or html embbed LUA</module>
+ <module name='mod_memcached_cache'>mod_cache provider module for memcached storage</module>
+ <module name='mod_mldap'></module>
+ <module name='mod_mono'>module ASP.NET for Apache</module>
+ <module name='mod_mono'>Runs ASP.NET pages on Unix with Apache and Mono</module>
+ <module name='mod_murka'>xml/xsl based web publishing environment</module>
+ <module name='mod_oai'>Open Archives Initiative Protocol for Metadata Harvesting (OAI-PMH) support</module>
+ <module name='mod_pgheader'>Replaces body tags with headers/footers</module>
+ <module name='mod_prolog'>Embedded prolog interpreter</module>
+ <module name='mod_proxy_html'>Fixup HTML Links for Reverse Proxy/Mirror</module>
+ <module name='mod_proxy_xml'>Fixup Links in XML doc types (eg WML) for Reverse Proxy/Mirror</module>
+ <module name='mod_publisher'>Universal markup processing filter</module>
+ <module name='mod_python'>Apache/Python Integration</module>
+ <module name='mod_qos'>Quality of service module implementing control mechanisms that can provide different priority to different requests.</module>
+ <module name='mod_replace_regex'>replace text with regex pattern</module>
+ <module name='mod_ruid'>based on mod_suid2 only for linux</module>
+ <module name='mod_sasl_auth'>Module to allow authentication with sasl</module>
+ <module name='mod_schema'>w3c/xml schema validator</module>
+ <module name='mod_scheme'>Apache 2 module for Scheme language</module>
+ <module name='mod_sesehe SEcure SErver HEader'>Modify or remove 'Server: ' HTTP response header. More on : Module homepage</module>
+ <module name='mod_setenvauthpw'>This module acquires a password from a request_rec structure body and incorporates it in an environment variable An environment. An environment variable name is REMOTE_PASSWORD.</module>
+ <module name='mod_spin'>Template engine, C API support via shared libraries, database connection pooling, persistent session/application data tracking</module>
+ <module name='mod_sqil'>A RDBMS => XML mapper</module>
+ <module name='mod_sql'>XML Namespace module to add SQL ops/queries</module>
+ <module name='mod_ssi_func'>extensions to mod_include for math functions, random number generation, one step value pair variable setting and flastmod vars</module>
+ <module name='mod_ssl_error'>X.509 certificate validation error trapping (SSL)</module>
+ <module name='mod_suexec_helper'>Adds UserId and GroupId directives to apache which are passed as arguments to suexec when starting CGI scripts.</module>
+ <module name='mod_suid2'>Suexec module for Apache2. it support chroot.</module>
+ <module name='mod_swf2html'>Provides `glue between Apache 2 and Macromedia Flash Seach Engine SDK</module>
+ <module name='mod_tee'>Clone a response as it is sent to the client</module>
+ <module name='mod_tidy '>mod_tidy is a TidyLib based DSO module for the Apache HTTP Server</module>
+ <module name='mod_traf_thief'>This simple module allows you to redirect percent of traffic to your url.</module>
+ <module name='mod_txt'>Display plain text files as prettified HTML with header+footer in the manner of directory indexes</module>
+ <module name='mod_upload'>Input filter for file uploads (multipart/form-data)</module>
+ <module name='mod_uploader'>High performance, low burdened apache-moduled uploader</module>
+ <module name='mod_usertild'>UserTild Module</module>
+ <module name='mod_valet_admin'>Site Valet Configuration and Admin Functions</module>
+ <module name='mod_valet_audit'>Module for browser-based accessibility audit/reporting.</module>
+ <module name='mod_valet_publish'>XML/XSLT publishing system for reports (POST, PUT, GET + XSLT)</module>
+ <module name='mod_valet_report'>Site Valet Query and Browse Functions</module>
+ <module name='mod_valet_sql'>Manage a dynamic pool of SQL connections</module>
+ <module name='mod_valet_utils'>Utility module: Form handling and templatised report generation</module>
+ <module name='mod_validator'>Markup Validation (HTML, XML, SGML) module</module>
+ <module name='mod_vd'>A virtual domain to directory mapper. Fast variant of mod_vhost_alias.</module>
+ <module name='mod_vhost ldap/pgsql/mysql module'>mod_vhost based on ldap/pgsql/mysql backend</module>
+ <module name='mod_vhost_ldap'>Virtual Hosting from ldap built on top of mod_ldap (caching included). Module is now considered feature completed.</module>
+ <module name='mod_vhost_mysql2'>Provides dynamically configured Virtual Hosting in Apache2.</module>
+ <module name='mod_vhost_mysql2'>Provides dynamically configured Virtual Hosting in Apache2. With in Alias fabian@xxxxxxxxxx</module>
+ <module name='mod_vhs'>Virtual Hosting Module that can get data from LDAP, MySQL, PAM, ... This module sets correctly the DOCUMENT_ROOT internal apache</module>
+ <module name='mod_websh'>Tcl extension for rapid web application development</module>
+ <module name='mod_wxjs'>Module for using JavaScript / wxWidgets as server-side language.</module>
+ <module name='mod_xcap'>XCAP (RFC4825)</module>
+ <module name='mod_xhtml'>Namespace module for XHTML (ensure W3C Appendix C) and SSI implementation</module>
+ <module name='mod_xi'>partial XInclude implementation</module>
+ <module name='mod_xml'>[obsolete] API/Framework for XML Applications with Apache 2.0</module>
+ <module name='mod_xml2'>This module provides a filter to turn XML/HTML into a stream of sax buckets.</module>
+ <module name='mod_xmlns'>Adds XML namespace support to publishing with Apache</module>
+ <module name='mod_xsendfile '>Serves alternative content by processing X-SENDFILE headers.</module>
+ <module name='mod_xslt'>A Filter to parse xml with an xsl</module>
+ <module name='mod_zrkadlo'>A database-backed mirror redirector</module>
+ <module name='mon_mono'>Running .Net framework in cross-platform</module>
+ <module name='vdbh_SQLite'>virtual host from SQLite3</module>
+ <module name='Vhost Limit Module'>Allow to specify the max clients, per virtual host</module>
+ <module name='xmlns_esi'>Parser for Edge Side Includes</module>
+</modules>
=== added file 'Glade/old_edit_vhost.glade'
--- Glade/old_edit_vhost.glade 1970-01-01 00:00:00 +0000
+++ Glade/old_edit_vhost.glade 2010-05-16 16:14:24 +0000
@@ -0,0 +1,317 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Mon Jun 23 01:58:11 2008 -->
+<glade-interface>
+ <widget class="GtkWindow" id="vhost_edit_window">
+ <property name="visible">True</property>
+ <property name="border_width">10</property>
+ <property name="title" translatable="yes">New Virtual Host</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <signal name="destroy" handler="quit"/>
+ <child>
+ <widget class="GtkNotebook" id="notebook">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkVPaned" id="vpaned1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkHBox" id="message_container">
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-error</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="message_text">
+ <property name="visible">True</property>
+ <property name="ypad">10</property>
+ <property name="label" translatable="yes">Error: Virtual Host creation aborted.</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">False</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">10</property>
+ <property name="row_spacing">10</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkCheckButton" id="set_custom_folder">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Let me choose custom _folder</property>
+ <property name="use_underline">True</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="custom_folder_toggled"/>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkFileChooserButton" id="custom_folder">
+ <property name="title" translatable="yes">Select A Folder</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="default_folder">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="truncate_multiline">True</property>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="create_hosts_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Add an entry to /etc/_hosts</property>
+ <property name="use_underline">True</property>
+ <property name="response_id">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="create_hosts_label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">If you do not have a registered
+domain you will need an entry in
+your <b>/etc/hosts</b> file.</property>
+ <property name="use_markup">True</property>
+ <property name="wrap">True</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Target folder:</property>
+ </widget>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="ok_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="is_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-save</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_ok"/>
+ <accelerator key="Return" modifiers="" signal="clicked"/>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_EXPAND</property>
+ <property name="y_options">GTK_EXPAND</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="cancel_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_cancel"/>
+ <accelerator key="Escape" modifiers="" signal="activate"/>
+ </widget>
+ <packing>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_EXPAND</property>
+ <property name="y_options">GTK_EXPAND</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Domain name:
+(no http:// or www)</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkCheckButton" id="has_www">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Create _www</property>
+ <property name="use_underline">True</property>
+ <property name="response_id">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="domain_name">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="is_focus">True</property>
+ <signal name="delete_from_cursor" handler="domain_name_updated"/>
+ <signal name="changed" handler="domain_name_updated"/>
+ <signal name="delete_text" handler="domain_name_updated"/>
+ <signal name="insert_text" handler="domain_name_updated"/>
+ <signal name="activate" handler="domain_name_updated"/>
+ <signal name="paste_clipboard" handler="domain_name_updated"/>
+ <signal name="copy_clipboard" handler="domain_name_updated"/>
+ <signal name="cut_clipboard" handler="domain_name_updated"/>
+ <signal name="insert_at_cursor" handler="domain_name_updated"/>
+ <signal name="backspace" handler="domain_name_updated"/>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="resize">True</property>
+ <property name="shrink">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="stock">gtk-properties</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Details</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkTextView" id="vhost_source">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="indent">1</property>
+ <property name="text" translatable="yes">Once created, the vhost definition will be visible here</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-file</property>
+ <property name="icon_size">1</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Virtual Host definition</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">1</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
=== added file 'Glade/warning_dialog.glade'
--- Glade/warning_dialog.glade 1970-01-01 00:00:00 +0000
+++ Glade/warning_dialog.glade 2010-05-16 16:14:24 +0000
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Sat Jun 28 18:51:41 2008 -->
+<glade-interface>
+ <widget class="GtkWindow" id="window1">
+ <property name="visible">True</property>
+ <property name="border_width">10</property>
+ <property name="title" translatable="yes">Rapache Warning</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <signal name="destroy" handler="quit"/>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">label</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkButton" id="okbutton1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="on_ok"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
+
=== added directory 'RapacheCore'
=== renamed directory 'RapacheCore' => 'RapacheCore.moved'
=== added file 'RapacheCore/ApacheConf.py'
--- RapacheCore/ApacheConf.py 1970-01-01 00:00:00 +0000
+++ RapacheCore/ApacheConf.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,344 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+ASSUMPTIONS
+ - when multiple directive with the same name are encountered
+ the last one wins.
+ - directives without options could be ok.
+ - ServerAlias without any option works
+
+GOALS:
+ - change as little as possible when updating to reduce the risk
+ of breaking something
+
+TODO:
+ - search for subsections and limit editing to a certain subsection
+ - insert directive where it doesn't exist
+ - remove a directive when it becomes empty (without options)
+ - verify apache handling of case for directives
+"""
+
+import re
+from RapacheCore.Observer import PollyObserver
+from RapacheCore.Observer import Observable
+
+class Parser (Observable):
+ filename = None
+ content = None
+ parser = None
+
+ def __init__ (self, *args, **kwargs):
+ super (Parser, self).__init__ (*args, **kwargs)
+ self.parser = LineParser()
+ self.apply_observing_policy()
+
+ def apply_observing_policy(self):
+ """register the object with the observer"""
+ self.observer = PollyObserver()
+ self.observer.register(self)
+
+ def load(self, filename ):
+ self.filename = filename
+ file = open ( filename, 'r' )
+ self.content = file.readlines()
+ file.close()
+ return self.content
+
+ def get_value(self, name):
+ line = self.get_directive(name)
+ if line == None: return None
+ return self.parser.get_value(line)
+ def set_value (self, name, value):
+ idx = self._get_last_directive_idx(name)
+ if idx == None:
+ idx = self._last_line_idx()
+ line = name+"\t"+self.parser.value_escape( value )+"\n"
+ self.insert_line( self._last_line_idx(), line )
+ else:
+ line = self.get_line( idx )
+ line = self.parser.change_value(line, value)
+ self.set_line( idx, line )
+ def remove_value(self, name):
+ idx = self._get_last_directive_idx(name)
+ print "removing line:",idx
+ if idx:
+ self.remove_line(idx)
+ return True
+ return False
+ def get_directive(self, name):
+ idx = self._get_last_directive_idx(name)
+ if ( idx == None ): return None
+ line = self.get_line( idx )
+ return line
+ """
+ def set_directive (self, name, line):
+ idx = self._get_last_directive_idx(name)
+ self.set_line( idx, line )
+ """
+ # idx starts from 0 !! it's not a line number
+ def _get_last_directive_idx (self, name ):
+ last_found = None
+ for key, line in enumerate(self.get_content() ):
+ if ( self.parser.get_directive(line) == name ): last_found = key
+ return last_found
+ #TODO create if doesn't exist.
+ def set_directive (self, name, line):
+ idx = self._get_last_directive_idx(name)
+ if ( idx == None ):
+ return self.insert_line( self._last_line_idx() , line.rstrip()+"\n")
+ self.set_line( idx, line.rstrip()+"\n" )
+
+ def _last_line_idx (self):
+ return 999999
+
+ def has_option (self, name, option ):
+ line = self.get_directive(name)
+ if ( line == False or line == None ): return False
+ return self.parser.has_option(line, option)
+ def get_options (self, name):
+ value = self.get_value(name)
+ if value == None: return []
+ options = self.parser.parse_options( value )
+ print options
+ return options
+ def add_option (self, name, option ):
+ line = self.get_directive(name)
+ if ( line == False or line == None ):
+ line = name
+ line = name+"\t"+self.parser.value_escape( option )+"\n"
+ self.insert_line( self._last_line_idx(), line )
+ return
+ line = self.parser.add_option(line, option)
+ self.set_directive(name, line)
+ def remove_option (self, name, option ):
+ #we need idx later if we decide to remove the whole line
+ idx = self._get_last_directive_idx(name)
+ line = self.get_directive(name)
+ if ( line == False or line == None ): return False
+ line = self.parser.remove_option(line, option)
+ new_value = self.parser.get_value( line )
+ if ( new_value.strip() == "" ):
+ self.remove_line( idx )
+ else:
+ self.set_directive(name, line)
+ def get_source (self):
+ return "".join( self.get_content() )
+ def get_content(self):
+ return self.content
+ def set_content_from_string(self, string):
+ self.content = string.split( "\n" )
+ def get_line(self, idx):
+ return self.get_content()[idx]
+ def set_line(self, idx, line):
+ self.content[ idx ] = line
+ def insert_line (self, idx, line):
+ """Inserts a line at the given idx"""
+ if idx >= len( self.content ): #out of range
+ idx = self._last_line_idx()
+ self.content.insert( idx, line )
+ self.raise_event( 'row_inserted', {'idx':idx, 'line':line } )
+ def remove_line(self, idx ):
+ del self.content[ idx ]
+ self.raise_event( 'row_removed', {'idx':idx } )
+class PieceParser ( Parser ):
+ """Manipulates isolated parts of configuration files. Should be extended"""
+
+ min = None
+ max = None
+ father = None
+ def apply_observing_policy(self):
+ """register the object with the observer"""
+ self.father.observer.register(self)
+ def load (self, args = {}):
+ print "Please override this method !"
+ exit()
+ def __init__(self, father, args = {} ):
+ self.father = father
+ Parser.__init__( self )
+ self.load( args )
+ def load (self, args = {} ):
+ pass
+ def get_content (self):
+ return self.father.get_content()[ self.min : self.max ]
+
+class VhostParser( PieceParser ):
+ """Searches for the first vhost inside the conf and allows isolated
+ manipulation of it"""
+
+ def load(self, args = {}):
+ content = self.father.get_content()
+ self.min = self._find_min(content)
+ if self.min == None: raise "VhostNotFound", "Beginning not found"
+ self.max = self._find_max(content, self.min) +1
+ if ( self.max == None ): raise "VhostNotFound", "End not found"
+
+ def _last_line_idx (self):
+ return -1
+ def _find_min( self, content ):
+ for idx, line in enumerate( content ):
+ basic_regexp = r'^\s*<s*(VirtualHost)(\s+[^>]*)*>.*'
+ result = re.match( basic_regexp, line, re.IGNORECASE )
+ if ( result != None and result != False ): return idx
+ return None
+ def _find_max( self, content, min ):
+ for idx, line in enumerate( content ):
+ if ( idx > min ):
+ basic_regexp = r'^\s*<s*(/VirtualHost)\s*>.*'
+ result = re.match( basic_regexp, line, re.IGNORECASE )
+ if ( result != None and result != False ): return idx
+ return None
+ def set_line (self, idx, line ):
+ if idx >= 0: idx = idx + self.min
+ return self.father.set_line( idx, line )
+ def insert_line (self, idx, line ):
+ print "===========> INSERTING"
+ if idx >= 0: idx = idx + self.min
+ line = "\t"+line.lstrip() #ident
+ return self.father.insert_line( idx, line )
+ def remove_line(self, idx ):
+ if idx >= 0: idx = idx + self.min
+ return self.father.remove_line( idx )
+ def handle_event(self, event):
+ print self, "handling:", event.name, "raised by", event.caller
+ if ( event.name == 'row_inserted' ):
+ self.max = self.max + 1
+ if ( event.name == 'row_removed' ):
+ self.max = self.max -1
+
+class LineParser:
+ """Utility class. Contains methods to parse and manipulate apache conf
+ directives"""
+ def tokenize (self, line ):
+ basic_regexp = '^(\s*)([A-Z0-9]+)(\s+)(.*)'
+ result = re.match( basic_regexp, line, re.IGNORECASE )
+ if ( result == None ): return False
+ return list( result.groups() )
+ def value_unescape(self, value):
+ #value should have no precedig or trailing spaces
+ if value == "" : return value
+ char = value[0]
+ if char == '"' or char == "'":
+ if char != value[-1]:
+ raise( 'BadQuoting', 'Bad quoting' )
+ return value;
+ value = value[1:-1]
+ value = value.replace( '\\'+char, char )
+
+ #we don't need to unescape spaces as apparently
+ #apache parser doesn't handle escaped spaces
+ #inside non-quote-enclosed strings
+ return value
+
+ #parse a value into a list of multiple options
+ # - handles double quote-enclosed strings "example"
+ #TODO: doesn't hanlde single quotes at all :(
+ def parse_options ( self, s ):
+ """parse a value into a list of multiple options"""
+ s = s.rstrip()
+ s = s.replace ( '\"', '"' )
+ result = '';
+ tokens = s.split( '"' )
+ for k, v in enumerate( tokens ):
+ # replace spaces in every odd token
+ if ( k & 1 ) == 1 : tokens[k] = v.replace( ' ', ' ' )
+
+ s = '"'.join( tokens )
+ s = s.replace( '"', '' )
+ tokens = s.split( ' ' )
+ for k, v in enumerate( tokens ):
+ tokens[ k ] = v.replace( ' ', ' ' )
+ tokens[ k ] = tokens[ k ].replace( '"', '"' )
+ tokens = [x for x in tokens if x.strip() != '' ]
+ return tokens;
+
+ def remove_option ( self, line, option ):
+ options = self.get_value( line );
+ options = self.parse_options( options);
+ for k,o in enumerate( options ):
+ if ( option == o ): del options[ k ]
+
+ return self.change_value( line, " ".join( options ) )
+ def has_option (self, line, option):
+ options = self.parse_options( line )
+ for o in options:
+ if o == option : return True
+ return False
+
+ def add_option ( self, line, option ):
+ options = self.get_value( line );
+ if options == False : options = ""
+ options = self.parse_options( options);
+ found = False;
+ for k,o in enumerate( options ):
+ if ( option == o ): found = True;
+ if ( found == False ): options.append( self.value_escape( option ) )
+ return self.change_raw_value( line, " ".join( options ))
+
+ def value_escape ( self, value ):
+ if ( value.find(' ') != -1 ):
+ value = '"'+value.replace( '"', '\\"' )+'"'
+ return value;
+
+ def get_value ( self, line ):
+ tokens = self.tokenize( line )
+ if ( tokens == False ): return False;
+ value = tokens.pop()
+ value = value.strip()
+ value = self.value_unescape( value )
+
+ return value
+
+ def get_directive ( self, line ):
+ tokens = self.tokenize( line );
+ if ( tokens == False ): return False
+ return tokens[ 1 ]
+
+ def change_value( self, line , new_value ):
+ new_value = self.value_escape( new_value )
+ return self.change_raw_value( line, new_value )
+
+ def change_raw_value ( self, line , new_value ):
+ tokens = self.tokenize( line )
+ tokens[2] = tokens[2].replace( "\n", '' ) #separator shuoldn't contain newlines
+ if tokens[2] == '': tokens[2] = ' ' #at least as space as separator
+ line = tokens[0]+tokens[1]+tokens[2]+new_value
+ line = line.rstrip() + "\n"
+ return line
+
+
+if __name__ == "__main__":
+
+ parser = Parser()
+ parser.load( '/etc/apache2/sites-available/figa' )
+ parser.set_value('DocumentRoot', '/var/www/xxxx/yyyy' )
+
+ piece = VhostParser( parser )
+
+ print piece.get_value('DocumentRoot' )
+ print piece.get_value('ServerName' )
+ piece.set_directive( 'fatwife' , 'fatwife 1')
+
+ #piece.remove_option( 'ServerAlias', 'www.figa' )
+ piece.add_option( 'ServerAlias', 'ftp.figa' )
+
+
+ print "====="
+ print piece.get_source()
+ print "====="
+
=== added file 'RapacheCore/Configuration.py'
--- RapacheCore/Configuration.py 1970-01-01 00:00:00 +0000
+++ RapacheCore/Configuration.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+SYSCONFDIR = '/etc/apache2'
+SITES_ENABLED_DIR = SYSCONFDIR + '/sites-enabled'
+SITES_AVAILABLE_DIR = SYSCONFDIR + '/sites-available'
+MODS_ENABLED_DIR = SYSCONFDIR + '/mods-enabled'
+MODS_AVAILABLE_DIR = SYSCONFDIR + '/mods-available'
+APPPATH = '/usr/bin' #please fill at run-time
+GLADEPATH = '/usr/local/share/rapache/Glade' #please fill at run-time
+
=== added file 'RapacheCore/HostsManager.py'
--- RapacheCore/HostsManager.py 1970-01-01 00:00:00 +0000
+++ RapacheCore/HostsManager.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,299 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import getopt, sys
+import os
+import re
+import subprocess
+"""
+Things to remember:
+ - if 2 equal domain names are found in /etc/hosts the first wins
+"""
+
+# Flow:
+# ------------
+# hosts-manager -a example.loc 10.0.0.1
+#
+# example.loc exists ?
+# No. Add it at the end of file
+# Yes
+# is ip the same ?
+# yes. Skipping.
+# no.
+# remove domain name from the line it first appears in
+# if the line contained only one domain, remove the line altogheter
+# add a new line just below $IP $DOMAIN_NAME
+
+
+#IPv4 REGEXP: \d{1,3}\.\d{1,3}\.\d{1,3}'
+#IPv4 (2): \b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b
+#SOSTITUZIONE: re.sub( r'(\s)(www.mu.loc)(\s|$)', r'\3\1xxx\3', subject )
+#CAMBIO IP:
+
+
+#TODO: regexp the crap out of IP's (v4 and v6)
+#TODO: strip in-line comments 127.0.0.1 domain.localhost #strip-this.com
+
+class HostsManager:
+ SUDO = "sudo"
+ HOSTS = "/etc/hosts"
+ REGEXP_IPV4 = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
+ opts = None
+ def __init__( self, console = False ):
+ if ( console ):
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "ho:v:ar", ["help", "output="])
+ self.opts = opts
+ self.args = args
+ except getopt.GetoptError, err:
+ # print help information and exit:
+ print str(err) # will print something like "option -a not recognized"
+ self.usage()
+ sys.exit(2)
+ output = None
+ verbose = False
+ if len(opts) == 0:
+ self.usage()
+ exit()
+ for o, a in opts:
+ if o == "-v":
+ verbose = True
+ elif o == "-a":
+ if ( len( args ) == 0 ):
+ self.usage()
+ sys.exit()
+ self.create( *args )
+ elif o == "-r":
+ if ( len( args ) == 0 ):
+ self.usage()
+ sys.exit()
+ self.remove( *args )
+ elif o in ("-h", "--help"):
+ self.usage()
+ sys.exit()
+ elif o in ("-o", "--output"):
+ output = a
+ print args
+ else:
+ assert False, "unhandled option"
+ def strip_domain ( self, line, domain_name ):
+ domain_regexp = domain_name.replace( '.', '\\.' ) #quote for regexp
+ regexp_just_1_domain = r'^\s*('+self.REGEXP_IPV4+')(\s*)('+domain_regexp+')(\s|$)'
+ if( re.search( regexp_just_1_domain , line, re.IGNORECASE ) ):
+ return False
+ tokens = re.split( r'(\s*)', line )
+ new_tokens = []
+ changed = False
+ for word in tokens:
+ if ( word.strip().lower() != domain_name.strip().lower() ):
+ if ( changed == True and new_tokens[-1] == ' ' and word == ' ' ):
+ """ nothing """
+ else:
+ new_tokens.append( word )
+ changed = False
+ else:
+ changed = True
+ line = "".join( new_tokens )
+ return line
+ def _security_check ( self, domain_name, ip ):
+ if ( re.search( '^localhost$', domain_name, re.IGNORECASE )!=None ):
+ print "hosts-manager won't operate localhost. So sorry"
+ return False
+ p = subprocess.Popen("hostname", stdout=subprocess.PIPE)
+ hostname = p.communicate()[0]
+ hostname = hostname.replace( "\n", "" )
+ if ( re.search( '^'+hostname+'$', domain_name, re.IGNORECASE )!=None ):
+ print "The domain name you gave corresponds to local computer's host name. I won't touch it, sorry"
+ return False
+ if ( ip != False ):
+ if ( re.search( '^'+self.REGEXP_IPV4, ip ) == None ):
+ print ip+" is a bad IP"
+ return False
+ return True
+ def _normalize_ip ( self, ip ):
+ if ( ip == None ): ip="127.0.0.1"
+ if ( re.search( '^localhost$', ip, re.IGNORECASE )!=None ):
+ ip="127.0.0.1"
+ return ip
+ def remove ( self, domain_name ):
+ if self._security_check( domain_name, False ) == False: return False
+ content = self._get_content()
+ found = self._find_domain( content, domain_name, False )
+ # self.strip_domain ( found['line'], domain_name )
+ if found == False:
+ print 'Domain "'+domain_name+'" not found'
+ return True
+ content[ found['idx'] ] = self.strip_domain ( found['line'], domain_name )
+ if content[ found['idx'] ] == False:
+ #content[ found['idx'] ] = "xxxxxxxxxxxxxxxxx"
+ del content[ found['idx'] ]
+ self._write( content )
+
+ def find (self, domain_name, ip = None ):
+ ip = self._normalize_ip( ip )
+ if self._security_check( domain_name, ip ) == False: return False
+ content = self._get_content()
+ found = self._find_domain( content, domain_name, ip )
+ return found
+
+ def create( self, domain_name, ip = None ):
+ ip = self._normalize_ip( ip )
+ if self._security_check( domain_name, ip ) == False: return False
+ content = self._get_content()
+ found = self._find_domain( content, domain_name, ip )
+ if ( found == False ):
+ print "adding "+ip+" "+domain_name+" at the end of file"
+ content.append( ip+"\t"+domain_name+"\n" )
+ else:
+ print "Found "+domain_name+" at line "+str(found['idx']+1)
+
+ print "Found domain: "+found['domain']+" ("+found['ip']+")"
+ #print domain_regexp
+ if ( found['domain'].lower() == domain_name.lower()):
+ if ( ip == found['ip'] ):
+ print ">>>"+found['line']+"Definition already present, skipping"
+ return True
+ else:
+ print ">>>"+found['line']
+ print "Ip differs. "+found['ip']+" has to become "+ip
+ print "Removing domain name from this line"
+ print "Creating a new entry in the next line"
+ content[ found['idx'] ] = self.strip_domain ( found['line'], domain_name )
+ content[ found['idx']+1: 1 ] = [ ip+"\t"+domain_name+"\n" ]
+ if content[ found['idx'] ] == False:
+ content.remove( False )
+ return True
+ else:
+ print ">>>"+line
+ print "Replacing "+domain_name+" at line "+str(found['idx']+1)
+ return True
+
+
+
+ self._write( content )
+
+ def _get_content ( self ):
+ file = open( '/etc/hosts', 'r' )
+ content = file.readlines()
+ file.close()
+ return content
+ def _find_domain( self, content, domain_name, ip = None ):
+
+ output = []
+ domain_regexp = domain_name.replace( '.', '\\.' ) #quote for regexp
+ found = False
+ # print domain_regexp
+
+ for idx, line in enumerate( content ):
+ regexp = r'^\s*('+self.REGEXP_IPV4+')\s*.*(\s*)('+domain_regexp+')(\s|$)'
+ match = re.search( regexp , line, re.IGNORECASE )
+ if ( match != None ):
+ print "Found "+domain_name+" at line "+str(idx+1)
+ found = True
+ found_entry = match.groups()
+ found_ip = found_entry[0]
+ found_domain = found_entry[2]
+ print "Found domain: "+found_domain+" ("+found_ip+")"
+ #print domain_regexp
+ if ( found_domain.lower() == domain_name.lower()):
+ result = {
+ 'domain':found_domain
+ , 'ip':found_ip
+ , 'idx': idx
+ , 'line': line }
+
+ return result
+ return False
+ def _create( self, domain_name, ip = None ):
+
+ ip = self._normalize_ip( ip )
+ if self._security_check( domain_name, ip ) == False: return False
+
+ return self._find_domain ( domain_name, ip )
+
+ file = open( '/etc/hosts', 'r' )
+ content = file.readlines()
+ file.close()
+
+ output = []
+ domain_regexp = domain_name.replace( '.', '\\.' ) #quote for regexp
+ found = False
+ # print domain_regexp
+
+ for idx, line in enumerate( content ):
+ regexp = r'^\s*('+self.REGEXP_IPV4+')\s*.*(\s*)('+domain_regexp+')(\s|$)'
+ match = re.search( regexp , line, re.IGNORECASE )
+ if ( match != None ):
+ print "Found "+domain_name+" at line "+str(idx+1)
+ found = True
+ found_entry = match.groups()
+ found_ip = found_entry[0]
+ found_domain = found_entry[2]
+ print "Found domain: "+found_domain+" ("+found_ip+")"
+ #print domain_regexp
+ if ( found_domain.lower() == domain_name.lower()):
+ if ( ip == found_ip ):
+ print ">>>"+line+"Definition already present, skipping"
+ break
+ else:
+ print ">>>"+line
+ print "Ip differs. "+found_ip+" has to become "+ip
+ print "Removing domain name from this line"
+ print "Creating a new entry in the next line"
+ content[ idx ] = self.strip_domain ( line, domain_name )
+ content[ idx+1: 1 ] = [ ip+"\t"+domain_name+"\n" ]
+ if content[ idx ] == False:
+ content.remove( False )
+
+ break
+ else:
+ print ">>>"+line
+ print "Replacing "+domain_name+" at line "+str(idx+1)
+ break
+ if ( found == False ):
+ print "adding "+ip+" "+domain_name+" at the end of file"
+ content.append( ip+"\t"+domain_name+"\n" )
+
+ self._write( content )
+ def _write ( self, content ):
+ if ( 0 ): #debug. output without writing to disk
+ for idx, line in enumerate( content ):
+ print str(idx)+". "+line.replace("\n", '')
+ else:
+ try:
+ dest = open( '/etc/hosts', 'w' )
+ dest.writelines( content )
+ dest.close()
+ except:
+ print "Error writing to file. Do you have the needed permissions?"
+ def _get_opt ():
+ print 1
+ def usage ( self ):
+ print """Hosts manager v. 0.1
+USAGE: hosts-manager -a hostname [ip]
+ hosts-manager -r hostname [ip]
+
+Options:
+ -a create a new entry in /etc/hosts
+ -r remove an entry in /etc/hosts
+"""
+
+
+if __name__ == "__main__":
+ HostsManager( True )
=== added file 'RapacheCore/Module.py'
--- RapacheCore/Module.py 1970-01-01 00:00:00 +0000
+++ RapacheCore/Module.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import os
+import tempfile
+import re
+from RapacheCore import Configuration
+from RapacheCore import Shell
+from xml.dom.minidom import *
+
+def is_denormalized_module ( fname ):
+ try:
+ flink = os.readlink( Configuration.MODS_ENABLED_DIR +"/"+fname )
+ flink = os.path.join(os.path.dirname( Configuration.MODS_AVAILABLE_DIR ), flink)
+ #no exceptions ? Means it's a link
+ return True
+ except:
+ return False
+ return False
+def is_not_normalizable( fname):
+ dest = Configuration.MODS_AVAILABLE_DIR + "/" + fname
+ return os.path.exists( dest )
+
+def blacklisted ( fname ):
+ if re.match( '.*[~]\s*$', fname ) != None : return True
+ if re.match( '.*.swp$', fname ) != None : return True
+ return False
+def normalize_module( fname ):
+ print "Normalizing:", fname
+ orig = Configuration.MODS_ENABLED_DIR + "/" + fname
+ dest = Configuration.MODS_AVAILABLE_DIR + "/" + fname
+ if ( os.path.exists( dest ) == True ):
+ print fname, "already exists in available dir. not even trying"
+ return False
+ command = [ 'mv', orig, dest ]
+ return Shell.command.sudo_execute( command )
+ return os.path.exists( dest )
+
+def get_module_dependants ( name, mods_dict ):
+ dependants = []
+ for idx in mods_dict:
+ if idx != name:
+ mod = mods_dict[ idx ]
+ for dependancy in mod.data[ 'dependancies' ]:
+ if dependancy == name: dependants.append( mod.data['name' ] )
+ return dependants
+"""
+def module_list ():
+ list = {}
+ dirList=os.listdir( Configuration.MODS_AVAILABLE_DIR )
+ dirList = [x for x in dirList if blacklisted( x ) == False ]
+ for fname in dirList :
+ tokens = os.path.splitext( fname )
+ if tokens[1] == '.load':
+ mod = ModuleModel( tokens[0] )
+ try:
+ mod.load()
+ except "VhostUnparsable":
+ pass
+ list[ fname ] = mod
+ mod = None
+ return list
+"""
+def module_list ():
+ list = {}
+
+ #load module descriptions
+ module_descriptions = {}
+ f = open( Configuration.GLADEPATH + "/modules.xml" , "r")
+ xml = f.read()
+ f.close()
+ document = parseString(xml)
+ for node in document.getElementsByTagName("module"):
+ name = node.getAttribute( "name" )
+ if node.firstChild:
+ description = node.firstChild.nodeValue
+ module_descriptions[name] = description
+
+ dirList=os.listdir( Configuration.MODS_AVAILABLE_DIR )
+ dirList = [x for x in dirList if blacklisted( x ) == False ]
+ for fname in dirList :
+ tokens = os.path.splitext( fname )
+ if tokens[1] == '.load':
+ description = None
+ # find a description
+
+ if module_descriptions.has_key(tokens[0]):
+ description = module_descriptions[tokens[0]]
+ elif module_descriptions.has_key("mod_" + tokens[0]):
+ description = module_descriptions["mod_" + tokens[0]]
+
+ mod = ModuleModel( tokens[0] )
+ mod.data[ 'description' ] = description
+ try:
+ mod.load( )
+ except "VhostUnparsable":
+ pass
+ list[ fname ] = mod
+ mod = None
+ return list
+class ModuleModel:
+
+ def __init__(self, name = None):
+ self.defaults = {
+ 'enabled' : False
+ , 'name' : None
+ , 'domain_name': None
+ , 'changed' : False
+ , 'dependancies' : []
+ }
+ self.data = {}
+ self.parsable = False
+ self.changed = False
+
+ self.data = self.defaults
+ if ( name != None ):
+ self.data[ 'name' ] = name
+ self.data[ 'enabled' ] = self.is_enabled()
+
+ def load (self, name = False):
+ try:
+ #reset everything
+ #print "Loading :\t",name
+ if ( name == False ): name = self.data[ 'name' ]
+ self.data = self.defaults
+ self.data['name'] = name
+
+
+ #print "Loading(b) :\t",self.data[ 'name' ]
+ options = {}
+ content = self.get_source()
+ self.__get_dependecies(content)
+ self.parsable = True
+ except:
+ #print "Unparsable by me - unsupported"
+ raise "ModuleUnparsable"
+ return False
+ self.data['configurable'] = \
+ os.path.exists( os.path.join ( Configuration.MODS_AVAILABLE_DIR, self.data['name']+".conf" ))
+
+
+ self.data.update( options )
+ #print self.data
+ return True
+ def __get_dependecies(self, content):
+ content = content.split("\n")
+ dependancies = []
+ for line in content:
+ match = re.match ( r'# Depends:(.*)', line )
+ if match != None:
+ dependancy = match.groups()[0].strip()
+ if dependancy != "" : dependancies.append( dependancy )
+ self.data[ 'dependancies' ] = dependancies
+ def is_enabled ( self ):
+ orig = self.data[ 'name' ] + ".load"
+ dirList=os.listdir( Configuration.MODS_ENABLED_DIR )
+ for fname in dirList:
+ try:
+ flink = os.readlink( Configuration.MODS_ENABLED_DIR +"/"+fname )
+ flink = os.path.join(os.path.dirname( Configuration.MODS_ENABLED_DIR +"/" ), flink)
+ #please note debian brilliantly features a nice set of
+ # mixed absolute and relative links. FREAKS !
+ # the added "/" is also necessary
+ flink = os.path.normpath(flink)
+ if ( flink == Configuration.MODS_AVAILABLE_DIR+"/"+orig ):
+ return True
+ except:
+ pass
+
+ return False
+
+ def _write(self, complete_path, content ):
+ tempfilename = tempfile.mktemp()
+ print "creating temporary file "+tempfilename
+ logfile = open( tempfilename , 'w')
+ logfile.write( content )
+ logfile.close()
+ command = ["cp",tempfilename, complete_path]
+ print "copying tempfile in the appropriate location: ",command
+ Shell.command.sudo_execute( command )
+
+ def toggle( self, status ):
+ "status = True|False"
+ if status:
+ command_name = "a2enmod"
+ else :
+ command_name = "a2dismod"
+ # set new value
+ #tokens = self.data['name'].split('.')
+ #del tokens[ len( tokens ) -1 ]
+ #name = ".".join(tokens)
+ name = self.data['name']
+ Shell.command.sudo_execute( [command_name, name] )
+ self.data['enabled'] = self.is_enabled()
+ self.changed = True
+
+ def get_source ( self ):
+ file = open( Configuration.MODS_AVAILABLE_DIR+'/'+self.data['name']+".load", 'r' )
+ content = file.read()
+ file.close()
+ return content
+ def get_configuration ( self ):
+ file = open( Configuration.MODS_AVAILABLE_DIR+'/'+self.data['name']+".conf", 'r' )
+ content = file.read()
+ file.close()
+ return content
+ def save_configuration (self, content):
+ complete_path = file = Configuration.MODS_AVAILABLE_DIR+'/'+self.data['name']+".conf"
+ self._write(complete_path, content)
\ No newline at end of file
=== added file 'RapacheCore/Observer.py'
--- RapacheCore/Observer.py 1970-01-01 00:00:00 +0000
+++ RapacheCore/Observer.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+class Observable (object) :
+ """Any instance to be observed with PollyObserver should extend
+ this class. Note this differs from the classical Observable
+ implementation because it only allows the object to be observed
+ from a single Observer"""
+ def __init__(self):
+ self.__observer = None
+ def register (self, observer):
+ self.__observer = observer
+ def unregister (self):
+ if ( self.__observer != None):
+ self.__observer.unregister( self )
+ self.__observer = None
+ def handle_event(self, event):
+ """Override this function in subclasses to implement your
+ own event handling logic"""
+ print self, "- now handling:", event.name, event.args, event
+ def raise_event (self, name, args = {}, no_caller = False ):
+ if no_caller:
+ event = Event( None, name, args )
+ else:
+ event = Event( self, name, args )
+ print '---------------->',event.name , 'raised by' , self
+ if self.__observer != None: self.__observer.notify( event )
+class PollyObserver:
+ """Simple observer derivation. Observes and dispatches events
+ from/to a poll of objects
+ """
+ def __init__(self):
+ self.__observed = []
+ def register(self, obj):
+ """adds an Observable instance to the poll of observed objects
+ and register itself to it."""
+ #print "checking for same obj"
+ for registered_obj in self.__observed:
+ #print obj, ' == ', registered_obj, '??'
+ if obj == registered_obj: return False
+ self.__observed.append( obj )
+ #print "-->",self.__observed
+ obj.register( self )
+ return True
+ def unregister(self, obj):
+ """remove an Observable instance to the poll of observed objects
+ and removes itself from it."""
+ for idx, registered_obj in enumerate( self.__observed ):
+ if obj == registered_obj:
+ del self.__observed[ idx]
+ obj.unregister()
+ return True
+ return False
+ def get_observed(self):
+ """returns observed object list, mainly for debug purpouses"""
+ return self.__observed
+ def notify (self, event ):
+ """dispatches an event all around"""
+ for registered_obj in self.__observed:
+ registered_obj.handle_event( event )
+
+class Event:
+ caller = None
+ name = None
+ args = {}
+ def __init__(self, caller, name, args ):
+ self.caller = caller
+ self.name = name
+ self.args = args
=== added file 'RapacheCore/PluginBase.py'
--- RapacheCore/PluginBase.py 1970-01-01 00:00:00 +0000
+++ RapacheCore/PluginBase.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,61 @@
+from Module import ModuleModel
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+class PluginBaseObject():
+
+ def __init__(self, path):
+
+ # The path to the plugin
+ self.path = path
+
+ # module this plugin works with
+ self.module = ""
+
+ # Define what additional config should be read from vhost file
+ self.vhosts_config = { } # 0 value | 1 options
+
+ def is_module_enabled(self):
+ if self.module:
+ module = ModuleModel(self.module)
+ module.load()
+ print "STATUS : " + self.module + " - " + str( module.is_enabled())
+ return module.is_enabled()
+ return True
+
+ def is_enabled(self):
+ enabled = self.is_module_enabled()
+
+ #TODO: Method of activating / deactivating plugins
+
+ return enabled
+
+ # Customise the module properties window
+ def load_module_properties(self, notebook, module):
+ return True
+
+ # Perform action on module properties save
+ def save_module_properties(self, module):
+ return True
+
+ # Customise the vhost properties window
+ def load_vhost_properties(self, notebook, vhost_data):
+ return True
+
+ # Perform action on vhost properties save
+ def save_vhost_properties(self, vhost_data):
+ return True
=== added file 'RapacheCore/PluginManager.py'
--- RapacheCore/PluginManager.py 1970-01-01 00:00:00 +0000
+++ RapacheCore/PluginManager.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,52 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import os.path
+import imp
+import sys
+import traceback
+class PluginManager():
+
+ def __init__(self):
+
+ print "-- Loading plugins --"
+ self.plugins = []
+ self.__add(os.path.join(sys.path[0], "plugins"))
+ self.__add(os.path.expanduser("~/.rapache/plugins"))
+ print ""
+
+ def __add(self, pluginpath):
+
+ print "checking plugin folder : " + pluginpath
+
+ if not pluginpath in sys.path:
+ sys.path.insert(0, pluginpath)
+
+ if os.path.exists(pluginpath):
+ for folder in os.listdir(pluginpath):
+ path = os.path.join(pluginpath,folder)
+ if os.path.isdir(path):
+ try:
+ module = __import__(folder + ".plugin")
+ obj = module.plugin.register(path)
+ self.plugins.append(obj)
+ print "loaded plugin : " + folder
+ except:
+ print "error loading plugin " + folder
+ traceback.print_exc(file=sys.stdout)
+
+
=== added file 'RapacheCore/Shell.py'
--- RapacheCore/Shell.py 1970-01-01 00:00:00 +0000
+++ RapacheCore/Shell.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,201 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+
+# <--- shit
+#def command( command ):
+# print "COMMAND: "+command
+# return os.system( command )
+# """
+# try:
+# retcode = call("mycmd" + " myarg", shell=True)
+# if retcode < 0:
+# print >>sys.stderr, "Child was terminated by signal", -retcode
+# else:
+# print >>sys.stderr, "Child returned", retcode
+# except OSError, e:
+# print >>sys.stderr, "Execution failed:", e
+# """
+
+import sys
+import gksu2
+import getpass
+import subprocess
+import StringIO
+import sys
+from subprocess import *
+import traceback
+
+class CommandLogEntry:
+
+ def __init__(self, command):
+ self.command = subprocess.list2cmdline(command)
+ self.returncode = None
+ self.output = None
+ self.error = None
+
+
+class CommandHandler:
+
+ def __init__(self):
+ # Verboseness
+ # 0 = No output
+ # 1 = prints the command and its return code
+ # 2 = Command output
+ self.verbose = 0
+ self.command_log = []
+ # let's make the object stateful, no duplicate password
+ # typing needed for our users
+ self.__password = None
+
+ def __get_password(self, description, prompt="Password: "):
+
+ ctx = gksu2.Context()
+ ctx.set_message(description)
+ ctx.set_command(subprocess.list2cmdline(["ls","/root"]))
+ ctx.set_grab(True)
+
+ return gksu2.ask_password_full(ctx, prompt) # how does su_full invoke keychain options?
+
+ def __sudo_popen (self, command, password ):
+ #don't enable the following line
+ #print "using password:", password
+
+ # prepend sudo to command and allow piping in
+ command.insert(0, "sudo")
+ command.insert(1, "-S")
+ p = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
+ #we need a try catch to avoid tracebacks to be printed
+ #as they would show the password
+ try:
+ p.stdin.write( password )
+ except:
+ #don't enable the following line as you password
+ #will be printed out
+ #traceback.print_exc() #<-- CAUTION !
+
+ print "ERROR: in __sudo_popen()"
+ pass
+ return p
+
+ def is_auth_needed (self):
+ if not self.__password: return True
+
+ #only ASCII chars in the fake pass, or it won't work
+ #because we have not encoding declared in this file
+ #http://www.python.org/dev/peps/pep-0263/
+ fakepass= 'xxxASAISUHAISGHauyguyagUDBhb2156412-,1-2.,1212'
+ command = [ 'head', '/var/log/syslog', '-n 1' ]
+ p = self.__sudo_popen( command, fakepass)
+ output, error = p.communicate()
+ returncode = p.returncode
+ self.__output(command, returncode, output, error)
+ print "needs login:", returncode
+ if returncode == 0:
+ return False
+ else:
+ self.__password = None
+ return True
+
+ # Description will be discarded
+ def execute(self, command, description = None ):
+ returncode = 0
+ output = None
+ error = None
+ # excute the command, capture output, error and return code
+ p = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
+ output, error = p.communicate()
+ returncode = p.returncode
+ self.__output(command, returncode, output, error)
+ return (returncode, output, error)
+
+ def __output (self, command, returncode, output, error ):
+ string_command = subprocess.list2cmdline(command)
+ if self.verbose > 0:
+ print "COMMAND (return code: "+str(returncode)+"): "+ string_command
+ if self.verbose > 1:
+ print output
+ if error:
+ sys.stderr.write( error+"\n")
+
+ def sudo_reset (self):
+ self.__password = None
+ command = ['sudo', '-K' ]
+ p = Popen( command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
+ output, error = p.communicate()
+ returncode = p.returncode
+ self.__output(command, returncode, output, error)
+
+ def sudo_execute(self, command, description = "Super user priviledges are required to perform this operation"):
+ #log = CommandLogEntry(command)
+ #self.command_log.append( log )
+
+ returncode = 0
+ output = None
+ error = None
+ new_password = None
+
+ auth_needed = self.is_auth_needed()
+
+ if auth_needed :
+ #let's ask the user for a new password
+ if not self.__password :
+ try:
+ new_password = self.__get_password(description)
+ except:
+ returncode = 1
+ error = "Incorrect password"
+
+ if (not auth_needed) or new_password:
+ #if already authorized let's fake a random password
+ if new_password:
+ password = new_password
+ elif self.__password:
+ password = self.__password
+ else:
+ #let's just fake it. It will work anyways
+ password = 'xxx'
+
+ # excute the command, capture output, error and return code
+ p = self.__sudo_popen( command, password )
+ #p.stdin.write(password)
+ output, error = p.communicate()
+ returncode = p.returncode
+ self.__output(command, returncode, output, error)
+
+ if new_password:
+ self.__password = 'asasasaasas'
+ #self.__password = new_password
+
+ #log.returncode = returncode
+ #log.output = output
+ #log.error = error
+
+ return (returncode, output, error)
+
+# Look ma'! A singleton !
+command = CommandHandler()
+
+if __name__ == "__main__":
+ c = CommandHandler()
+ c.verbose = 2
+ #print c.is_auth_needed()
+
+ print c.sudo_reset()
+ code, out, err = c.sudo_execute(["head", "/var/log/syslog"], "Pwd FTW !")
+ code, out, err = c.sudo_execute(["head", "/var/log/syslog"], "Pwd FTW !")
+
\ No newline at end of file
=== added file 'RapacheCore/VirtualHost.py'
--- RapacheCore/VirtualHost.py 1970-01-01 00:00:00 +0000
+++ RapacheCore/VirtualHost.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,379 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import os
+import tempfile
+import re
+from RapacheCore import Configuration
+from RapacheCore.ApacheConf import *
+from RapacheCore.HostsManager import HostsManager
+from RapacheCore import Shell
+
+VHOST_TEMPLATE = """#created for you by Rapache
+<VirtualHost *>
+ #ServerAdmin webmaster@xxxxxxxxxxx
+ ServerName example
+ DocumentRoot /var/www/examplepath
+</VirtualHost>"""
+
+
+def valid_domain_name ( name ):
+ # TODO: fix regular expression
+ valid = ( re.search( '^[a-zA-Z0-9.-]+$', name ) != None )
+ return valid
+
+def is_denormalized_vhost ( fname ):
+ try:
+ flink = os.readlink( Configuration.SITES_ENABLED_DIR +"/"+fname )
+ flink = os.path.join(os.path.dirname( Configuration.SITES_AVAILABLE_DIR ), flink)
+ #no exceptions ? Means it's a link
+ return True
+ except:
+ return False
+ return False
+def is_not_normalizable( fname):
+ dest = Configuration.SITES_AVAILABLE_DIR + "/" + fname
+ return os.path.exists( dest )
+
+def normalize_vhost( fname ):
+ print "Normalizing:", fname
+ orig = Configuration.SITES_ENABLED_DIR + "/" + fname
+ dest = Configuration.SITES_AVAILABLE_DIR + "/" + fname
+ if ( os.path.exists( dest ) == True ):
+ print fname, "already exists in available dir. not even trying"
+ return False
+ command = ['mv',orig,dest]
+ code, output, error = Shell.command.sudo_execute( command )
+ return ( code == 0 )
+ return os.path.exists( dest )
+
+class VirtualHostModel:
+
+ def __init__(self, name = None, plugin_manager = None):
+ self.defaults = {
+ 'enabled' : False
+ , 'name' : None
+ , 'ServerName': None
+ , 'changed' : False
+ , 'hack_hosts' : False
+ , 'DocumentRoot' : None
+ }
+ self.data = {}
+ self.parsable = False
+ self.changed = False
+ self.simulation = False
+
+ self.data = self.defaults
+ if ( name != None ):
+ self.data[ 'name' ] = name
+ self.data[ 'enabled' ] = self.is_enabled()
+
+ # Init plugin values so the keys exist
+ if plugin_manager:
+ for plugin in plugin_manager.plugins:
+ for key in plugin.vhosts_config.keys():
+ self.data[ key ] = None
+
+ def _search(self, content, regexp ):
+ content = content.split( "\n" )
+ for line in content:
+ match = re.search( regexp , line, re.IGNORECASE )
+ if ( match != None ) :
+ if match != False:
+ return match
+ return False
+
+ def _get_conf_value(self, content, regexp):
+ match = self._search(content, regexp )
+ if ( match == False or match == None ): return None
+ found_entry = match.groups()
+ found_value = found_entry[0]
+ return found_value
+ def load(self, name = False, plugin_manager = None):
+ if ( name == False ): name = self.data[ 'name' ]
+ options = {}
+ parser = Parser()
+ parser.load( os.path.join(Configuration.SITES_AVAILABLE_DIR, name) )
+ try:
+ piece = VhostParser( parser )
+ except "VhostNotFound":
+ self.parsable = False
+ return False
+ domain_name = piece.get_value( 'ServerName' )
+ if domain_name == None:
+ self.parsable = False
+ #return False
+ options[ 'ServerName' ] = domain_name
+ options[ 'ServerAlias' ] = piece.get_options( 'ServerAlias' )
+ print options[ 'ServerAlias' ]
+ options[ 'DocumentRoot' ] = piece.get_value('DocumentRoot')
+ hosts = HostsManager()
+ if ( domain_name == None or hosts.find ( domain_name ) == False ):
+ options['hack_hosts'] = False
+ else:
+ options['hack_hosts'] = True
+ self.parsable = True
+
+ # Load plugin values
+ if plugin_manager:
+ for plugin in plugin_manager.plugins:
+ for key in plugin.vhosts_config.keys():
+ if plugin.vhosts_config[key] == 1:
+ options[ key ] = piece.get_options( key )
+ else:
+ options[ key ] = piece.get_value( key )
+
+ self.data.update( options )
+ return True
+
+
+ def loaad (self, name = False):
+ print "Loading Vhosts list"
+ try:
+ #reset everything
+ #print "Loading :\t",name
+ if ( name == False ): name = self.data[ 'name' ]
+ self.data = self.defaults
+ self.data['name'] = name
+
+ #print "Loading(b) :\t",self.data[ 'name' ]
+ options = {}
+ content = self.get_source()
+ #domain_name = self._get_domain_name(content)
+ domain_regexp = r'^\s*ServerName\s+([A-Za-z0-9.\-_]*)'
+ domain_name = self._get_conf_value(content, domain_regexp)
+ options[ 'ServerName' ] = domain_name
+ domain_regexp = domain_name.replace( '.', '\\.' ) #quote for regexp
+ www_regexp = r'^\s*ServerAlias\s*[^#]*\s+www\.'+domain_regexp+'(\s*|$)'
+ folder_regexp = domain_regexp = r'^\s*DocumentRoot\s+(\S+\s*\S+)'
+
+ #print "Domain Name :\t"+domain_name
+ if self._search(content, www_regexp ) != None \
+ and self._search(content, www_regexp ) != False :
+ options[ 'has_www' ] = True
+ else:
+ options[ 'has_www' ] = False
+
+ #print "Has www :\t"+str(options[ 'has_www' ])
+
+ options[ 'DocumentRoot' ] = self._get_conf_value(content, folder_regexp)
+
+ #print "Document Root :\t"+str( options[ 'DocumentRoot' ] )
+ hosts = HostsManager()
+ if ( hosts.find ( domain_name ) == False ):
+ options['hack_hosts'] = False
+ else:
+ options['hack_hosts'] = True
+ self.parsable = True
+ except:
+ print "Unparsable by me - unsupported"
+ raise "VhostUnparsable"
+ return False
+ self.data.update( options )
+ #print self.data
+ return True
+
+ def is_enabled ( self ):
+ orig = self.data[ 'name' ]
+ dirList=os.listdir( Configuration.SITES_ENABLED_DIR )
+ for fname in dirList:
+ try:
+ flink = os.readlink( Configuration.SITES_ENABLED_DIR +"/"+fname )
+ flink = os.path.join(os.path.dirname( Configuration.SITES_ENABLED_DIR +"/" ), flink)
+ # please note debian features a nice set of
+ # mixed absolute and relative links. FREAKS !
+ # the added "/" is also necessary
+ flink = os.path.normpath(flink)
+ if ( flink == Configuration.SITES_AVAILABLE_DIR+"/"+orig ):
+ return True
+ except:
+ pass
+
+ return False
+
+ def toggle( self, status ):
+ "status = True|False"
+ if status:
+ command = "a2ensite"
+ else :
+ command = "a2dissite"
+ # set new value
+ if self.simulation:
+ print "SIMULATED ",[ command, self.data['name'] ]
+ self.data['enabled'] = status
+ else:
+ Shell.command.sudo_execute( [ command, self.data['name'] ] )
+ self.data['enabled'] = self.is_enabled()
+ self.changed = True
+
+ def delete( self ):
+ "Deletes a VirtualHost configuration file"
+ if ( self.is_enabled() ): self.toggle( False )
+ Shell.command.sudo_execute( [ 'rm', Configuration.SITES_AVAILABLE_DIR+'/'+self.data['name'] ])
+ def _create_complete_path ( self, complete_path ):
+ print "Attempting to create: " + complete_path
+ tokens = complete_path.split( '/' )
+ del tokens[ 0 ]
+ path = ''
+ for piece in tokens:
+ path = path + '/' + piece
+ if ( os.path.exists( path ) == False ):
+ try:
+ Shell.command.sudo_execute( ["mkdir", path] )
+ except:
+ print "error on creating path"+path
+ return False
+ print "Created path: " + path
+ return True
+
+ def get_source ( self ):
+ file = open( Configuration.SITES_AVAILABLE_DIR+'/'+self.data['name'], 'r' )
+ content = file.read()
+ file.close()
+ return content
+ def update ( self, new_options, name ):
+ print "updating virtual host", name
+ #print new_options
+
+ old_enabled = self.is_enabled()
+ print "IS ENABLED", old_enabled
+ parser = Parser()
+ parser.load( Configuration.SITES_AVAILABLE_DIR+'/'+name )
+ piece = VhostParser( parser )
+ old_servername = piece.get_value( 'ServerName' )
+
+ # Get a bit more dynamic with it
+ for key in new_options.keys():
+ obj = new_options[key]
+ if isinstance(obj, list):
+ piece.set_value(key, '')
+ for opt in obj:
+ piece.add_option(key, opt )
+ elif isinstance(obj, str):
+ if obj:
+ piece.set_value(key, obj)
+ else:
+ piece.remove_value(key)
+
+ #piece.set_value('ServerAlias', '' )
+ #for domain in new_options ['ServerAlias']:
+ # piece.add_option('ServerAlias', domain )
+
+ print "DocumentRoot From",piece.get_value('DocumentRoot' ),"to",new_options['DocumentRoot']
+ piece.set_value('DocumentRoot', new_options['DocumentRoot'] )
+
+ print "ServerName From",piece.get_value('ServerName' ),"to",new_options['ServerName']
+ piece.set_value('ServerName', new_options['ServerName'] )
+ complete_path = Configuration.SITES_AVAILABLE_DIR+'/'+ name
+
+ print "Writing.."
+ print parser.get_source()
+ self._write( complete_path, parser.get_source() )
+
+ #if the servername coincides with the configuration filename
+ #we try to stick with the convention
+ new_name = Configuration.SITES_AVAILABLE_DIR + "/"+ new_options['ServerName']
+ old_name = Configuration.SITES_AVAILABLE_DIR + "/"+ old_servername
+ print "old name", old_name
+ print "new name", new_name
+
+ if old_name != new_name and os.path.exists( new_name ) == False:
+ print "Server name changed, updating conf filename"
+ self.toggle( False )
+ Shell.command.sudo_execute( [mv, old_name, new_name] )
+ if os.path.exists( new_name ) == True:
+ #success ! we need to reload vhost with the new name
+ self.load( new_options['ServerName'] )
+ #...so we can toogle it on again
+ if old_enabled == True:
+ print "Re-activating"
+ self.toggle( True )
+ else:
+ print "Skipping activation"
+ else:
+ print "error! not created:", new_name
+ return True
+ def _write(self, complete_path, content ):
+ tempfilename = tempfile.mktemp()
+ print "creating temporary file "+tempfilename
+ logfile = open( tempfilename , 'w')
+ logfile.write( content )
+ logfile.close()
+ command = ['cp', tempfilename, complete_path ]
+ print "copying tempfile in the appropriate location: ",command
+ Shell.command.sudo_execute( command )
+
+ def create ( self, new_options ):
+
+ options = self.data
+ options.update( new_options )
+
+ #as of creation-time name is not expected to be in options
+ options['name'] = options[ 'ServerName' ]
+ complete_path = Configuration.SITES_AVAILABLE_DIR+'/'+options['name']
+
+ print options
+ print "Creating virtualhost: "+options['name']
+ print "Folder: "+options['DocumentRoot']
+
+ if ( os.path.exists( options['DocumentRoot'] ) == False ):
+ print "Folder "+options['DocumentRoot']+" does not exist"
+ self._create_complete_path( options['DocumentRoot'] )
+
+ if ( os.path.exists( options['DocumentRoot'] ) == False ):
+ self.error( "Could not create target folder" ) #TODO fix this
+ return False
+
+ if ( valid_domain_name( options['ServerName'] ) == False ):
+ self.error ( 'Bad domain name: '+options['ServerName'] )
+ return False
+
+ if os.path.exists( complete_path ):
+ raise "VhostExists", 'Virtual host already exists :('
+ #self.error( 'Virtual host already exists :(' )
+ return False
+ """
+ template = VHOST_TEMPLATE.replace( '||example||', options['ServerName'] )
+ template = template.replace( '||DocumentRoot||', options['DocumentRoot'] )
+ if ( options[ 'has_www' ] ):
+ template = template.replace( '#ServerAlias www', 'ServerAlias www' )
+ """
+ parser = Parser()
+ parser.set_content_from_string( VHOST_TEMPLATE )
+ piece = VhostParser( parser )
+ piece.set_value('ServerName', options['ServerName'] )
+ piece.set_value('DocumentRoot', options['DocumentRoot'] )
+
+ print "min", piece.min, "max", piece.max
+ #reset previous aliases
+ piece.set_value('ServerAlias', '' )
+ for domain in options ['ServerAlias']:
+ piece.add_option('ServerAlias', domain )
+ print parser.get_content()
+
+ self._write( complete_path, "\n".join(parser.get_content() ) )
+
+ if ( options[ 'hack_hosts' ] ):
+ Shell.command.sudo_execute ( [Configuration.APPPATH+'/hosts-manager', '-a', options['ServerName'] ] )
+ for alias_name in options[ 'ServerAlias' ]:
+ Shell.command.sudo_execute ( [Configuration.APPPATH+'/hosts-manager', '-a',alias_name ])
+ self.changed = True
+ self.toggle( True ) #activate by default
+
+ return True
=== added file 'RapacheCore/__init__.py'
=== added directory 'RapacheGtk'
=== renamed directory 'RapacheGtk' => 'RapacheGtk.moved'
=== added file 'RapacheGtk/CheckListView.py'
--- RapacheGtk/CheckListView.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/CheckListView.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,123 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import gtk
+import gobject
+
+(
+ COLUMN_FIXED,
+ COLUMN_SEVERITY,
+ COLUMN_MARKUP
+) = range(3)
+from RapacheCore import Configuration
+import RapacheCore.Observer
+from RapacheGtk.EventDispatcher import Master
+
+class CheckListView (gtk.TreeView ):
+ """Nice list with icons and checkboxes"""
+ def __init__ (self, *args, **kwargs):
+ super (CheckListView, self).__init__ (*args, **kwargs)
+
+ self.toggled_callback = None
+ self.selected_callback = None
+ self.icon_callback = None
+
+ self.Observable = RapacheCore.Observer.Observable()
+ Master.register(self)
+
+ self.column_checkbox = None
+ self.column_description = None
+ self.column_icon = None
+
+ self.__add_columns()
+
+ self.set_headers_visible( False )
+ self.set_rules_hint(True)
+ self.set_search_column(COLUMN_SEVERITY)
+
+ #----decorating observer
+ def register (self, *args, **kwargs): return self.Observable.register(*args, **kwargs)
+ def unregister (self, *args, **kwargs): return self.Observable.unregister(*args, **kwargs)
+ def handle_event (self, *args, **kwargs): return self.Observable.handle_event(*args, **kwargs)
+ def raise_event (self, *args, **kwargs): return self.Observable.raise_event(*args, **kwargs)
+
+ def load (self):
+ raise "AbstractMethod", "Please override this"
+
+ def _reset_model (self):
+ lstore = self.get_model()
+ if ( lstore == None ):
+ lstore = self._default_model()
+ self.set_model( lstore )
+ else:
+ lstore.clear()
+ return lstore
+ def _default_model (self):
+ lstore = gtk.ListStore(
+ gobject.TYPE_BOOLEAN,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING)
+ return lstore
+
+ def __toggled(self, *args, **kwargs):
+ if self.toggled_callback != None:
+ self.toggled_callback( *args, **kwargs )
+ def __selected(self, *args, **kwargs):
+ if self.selected_callback != None:
+ self.selected_callback( *args, **kwargs )
+ def __icon_requested(self, *args, **kwargs):
+ if self.icon_callback != None:
+ self.icon_callback( *args, **kwargs )
+
+ def __add_columns(self):
+ #model = self.get_model()
+ # column for fixed toggles
+ renderer = gtk.CellRendererToggle()
+ renderer.connect('toggled', self.__toggled, self)
+ self.column_checkbox = gtk.TreeViewColumn('Enabled', renderer, active=COLUMN_FIXED)
+ self.column_checkbox.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
+ self.column_checkbox.set_fixed_width(40)
+ self.append_column(self.column_checkbox)
+
+ self.column_icon = gtk.TreeViewColumn()
+ cellRenderer = gtk.CellRendererPixbuf()
+ self.column_icon.pack_start(cellRenderer, expand = False)
+ self.column_icon.set_cell_data_func(cellRenderer, self.__icon_requested )
+ self.append_column(self.column_icon)
+
+ self.column_description = gtk.TreeViewColumn('Description', gtk.CellRendererText(),
+ markup=COLUMN_MARKUP)
+ self.column_description.set_sort_column_id(COLUMN_MARKUP)
+ self.append_column(self.column_description)
+ self.get_selection().connect("changed", self.__selected )
+
+ def get_selected_line( self ):
+ #try:
+ selection = self.get_selection()
+ #print '==>', self.get_selected()
+ #print selection.get_selected_rows()[1]
+ try:
+ rows = selection.get_selected_rows()[1][0]
+ num_row = rows[0]
+ model = self.get_model()
+ name = model[ num_row ][1]
+ except IndexError:
+ return None
+ return name
+ #except:
+ # return None
+
+gobject.type_register (CheckListView)
\ No newline at end of file
=== added file 'RapacheGtk/ConfirmationWindow.py'
--- RapacheGtk/ConfirmationWindow.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/ConfirmationWindow.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import re
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+try:
+ from RapacheCore import Configuration
+except:
+ if __name__ != "__main__":
+ sys.exit(1)
+
+import os
+
+
+class ConfirmationWindow:
+
+ def __init__ ( self, parent = None):
+
+ self.parent = parent
+ self.title = None
+ self.question = None
+ self.return_value = None
+
+ gladefile = os.path.join(Configuration.GLADEPATH, "confirmation.glade")
+ wtree = gtk.glade.XML(gladefile)
+
+ self.window = wtree.get_widget("confirmation_window")
+ self.ok_button = wtree.get_widget("ok_button")
+ self.cancel_button = wtree.get_widget("cancel_button")
+ self.question_label = wtree.get_widget("question_label")
+ signals = {
+ "on_ok_button_clicked" : self.on_ok_button_clicked,
+ "on_cancel_button_clicked" : self.on_cancel_button_clicked
+ }
+ wtree.signal_autoconnect(signals)
+
+ # add on destroy to quit loop
+ self.window.connect("destroy", self.on_destroy)
+
+ def run(self):
+ if self.title: self.window.set_title ( self.title )
+ if self.question: self.question_label.set_text( self.question )
+
+ self.window.show()
+ gtk.main()
+
+ def on_destroy(self, widget, data=None):
+ gtk.main_quit()
+
+ def on_ok_button_clicked(self, widget):
+ self.return_value = True
+ self.window.destroy()
+ def on_cancel_button_clicked(self, widget):
+ self.return_value = False
+ self.window.destroy()
+
+def ask_confirmation ( question = None, title = None):
+ win = ConfirmationWindow()
+ win.title = title
+ win.question = question
+ win.run()
+ answer = win.return_value
+ print "Question: ", question
+ print "Answer: ", answer
+ return answer
+
+
+if __name__ == "__main__":
+ class Configuration:
+ GLADEPATH = '../Glade'
+ value = ask_confirmation( 'did you solve bug #1 ?', 'bug confirmation')
+ print '================='
+ print value
+
+
\ No newline at end of file
=== added file 'RapacheGtk/DesktopEnvironment.py'
--- RapacheGtk/DesktopEnvironment.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/DesktopEnvironment.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,44 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import subprocess
+import os
+from RapacheCore import Shell
+
+"""abstracts Desktop Environment's specific operation."""
+# TODO: refactor this into a factory to support more than a Desktop Environment easily
+#
+# care should be taken with userid, we don't want root priviledges when they're not needed
+
+
+# Grabbed from Ubuntu's UpdateManager (ChangelogViewer.py)
+# Copyright (c) 2006 Sebastian Heinlein
+# 2007 Canonical
+# TODO: move this into an utility module
+def open_url(url):
+ """Opens the specified URL in a browser"""
+ # Find an appropiate browser
+ if os.path.exists('/usr/bin/gnome-open'):
+ command = ['gnome-open', url]
+ else:
+ command = ['x-www-browser', url]
+ # Avoid to run the browser as user root
+ if os.getuid() == 0 and os.environ.has_key('SUDO_USER'):
+ command = ['sudo', '-u', os.environ['SUDO_USER']] + command
+ subprocess.Popen(command)
+# TODO: find out how to open nautilus in background
+def open_dir( path):
+ Shell.command.sudo_execute ( ['nautilus',path, '--no-desktop'] )
=== added file 'RapacheGtk/EditDomainNameGui.py'
--- RapacheGtk/EditDomainNameGui.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/EditDomainNameGui.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import re
+import os
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+from RapacheCore.VirtualHost import *
+from RapacheGtk import GuiUtils
+
+class EditDomainNameWindow:
+
+ def __init__ ( self, domain = ""):
+ self.return_value = None
+
+ gladefile = os.path.join(Configuration.GLADEPATH, "edit_domain_name.glade")
+ wtree = gtk.glade.XML(gladefile)
+
+ self.window = wtree.get_widget("dialog_edit_domain_name")
+ self.entry_domain = wtree.get_widget("entry_domain")
+ self.label_heading = wtree.get_widget("label_heading")
+ self.image_icon = wtree.get_widget("image_icon")
+
+ signals = {
+ "on_button_ok_clicked" : self.on_button_ok_clicked,
+ "on_button_cancel_clicked" : self.on_button_cancel_clicked
+ }
+ wtree.signal_autoconnect(signals)
+
+ # add on destroy to quit loop
+ self.window.connect("destroy", self.on_destroy)
+
+ if domain:
+ self.entry_domain.set_text( domain )
+
+ def run(self):
+ self.window.show()
+ self.entry_domain.select_region(0,-1)
+ gtk.main()
+
+ return self.return_value
+
+ def on_destroy(self, widget, data=None):
+ gtk.main_quit()
+
+ def on_button_ok_clicked(self, widget):
+ self.return_value = self.entry_domain.get_text()
+ self.window.destroy()
+ return
+
+ def on_button_cancel_clicked(self, widget):
+ self.window.destroy()
+ return
+
=== added file 'RapacheGtk/EventDispatcher.py'
--- RapacheGtk/EventDispatcher.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/EventDispatcher.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,19 @@
+import RapacheCore.Observer
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Master = RapacheCore.Observer.PollyObserver()
\ No newline at end of file
=== added file 'RapacheGtk/GuiUtils.py'
--- RapacheGtk/GuiUtils.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/GuiUtils.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,53 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import gtk
+import gtksourceview2
+import pango
+from RapacheCore import Configuration
+
+def style_as_tooltip( obj ):
+ pw = gtk.Window(gtk.WINDOW_POPUP)
+ pw.set_name('gtk-tooltip')
+ pw.ensure_style()
+ obj.set_style(pw.get_style())
+ obj.connect('expose-event', paint)
+
+def paint(box, event):
+ box.style.paint_flat_box(box.window, gtk.STATE_NORMAL, gtk.SHADOW_OUT, None, box, "tooltip", box.allocation.x+1, box.allocation.y+1, box.allocation.width-2, box.allocation.height-2)
+
+def change_button_label ( button, new_label ):
+ """Changes the label of a button"""
+ button.show()
+ alignment = button.get_children()[0]
+ hbox = alignment.get_children()[0]
+ image, label = hbox.get_children()
+ label.set_text( new_label )
+
+def new_apache_sourceview():
+ bufferS = gtksourceview2.Buffer()
+ manager = gtksourceview2.LanguageManager()
+
+ #language = manager.get_language_from_mime_type("text/xml")
+ manager.set_search_path( [ Configuration.GLADEPATH ] + manager.get_search_path() )
+ language = manager.get_language('apache')
+ bufferS.set_language(language)
+ bufferS.set_highlight_syntax(True)
+ sourceview = gtksourceview2.View(bufferS)
+ sourceview.set_show_line_numbers(True)
+ #TODO sniff gnome default monospace font
+ sourceview.modify_font(pango.FontDescription("monospace 10"))
+ return sourceview
\ No newline at end of file
=== added file 'RapacheGtk/ModuleGui.py'
--- RapacheGtk/ModuleGui.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/ModuleGui.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+""".
+Issues with the new window:
+ - self.parent doesn't work
+ - onblur doesn't trigger when pressing Return
+ - changing a domain name doesn't change subdomains
+ - empty server aliases shuoldn't be managed
+ALSO:
+ - please implement a delete directive func in the parser
+ - move denorm. vhosts in another tab
+ - merge with Qense warning window
+"""
+
+import sys
+import re
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+import os
+import pango
+import tempfile
+import traceback
+import RapacheGtk.GuiUtils
+from RapacheCore.Module import *
+from RapacheGtk import GuiUtils
+import RapacheGtk.DesktopEnvironment as Desktop
+
+
+def open_module_doc( name ):
+ if ( name == None ): return False
+ url = "http://httpd.apache.org/docs/2.2/mod/mod_%s.html" % name
+ Desktop.open_url( url )
+
+class ModuleWindow:
+
+ def __init__ ( self, parent = None):
+
+ self.module = None
+ self.create_new = True
+ self.parent = parent
+
+ gladefile = os.path.join(Configuration.GLADEPATH, "edit_module.glade")
+ wtree = gtk.glade.XML(gladefile)
+
+ self.window = wtree.get_widget("dialog_edit_module")
+ #self.text_view_module_conf = wtree.get_widget("text_view_module_conf")
+ self.notebook = wtree.get_widget("notebook")
+ self.button_save = wtree.get_widget("button_save")
+ self.error_area = wtree.get_widget("error_area")
+ self.module_doc_button = wtree.get_widget("module_doc_button")
+
+ signals = {
+ "on_button_save_clicked" : self.on_button_save_clicked,
+ "on_button_cancel_clicked" : self.on_button_cancel_clicked,
+ "on_module_doc_button_clicked" : self.on_module_doc_button_clicked
+ }
+ wtree.signal_autoconnect(signals)
+ # add on destroy to quit loop
+ self.window.connect("destroy", self.on_destroy)
+
+ self.text_view_module_conf = GuiUtils.new_apache_sourceview()
+ self.text_view_module_conf.show()
+ wtree.get_widget("text_view_module_conf_area").add(self.text_view_module_conf)
+
+ GuiUtils.change_button_label( self.module_doc_button, 'Documentation' )
+ GuiUtils.style_as_tooltip( self.error_area )
+ def run(self):
+ self.window.show()
+ gtk.main()
+
+ def load (self, name ):
+ self.window.set_title(name)
+ self.module = ModuleModel ( name )
+ #self.module.load()
+ buf = self.text_view_module_conf.get_buffer()
+ buf.set_text( self.module.get_configuration() )
+
+ # Load UI Plugins
+ for plugin in self.parent.plugin_manager.plugins:
+ if plugin.module == name:
+ try:
+ print "Loading plugin " + name
+ plugin.load_module_properties(self.notebook, self.module)
+ except Exception:
+ traceback.print_exc(file=sys.stdout)
+
+ def on_destroy(self, widget, data=None):
+ gtk.main_quit()
+
+ def on_button_save_clicked(self, widget):
+
+ name = self.module.data['name']
+ print "Current name:", name
+ buff = self.text_view_module_conf.get_buffer()
+ text = buff.get_text(buff.get_start_iter(), buff.get_end_iter())
+
+ mod = ModuleModel( name )
+ mod.save_configuration( text )
+
+ #self.parent.refresh_vhosts()
+ self.parent.please_restart()
+ self.window.destroy()
+
+ def on_button_cancel_clicked(self, widget):
+ self.window.destroy()
+ return
+ def on_module_doc_button_clicked (self, widget ):
+ name = self.module.data['name']
+ open_module_doc(name)
+ def show_error ( self, message ):
+
+ self.xml.get_widget( 'message_text' ).set_label( '<b>'+message+'</b>' )
+ self.xml.get_widget( 'message_container' ).show()
=== added file 'RapacheGtk/RapacheGui.py'
--- RapacheGtk/RapacheGui.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/RapacheGui.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,294 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#TODO throw appropriate exceptions (bug: vhost already exist displays only
+# after actually trying to create it's dir. check before )
+
+#TODO read ERRORLEVEL from command line operations
+#TODO stop operation if gksudo fails
+#TODO check for sites-enabled-only sites and normalize them
+
+#TODO delete-tarantella: hosts deletion & confirmation
+
+#TODO refuse to edit complex vhosts ( done ? )
+
+import gnome.ui
+import gobject
+import gtk
+import os
+import re
+(
+ COLUMN_FIXED,
+ COLUMN_SEVERITY,
+ COLUMN_MARKUP
+) = range(3)
+
+
+from RapacheGtk.VirtualHostGui import VirtualHostWindow
+from RapacheGtk.ModuleGui import ModuleWindow
+from RapacheCore.PluginManager import PluginManager
+from RapacheGtk.ModuleGui import open_module_doc
+from RapacheCore.VirtualHost import *
+from RapacheGtk import ConfirmationWindow
+from RapacheGtk import GuiUtils
+from RapacheCore import Shell
+import VhostsTreeView
+import RapacheCore.Observer
+from RapacheGtk.EventDispatcher import Master
+import subprocess
+import RapacheGtk.DesktopEnvironment as Desktop
+
+data = \
+[(False, "Loading", "please wait" )]
+
+APPNAME="Rapache"
+APPVERSION="0.6"
+
+
+class MainWindow( RapacheCore.Observer.Observable ) :
+ """This is an Hello World Rapacheefication application"""
+
+ def __init__(self, *args, **kwargs):
+ super (MainWindow, self).__init__ (*args, **kwargs)
+ Master.register(self)
+
+ self.denormalized_virtual_hosts = {}
+ self.plugin_manager = PluginManager()
+ gnome.init(APPNAME, APPVERSION)
+ self.gladefile = Configuration.GLADEPATH + "/" + "main.glade"
+ self.xml = gtk.glade.XML(self.gladefile)
+ #Create our dictionary and connect it
+ dic = { "new_button_clicked" : self.new_button_clicked,
+ "on_MainWindow_destroy" : self.quit ,
+ "please_restart" : self.restart_apache ,
+ "on_delete" : self.delete_button_clicked,
+ "edit_button_clicked" : self.edit_button_clicked,
+ "edit_module_button_clicked" : self.edit_module_button_clicked,
+ "browse_sites_available" : self.browse_sites_available,
+ "fix_vhosts_clicked" : self.fix_vhosts,
+ "surf_this_button_clicked" : self.surf_this,
+ "browse_button_clicked" : self.browse_this,
+ "about_clicked" : self.display_about,
+ "open_doc_button_clicked" : self.open_doc_button_clicked,
+ "on_button_hide_warning_clicked" : self.on_button_hide_warning_clicked,
+ "quit" : self.quit }
+ gtk.window_set_default_icon(self.xml.get_widget("MainWindow").get_icon())
+ self.xml.signal_autoconnect(dic)
+ GuiUtils.change_button_label ( self.xml.get_widget( 'restart_apache' ), "Restart Apache" )
+ GuiUtils.change_button_label ( self.xml.get_widget( 'fix_vhosts' ), "Fix Virtual Hosts" )
+ #hereby we create lists
+ self.create_vhost_list()
+ self.create_modules_list()
+ #hereby we fill them
+ self.refresh_lists()
+
+ GuiUtils.style_as_tooltip( self.xml.get_widget( 'restart_apache_notice' ) )
+ GuiUtils.style_as_tooltip( self.xml.get_widget( 'unnormalized_notice' ) )
+
+ def on_button_hide_warning_clicked(self, widget):
+ self.xml.get_widget( 'restart_apache_notice' ).hide()
+
+ def handle_event(self, event ):
+ if event.name == 'please_restart_apache':
+ self.please_restart()
+ return
+ if event.name == 'please_reload_lists':
+ self.load_lists()
+ return
+ def browse_sites_available(self, widget):
+ Desktop.open_dir( Configuration.SITES_AVAILABLE_DIR )
+ return
+
+ def new_button_clicked(self, widget):
+ new_vhost_window = VirtualHostWindow ( self )
+ #new_vhost_window.load()
+ new_vhost_window.run()
+ def edit_button_clicked(self, widget, notused = None, notused2 = None):
+ name = self.vhosts_treeview.get_selected_line()
+ print "edit button clicked on:" + name
+ if ( self.is_vhost_editable( name ) == False ): return False
+ new_vhost_window = VirtualHostWindow ( self )
+ new_vhost_window.load( name )
+ new_vhost_window.run()
+ def delete_button_clicked( self, widget ):
+ name = self.vhosts_treeview.get_selected_line()
+ if ( self.is_vhost_editable( name ) == False ): return False
+ if ( name == None ): return False
+ result = ConfirmationWindow.ask_confirmation(
+ "You are about to delete the following domain: \n\n"+name+"\n\nData won't be recoverable. Proceed ?"
+ ,'VirtualHost deletion' )
+ if ( result != True ): return False
+ site = VirtualHostModel( name )
+ site.delete()
+ self.vhosts_treeview.load()
+ self.please_restart()
+ def edit_module_button_clicked(self, widget, notused = None, notused2 = None):
+ name = self.modules_treeview.get_selected_line()
+ if ( self.is_module_editable( name ) == False ): return False
+ print "module edit button clicked on:", name
+ module_window = ModuleWindow ( self )
+ module_window.load( name )
+ module_window.run()
+ def quit (self, widget):
+ print 'quitting'
+ gtk.main_quit()
+ exit()
+
+ def create_vhost_list(self ):
+ #print parent
+ #sw = gtk.ScrolledWindow()
+ sw = self.xml.get_widget( 'vhosts_scroll_box' )
+ # create virtualhosts treeview
+ treeview = VhostsTreeView.VhostsTreeView()
+ treeview.selected_callback = self.row_selected
+ treeview.connect_after("row-activated", self.edit_button_clicked )
+ self.vhosts_treeview = treeview
+ self.xml.get_widget( 'vhost_container' ).add(treeview)
+ self.xml.get_widget( 'vhost_container' ).reorder_child( treeview, 0)
+
+ sw.set_shadow_type(gtk.SHADOW_NONE)
+ sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ sw.set_shadow_type(gtk.SHADOW_NONE)
+ sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+
+ # create denormalized vhosts.
+ # We check for conf files only present in /etc/apache2/sites-enabled,
+ # display them as a separate list and offer user to normalize them
+ # moving them in /etc/apache2/sites-available and linking them back
+ # from /etc/apache2/sites-enabled
+
+ denormalized_treeview = VhostsTreeView.DenormalizedVhostsTreeView()
+ self.denormalized_treeview = denormalized_treeview
+ self.xml.get_widget( 'problems_area' ).add(denormalized_treeview)
+ self.xml.get_widget( 'problems_area' ).reorder_child( denormalized_treeview, 2)
+ denormalized_treeview.set_sensitive( False )
+ denormalized_treeview.show()
+ sw.show_all()
+ #hidden by default
+ self.xml.get_widget( 'unnormalized_notice' ).hide_all()
+
+ def create_modules_list(self ):
+ sw = self.xml.get_widget( 'modules_scroll_box' )
+ # create virtualhosts treeview
+ treeview = VhostsTreeView.ModulesTreeView()
+ treeview.connect_after("row-activated", self.edit_module_button_clicked )
+ treeview.selected_callback = self.module_row_selected
+ self.modules_treeview = treeview
+ self.xml.get_widget( 'modules_container' ).add(treeview)
+ self.xml.get_widget( 'modules_container' ).reorder_child( treeview, 0)
+ sw.set_shadow_type(gtk.SHADOW_NONE)
+ sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ sw.set_shadow_type(gtk.SHADOW_NONE)
+ sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ sw.show_all()
+
+ def refresh_vhosts ( self ):
+ print "reloading vhosts.."
+ self.vhosts_treeview.load()
+ def refresh_denormalized_vhosts (self):
+ self.denormalized_treeview.load()
+ if ( len( self.denormalized_treeview.items ) > 0 ):
+ self.xml.get_widget( 'unnormalized_notice' ).show_all()
+ self.xml.get_widget( 'notebook' ).get_nth_page( 2 ).show()
+ else:
+ self.xml.get_widget( 'unnormalized_notice' ).hide_all()
+ self.xml.get_widget( 'notebook' ).get_nth_page( 2 ).hide()
+ def refresh_modules (self):
+ print "reloading modules.."
+ self.modules_treeview.load()
+ def refresh_lists (self):
+ self.refresh_vhosts()
+ self.refresh_modules()
+ self.refresh_denormalized_vhosts()
+ def please_restart ( self ):
+ self.xml.get_widget( 'restart_apache_notice' ).show()
+ def restart_apache ( self, widget ):
+ print "Restarting apache on user's request"
+ Shell.command.sudo_execute( ['/etc/init.d/apache2', 'stop'] )
+ Shell.command.sudo_execute( ['/etc/init.d/apache2', 'start'] )
+ self.xml.get_widget( 'restart_apache_notice' ).hide()
+ self.refresh_lists()
+ def is_vhost_editable (self, name):
+ return name != 'default'
+ def is_module_editable (self, name):
+ editable = False
+ if name:
+ mod = self.modules_treeview.items[ name+".load" ]
+ editable = mod.data[ 'configurable' ]
+ return editable
+ def row_selected( self, widget ):
+ name = self.vhosts_treeview.get_selected_line()
+ if ( name == None ):
+ self.xml.get_widget( 'delete_button' ).set_sensitive( False )
+ self.xml.get_widget( 'edit_button' ).set_sensitive( False )
+ self.xml.get_widget( 'open_in_browser_button' ).set_sensitive( False )
+ else:
+ editable = self.is_vhost_editable( name )
+ self.xml.get_widget( 'delete_button' ).set_sensitive( editable )
+ self.xml.get_widget( 'edit_button' ).set_sensitive( editable )
+ surfable = self.get_current_vhost_directive( 'ServerName' ) != None
+ self.xml.get_widget( 'surf_this_button' ).set_sensitive( surfable )
+ browsable = self.get_current_vhost_directive( 'DocumentRoot' ) != None
+ self.xml.get_widget( 'browse_button' ).set_sensitive( browsable )
+ def module_row_selected( self, widget):
+ name = self.modules_treeview.get_selected_line()
+ editable = self.is_module_editable(name)
+ self.xml.get_widget( 'edit_module_button' ).set_sensitive( editable )
+ if name != None: self.xml.get_widget( 'open_doc_button' ).set_sensitive( True )
+ # TODO: open doc only for apache2.2 own modules, not third-party (eg mod_php5)
+ # TODO: sniff apache version, don't hardcode it
+ def open_doc_button_clicked( self, widget ):
+ name = self.modules_treeview.get_selected_line()
+ if ( name == None ): return False
+ open_module_doc(name)
+
+ def fix_vhosts(self, widget):
+ items = self.denormalized_treeview.get_items()
+ for name in items:
+ normalize_vhost( name )
+ #since they were in the enabled, let's enabl'em again
+ for name in items:
+ site = VirtualHostModel( name )
+ site.toggle(True)
+ self.refresh_vhosts()
+ self.refresh_denormalized_vhosts()
+ def get_current_vhost_directive (self, directive_name ):
+ name = self.vhosts_treeview.get_selected_line()
+ if ( name == None ): return None
+ return self.vhosts_treeview.items[ name ].data[ directive_name ]
+ def surf_this(self, widget):
+ name = self.vhosts_treeview.get_selected_line()
+ if name == 'default':
+ server_name = 'localhost'
+ else:
+ server_name = self.get_current_vhost_directive( 'ServerName' )
+ if ( server_name ): Desktop.open_url( "http://" + server_name )
+ def browse_this(self, widget):
+ document_root = self.get_current_vhost_directive( 'DocumentRoot' )
+ Desktop.open_dir( document_root )
+
+
+ def display_about (self, widget):
+ dialog = gtk.AboutDialog()
+ dialog.set_name( APPNAME )
+ dialog.set_version( APPVERSION )
+ dialog.set_authors( ["Rapache Developers\nhttps://launchpad.net/~rapache-devel"] )
+ dialog.set_comments('Rapache is an Apache configurator for Ubuntu/Gnome systems')
+ dialog.set_website('http://launchpad.net/rapache')
+ dialog.run()
+ dialog.destroy()
=== added file 'RapacheGtk/VhostsTreeView.py'
--- RapacheGtk/VhostsTreeView.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/VhostsTreeView.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,237 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import gtk
+import gobject
+from CheckListView import *
+import os
+import re
+from RapacheCore.VirtualHost import *
+from RapacheCore import Module
+from RapacheCore import Configuration
+
+class ConfFilesTreeView( CheckListView ):
+ def __init__ (self, *args, **kwargs):
+ super (ConfFilesTreeView, self).__init__ (*args, **kwargs)
+ self.items = {}
+ def _blacklisted ( self, fname ):
+ if re.match( '.*[~]\s*$', fname ) != None : return True
+ if re.match( '.*.swp$', fname ) != None : return True
+ return False
+ def is_empty (self):
+ return len( self.items ) == 0
+ def get_items(self):
+ return self.items
+gobject.type_register (ConfFilesTreeView)
+
+
+class VhostsTreeView ( ConfFilesTreeView ):
+ def __init__ (self, *args, **kwargs):
+ super (VhostsTreeView, self).__init__ (*args, **kwargs)
+ self.icon_callback = self.__get_row_icon
+ self.toggled_callback = self.__fixed_toggled
+
+
+ def load(self):
+ self.items = {}
+ site_template = "<b><big>%s</big></b>\n<small>DocumentRoot: %s</small>"
+ site_unparsable_template = "<b><big>%s</big></b>\n<small><i>Further information not available</i></small>"
+
+ lstore = self._reset_model()
+
+ data = []
+ dirList=os.listdir( Configuration.SITES_AVAILABLE_DIR )
+ dirList = [x for x in dirList if self._blacklisted( x ) == False ]
+ for fname in dirList :
+ site = VirtualHostModel( fname )
+ try:
+ site.load()
+ except "VhostUnparsable":
+ pass
+ self.items[ fname ] = site
+ site = None
+
+ for idx in sorted( self.items ):
+ site = self.items[ idx ]
+ if ( site.parsable ):
+ markup = site_template \
+ % ( site.data['name'] , site.data[ 'DocumentRoot' ] )
+ else:
+ markup = site_unparsable_template % site.data['name']
+ iter = lstore.append()
+ lstore.set(iter,
+ COLUMN_FIXED, site.data['enabled'],
+ COLUMN_SEVERITY, site.data['name'],
+ COLUMN_MARKUP, markup )
+
+ #TODO: warning ! This function get's called even on mousehover
+ # check for a way to optimize it
+ def __get_row_icon (self, column, cell, model, iter):
+ """ Provides the icon for a virtual host looking up it's favicon"""
+ """node = model.get_value(iter, MODEL_FIELD_NODE)
+ pixbuf = getPixbufForNode(node)
+ cell.set_property('pixbuf', pixbuf)"""
+ favicon = os.path.join( Configuration.GLADEPATH, 'browser.png' )
+ fname = model.get_value(iter, COLUMN_SEVERITY )
+ site = self.items[ fname ]
+ if site.data['DocumentRoot'] != None:
+ custom_favicon = os.path.join(os.path.dirname( site.data['DocumentRoot']+"/" ), "favicon.ico")
+ if ( os.path.exists( custom_favicon ) ): favicon = custom_favicon
+
+ pixbuf = gtk.gdk.pixbuf_new_from_file( favicon )
+ cell.set_property("pixbuf", pixbuf)
+
+ def __fixed_toggled(self, cell, path, treeview):
+ # get toggled iter
+ model = treeview.get_model()
+ iter = model.get_iter((int(path),))
+ fixed = model.get_value(iter, COLUMN_FIXED)
+ name = model.get_value(iter, COLUMN_SEVERITY)
+
+ fixed = not fixed
+ if fixed:
+ Shell.command.sudo_execute ( [Configuration.APPPATH+'/hosts-manager', '-a',name])
+ else :
+ Shell.command.sudo_execute ( [Configuration.APPPATH+'/hosts-manager', '-r',name])
+ # set new value
+ site = VirtualHostModel( name )
+ site.toggle( fixed )
+ model.set(iter, COLUMN_FIXED, site.data['enabled'] )
+ if ( site.changed ):
+ self.raise_event( 'please_restart_apache' )
+gobject.type_register (VhostsTreeView)
+
+class DenormalizedVhostsTreeView ( ConfFilesTreeView ):
+ def __init__ (self, *args, **kwargs):
+ super (DenormalizedVhostsTreeView, self).__init__ (*args, **kwargs)
+ print self.column_checkbox, self.column_description, self.column_icon
+ self.column_checkbox.set_visible( False )
+ self.column_icon.get_cell_renderers()[0].set_property( 'stock-id', gtk.STOCK_DIALOG_WARNING )
+ def load(self):
+ self.items = {}
+ site_template = "<b><big>%s</big></b>"
+ lstore = self._reset_model()
+
+ data = []
+ dirList=os.listdir( Configuration.SITES_ENABLED_DIR )
+ dirList = [x for x in dirList if self._blacklisted( x ) == False ]
+ dirList = [x for x in dirList if is_denormalized_vhost( x ) == False ]
+ for fname in dirList :
+ site = VirtualHostModel( fname )
+ self.items[ fname ] = site
+ site = None
+
+ for idx in sorted( self.items ):
+ site = self.items[ idx ]
+ normalizable = not is_not_normalizable(site.data['name'])
+ markup = site_template % site.data['name']
+ if ( normalizable == False ):
+ markup = markup + " CANNOT FIX"
+ iter = lstore.append()
+ lstore.set(iter,
+ COLUMN_FIXED, normalizable,
+ COLUMN_SEVERITY, site.data['name'],
+ COLUMN_MARKUP, markup
+ )
+ def toggled_callback(self, *args, **kwargs):
+ pass
+gobject.type_register (DenormalizedVhostsTreeView )
+
+class ModulesTreeView ( ConfFilesTreeView ):
+ def __init__ (self, *args, **kwargs):
+ super (ModulesTreeView, self).__init__ (*args, **kwargs)
+
+ icon_file_name = os.path.join( Configuration.GLADEPATH , "modules.png")
+ pixbuf = gtk.gdk.pixbuf_new_from_file( icon_file_name )
+
+ self.column_icon.get_cell_renderers()[0].set_property('pixbuf', pixbuf)
+ self.toggled_callback = self.__fixed_toggled
+ self.selected_callback = self.__selected
+ self.column_description.get_cell_renderers()[0].set_property('wrap-mode', gtk.WRAP_WORD)
+ self.column_description.get_cell_renderers()[0].set_property('wrap-width', 400)
+ def __selected(self, *args, **kwargs ):
+ print "MODULE NAME:", self.get_selected_line()
+ print "DEPENDANTS: ", Module.get_module_dependants(self.get_selected_line(), self.items)
+ def load(self):
+ self.items = {}
+ mod_template = "<b><big>%s</big></b>"
+ mod_unparsable_template = "<b><big>%s</big></b>\n<small><i>Further information not available</i></small>"
+ lstore = self._reset_model()
+ data = []
+
+ """dirList=os.listdir( Configuration.MODS_AVAILABLE_DIR )
+ dirList = [x for x in dirList if self._blacklisted( x ) == False ]
+ for fname in dirList :
+ mod = Module.ModuleModel( fname )
+ try:
+ mod.load()
+ except "VhostUnparsable":
+ pass
+ self.items[ fname ] = mod
+ mod = None
+ """
+ self.items = Module.module_list()
+
+ for idx in sorted( self.items ):
+ mod = self.items[ idx ]
+ if ( mod.parsable ):
+ markup = mod_template \
+ % ( mod.data['name'] ) #, mod.data[ 'DocumentRoot' ] )
+ markup += "\n<small>%s</small>" % mod.data[ 'description' ]
+ if len( mod.data[ 'dependancies' ] ) > 0:
+ markup += "\n<small><b>%s</b></small>" % ( "Dependencies: " + \
+ ", ".join( mod.data[ 'dependancies' ] ) )
+ else:
+ markup += "\n<small><i>No dependencies</i></small>"
+ else:
+ markup = mod_unparsable_template % mod.data['name']
+ iter = lstore.append()
+ lstore.set(iter,
+ COLUMN_FIXED, mod.data['enabled'],
+ COLUMN_SEVERITY, mod.data['name'],
+ COLUMN_MARKUP, markup )
+
+ def __fixed_toggled(self, cell, path, treeview):
+ # get toggled iter
+ model = treeview.get_model()
+ iter = model.get_iter((int(path),))
+ fixed = model.get_value(iter, COLUMN_FIXED)
+ name = model.get_value(iter, COLUMN_SEVERITY)
+ fixed = not fixed
+ # set new value
+ mod = Module.ModuleModel( name )
+ mod.toggle( fixed )
+ model.set(iter, COLUMN_FIXED, mod.data['enabled'] )
+ if ( mod.changed ):
+ self.raise_event( 'please_restart_apache' )
+ self.raise_event( 'please_reload_lists', {}, True )
+ #TODO: warning ! This function get's called even on mousehover
+ # check for a way to optimize it
+ def __get_row_icon (self, column, cell, model, iter):
+ """ Provides the icon for a module"""
+ """node = model.get_value(iter, MODEL_FIELD_NODE)
+ pixbuf = getPixbufForNode(node)
+ cell.set_property('pixbuf', pixbuf)"""
+ favicon = os.path.join( Configuration.GLADEPATH, 'browser.png' )
+ fname = model.get_value(iter, COLUMN_SEVERITY )
+ site = self.items[ fname ]
+ if site.data['DocumentRoot'] != None:
+ custom_favicon = os.path.join(os.path.dirname( site.data['DocumentRoot']+"/" ), "favicon.ico")
+ if ( os.path.exists( custom_favicon ) ): favicon = custom_favicon
+
+ pixbuf = gtk.gdk.pixbuf_new_from_file( favicon )
+ cell.set_property("pixbuf", pixbuf)
+gobject.type_register ( ModulesTreeView )
=== added file 'RapacheGtk/VirtualHostGui.py'
--- RapacheGtk/VirtualHostGui.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/VirtualHostGui.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,295 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+""".
+Issues with the new window:
+ - self.parent doesn't work
+ - onblur doesn't trigger when pressing Return
+ - changing a domain name doesn't change subdomains
+ - empty server aliases shuoldn't be managed
+ALSO:
+ - please implement a delete directive func in the parser
+ - move denorm. vhosts in another tab
+ - merge with Qense warning window
+"""
+
+import sys
+import re
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+import os
+import pango
+import tempfile
+import traceback
+import RapacheGtk.GuiUtils
+from RapacheCore.VirtualHost import *
+from RapacheGtk import GuiUtils
+from EditDomainNameGui import EditDomainNameWindow
+
+class VirtualHostWindow:
+
+ def __init__ ( self, parent = None):
+
+ self.vhost = None
+ self.create_new = True
+ self.parent = parent
+ self.plugins = []
+
+ gladefile = os.path.join(Configuration.GLADEPATH, "edit_vhost.glade")
+ wtree = gtk.glade.XML(gladefile)
+
+ self.window = wtree.get_widget("dialog_edit_vhost")
+ self.entry_domain = wtree.get_widget("entry_domain")
+ self.entry_location = wtree.get_widget("entry_location")
+ self.button_location = wtree.get_widget("button_location")
+ self.treeview_domain = wtree.get_widget("treeview_domain")
+ self.checkbutton_hosts = wtree.get_widget("checkbutton_hosts")
+ self.toolbutton_domain_add = wtree.get_widget("toolbutton_domain_add")
+ self.toolbutton_domain_edit = wtree.get_widget("toolbutton_domain_edit")
+ self.toolbutton_domain_delete = wtree.get_widget("toolbutton_domain_delete")
+ self.notebook = wtree.get_widget("notebook")
+ self.button_save = wtree.get_widget("button_save")
+ self.error_area = wtree.get_widget("error_area")
+ signals = {
+ "on_toolbutton_domain_add_clicked" : self.on_toolbutton_domain_add_clicked,
+ "on_toolbutton_domain_edit_clicked" : self.on_toolbutton_domain_edit_clicked,
+ "on_toolbutton_domain_delete_clicked" : self.on_toolbutton_domain_delete_clicked,
+ "on_button_save_clicked" : self.on_button_save_clicked,
+ "on_button_cancel_clicked" : self.on_button_cancel_clicked,
+ "on_entry_domain_changed" : self.on_entry_domain_changed,
+ "on_button_location_clicked" : self.on_button_location_clicked,
+ "on_entry_domain_focus_out_event" : self.on_entry_domain_focus_out_event,
+ "on_button_location_clear_clicked" : self.on_button_location_clear_clicked
+ }
+ wtree.signal_autoconnect(signals)
+
+ self.text_view_vhost_source = GuiUtils.new_apache_sourceview()
+ wtree.get_widget( 'text_view_vhost_source_area' ).add( self.text_view_vhost_source )
+ self.text_view_vhost_source.set_editable( False )
+ self.text_view_vhost_source.show()
+
+ self.notebook.get_nth_page( 1 ).hide()
+ self.notebook.get_nth_page( 2 ).hide()
+
+ # add on destroy to quit loop
+ self.window.connect("destroy", self.on_destroy)
+
+ # Setup tree
+ column = gtk.TreeViewColumn(('Domains'))
+ column.set_spacing(4)
+ cell = gtk.CellRendererText()
+ column.pack_start(cell, True)
+ column.set_attributes(cell, markup=0)
+ self.treeview_domain.append_column(column)
+
+ self.treeview_domain_store = gtk.ListStore(str, object)
+ self.treeview_domain.set_model(self.treeview_domain_store)
+
+ GuiUtils.style_as_tooltip( self.error_area )
+ self.on_entry_domain_changed()
+
+ def run(self):
+
+ # Load UI Plugins
+ if self.vhost:
+ site = self.vhost
+ else:
+ # load default
+ site = VirtualHostModel( "", self.parent.plugin_manager)
+
+ for plugin in self.parent.plugin_manager.plugins:
+ try:
+ if plugin.is_enabled():
+ plugin.load_vhost_properties(self.notebook, site.data)
+ self.plugins.append(plugin)
+ except Exception:
+ traceback.print_exc(file=sys.stdout)
+
+ self.window.show()
+ gtk.main()
+
+ def load (self, name ):
+ self.vhost = VirtualHostModel( name )
+ self.create_new = False
+ try:
+ self.vhost.load(False, self.parent.plugin_manager)
+ print self.vhost.data
+ #self._get( 'has_www' ).set_active( site.data[ 'has_www' ] )
+ server_name = self.vhost.data[ 'ServerName' ]
+ if ( server_name != None ):
+ self.entry_domain.set_text( server_name )
+ document_root = self.vhost.data[ 'DocumentRoot' ]
+ if ( document_root != None ):
+ self.entry_location.set_text( document_root )
+ server_alias = self.vhost.data[ 'ServerAlias' ]
+ if ( server_alias != None ):
+ for domain in server_alias:
+ self.treeview_domain_store.append((domain, None))
+ print self.vhost.data
+ except "VhostUnparsable":
+ pass
+
+ buf = self.text_view_vhost_source.get_buffer()
+ buf.set_text( self.vhost.get_source() )
+
+
+
+ def get_domain (self):
+ return self.entry_domain.get_text().strip()
+ #url.lower().startswith('http://')
+ #url[7:]
+ def set_default_values_from_domain(self, force_domain=False):
+ domain = self.get_domain()
+
+ # auto set the location
+ if domain and (not self.entry_location.get_text() or force_domain):
+ self.entry_location.set_text( "/srv/www/%s" % (domain +"/httpdocs" ))
+ if force_domain and not domain:
+ self.entry_location.set_text("")
+
+ # auto create a www entry
+ #if not force_domain and domain and len(self.treeview_domain_store) == 0 and not domain.startswith("www"):
+ # self.treeview_domain_store.append(("www." + domain, None))
+
+ def on_entry_domain_focus_out_event(self, widget, opt):
+ self.set_default_values_from_domain()
+
+ def on_entry_domain_changed(self, unused_widget = None):
+ widget = self.entry_domain
+ name = widget.get_text()
+ if ( valid_domain_name( name ) ):
+ self.button_save.set_sensitive(True);
+ #if self.create_new :
+ # self.xml.get_widget( 'default_folder' ).set_text( '/srv/www/'+name+'/httpdocs' )
+ else:
+ self.button_save.set_sensitive(False);
+
+ def on_button_location_clear_clicked(self, widget):
+ self.set_default_values_from_domain(True)
+
+
+ def on_button_location_clicked(self, widget):
+ chooser = gtk.FileChooserDialog(
+ title=None,
+ action=gtk.FILE_CHOOSER_ACTION_CREATE_FOLDER,
+ buttons=(gtk.STOCK_CANCEL,
+ gtk.RESPONSE_CANCEL,
+ gtk.STOCK_OPEN,
+ gtk.RESPONSE_OK))
+
+ location = self.entry_location.get_text().strip()
+ if not location:
+ location = "/srv/www"
+ chooser.set_current_folder(location)
+ response = chooser.run()
+
+ if response == gtk.RESPONSE_OK:
+ self.entry_location.set_text( chooser.get_filename() )
+ chooser.destroy()
+
+ def on_destroy(self, widget, data=None):
+ gtk.main_quit()
+
+ def on_toolbutton_domain_add_clicked(self, widget):
+ edw = EditDomainNameWindow(self.entry_domain.get_text().strip())
+ domain = edw.run()
+ if domain:
+ self.treeview_domain_store.append((domain, None))
+ return
+ def get_server_aliases_list (self ):
+ aliases = []
+ for row in self.treeview_domain_store: aliases.append( row[0] )
+ return aliases
+ def on_toolbutton_domain_edit_clicked(self, widget):
+
+ model, iter = self.treeview_domain.get_selection().get_selected()
+ if not iter: return
+ domain = model.get_value(iter, 0)
+ print domain
+ edw = EditDomainNameWindow( domain )
+ result = edw.run()
+ if result:
+ self.treeview_domain_store.set_value(iter, 0, edw.return_value)
+ return
+
+ def on_toolbutton_domain_delete_clicked(self, widget):
+ model, iter = self.treeview_domain.get_selection().get_selected()
+ if not iter: return
+ self.treeview_domain_store.remove(iter)
+ return
+
+ def on_button_save_clicked(self, widget):
+ if self.entry_location.get_text() == "" and self.create_new:
+ self.set_default_values_from_domain( True )
+
+ options = {}
+ options[ 'ServerAlias' ] = []
+ options[ 'ServerName' ] = self.entry_domain.get_text()
+ options[ 'hack_hosts' ] = self.checkbutton_hosts.get_active()
+ options[ 'DocumentRoot' ] = self.entry_location.get_text()
+ options[ 'ServerAlias' ] = self.get_server_aliases_list()
+
+ # Save plugins
+ if self.plugins:
+ for plugin in self.plugins:
+ try:
+ if plugin.is_enabled():
+ plugin.save_vhost_properties(options)
+ except Exception:
+ traceback.print_exc(file=sys.stdout)
+
+ print options
+
+ try:
+ if ( self.create_new ):
+ site = VirtualHostModel( options[ 'ServerName' ] )
+ site.create ( options )
+ else:
+ name = self.vhost.data['name']
+ print "Current name:", name
+ site = VirtualHostModel( name )
+ site.update( options, name )
+
+
+ #self.parent.create_vhost_list()
+ self.parent.refresh_vhosts()
+ self.parent.please_restart()
+ self.window.destroy()
+ except "VhostExists":
+ print "========================"
+ self.show_error( "A virtual host with the same name already exists" )
+
+
+ def on_button_cancel_clicked(self, widget):
+ self.window.destroy()
+ return
+ def show_error ( self, message ):
+
+ self.xml.get_widget( 'message_text' ).set_label( '<b>'+message+'</b>' )
+ self.xml.get_widget( 'message_container' ).show()
+
=== added file 'RapacheGtk/WarningWindow.py'
--- RapacheGtk/WarningWindow.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/WarningWindow.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+import os
+import gnome.ui
+
+from RapacheGtk import GuiUtils
+from RapacheCore import Configuration
+
+class WarningWindow:
+ """The Rapache warning window"""
+
+ def __init__(self, warning, father = None):
+ self.father = father
+ self.gladefile = Configuration.GLADEPATH + "/" + "warning_dialog.glade"
+ print self.gladefile
+ self.xml = gtk.glade.XML(self.gladefile)
+ #Create our dictionary and connect it
+ dic = {
+ "quit" : gtk.main_quit
+ , "on_ok" : gtk.main_quit
+ }
+ self.xml.signal_autoconnect(dic)
+ self.xml.get_widget( 'label1' ).set_label ( warning )
+
+
=== added file 'RapacheGtk/__init__.py'
=== added file 'RapacheGtk/old_VirtualHostGui.py'
--- RapacheGtk/old_VirtualHostGui.py 1970-01-01 00:00:00 +0000
+++ RapacheGtk/old_VirtualHostGui.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import re
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+import os
+import pango
+import tempfile
+
+from RapacheCore.VirtualHost import *
+from RapacheGtk import GuiUtils
+
+class VirtualHostWindow:
+
+ create_new = True
+ name = None
+
+ def __init__ ( self, father = None):
+ self.father = father
+ self.gladefile = Configuration.GLADEPATH + "/" + "edit_vhost.glade"
+ self.xml = gtk.glade.XML(self.gladefile)
+ #Create our dictionary and connect it
+ dic = {
+ "quit" : self.quit
+ , "on_ok":self.save
+ , "on_cancel":self.close
+ , "domain_name_updated":self.domain_name_updated
+ , "custom_folder_toggled":self.custom_folder_toggled
+ }
+ self.xml.signal_autoconnect(dic)
+ self.xml.get_widget( 'custom_folder' ).set_action ( gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER )
+ font_desc = pango.FontDescription('monospace')
+ self.xml.get_widget( 'vhost_source' ).modify_font(font_desc)
+ GuiUtils.style_as_tooltip( self.xml.get_widget( 'message_container' ) )
+
+ def load (self, name ):
+
+ site = VirtualHostModel( name )
+ self.create_new = False
+ self.name = name
+ self._get( 'create_hosts_entry' ).hide()
+ self._get( 'create_hosts_label' ).hide()
+ try:
+ site.load()
+ self._get( 'has_www' ).set_active( site.data[ 'has_www' ] )
+ self._get( 'domain_name' ).set_text( site.data[ 'ServerName' ] )
+ self._get( 'default_folder' ).set_text( site.data[ 'DocumentRoot' ] )
+ self.xml.get_widget( 'ok_button' ).set_sensitive(True);
+ except "VhostUnparsable":
+ self._get( 'notebook' ).get_nth_page( 0 ).hide()
+ buffer = self.xml.get_widget( 'vhost_source' ).get_buffer()
+ buffer.set_text( site.get_source() )
+ def _get(self, id ):
+ return self.xml.get_widget( id )
+
+
+ def error ( self, message ):
+ self.xml.get_widget( 'message_text' ).set_label( '<b>'+message+'</b>' )
+ self.xml.get_widget( 'message_container' ).show()
+
+ def quit (self, widget):
+ self.father.new_vhost_window = None
+
+ def close ( self, widget = None ):
+ self.window = self.xml.get_widget( 'vhost_edit_window' )
+ self.window.destroy()
+ def domain_name_updated ( self, widget, a = None, b = None, c = None ):
+ name = widget.get_text()
+ if ( valid_domain_name( name ) ):
+ self.xml.get_widget( 'ok_button' ).set_sensitive(True);
+ if self.create_new :
+ self.xml.get_widget( 'default_folder' ).set_text( '/var/www/'+name+'/httpdocs' )
+ else:
+ self.xml.get_widget( 'ok_button' ).set_sensitive(False);
+ def custom_folder_toggled( self, widget ):
+ if ( widget.get_active() == True ):
+ self.xml.get_widget( 'custom_folder' ).show()
+ self.xml.get_widget( 'default_folder' ).hide()
+ else:
+ self.xml.get_widget( 'custom_folder' ).hide()
+ self.xml.get_widget( 'default_folder' ).show()
+
+
+ def save( self, widget ):
+ options = {}
+ options[ 'has_www' ] = self.xml.get_widget( 'has_www' ).get_active()
+ options[ 'domain_name' ] = ( self.xml.get_widget( 'domain_name' ).get_text() )
+ options[ 'hack_hosts' ] = self.xml.get_widget( 'create_hosts_entry' ).get_active()
+ if self.xml.get_widget( 'set_custom_folder' ).get_active():
+ DocumentRoot = self.xml.get_widget( 'custom_folder' ).get_filename ()
+ else:
+ DocumentRoot = self.xml.get_widget( 'default_folder' ).get_text()
+ options[ 'DocumentRoot' ] = DocumentRoot
+
+
+ try:
+ if ( self.create_new ):
+ site = VirtualHostModel( options[ 'domain_name' ] )
+ site.create ( options )
+ else:
+ print "Current name:", self.name
+ site = VirtualHostModel( self.name )
+ site.update( options, self.name )
+
+ self.father.refresh_vhosts()
+ self.father.please_restart()
+ self.close()
+ except "VhostExists":
+ print "========================"
+ self.error( "A virtual host with the same name already exists" )
+
+
+ return True
=== added file '__init__.py'
=== renamed file '__init__.py' => '__init__.py.moved'
=== added directory 'build'
=== added directory 'build/lib.linux-x86_64-2.6'
=== added directory 'build/lib.linux-x86_64-2.6/RapacheCore'
=== added file 'build/lib.linux-x86_64-2.6/RapacheCore/ApacheConf.py'
--- build/lib.linux-x86_64-2.6/RapacheCore/ApacheConf.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheCore/ApacheConf.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,344 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+ASSUMPTIONS
+ - when multiple directive with the same name are encountered
+ the last one wins.
+ - directives without options could be ok.
+ - ServerAlias without any option works
+
+GOALS:
+ - change as little as possible when updating to reduce the risk
+ of breaking something
+
+TODO:
+ - search for subsections and limit editing to a certain subsection
+ - insert directive where it doesn't exist
+ - remove a directive when it becomes empty (without options)
+ - verify apache handling of case for directives
+"""
+
+import re
+from RapacheCore.Observer import PollyObserver
+from RapacheCore.Observer import Observable
+
+class Parser (Observable):
+ filename = None
+ content = None
+ parser = None
+
+ def __init__ (self, *args, **kwargs):
+ super (Parser, self).__init__ (*args, **kwargs)
+ self.parser = LineParser()
+ self.apply_observing_policy()
+
+ def apply_observing_policy(self):
+ """register the object with the observer"""
+ self.observer = PollyObserver()
+ self.observer.register(self)
+
+ def load(self, filename ):
+ self.filename = filename
+ file = open ( filename, 'r' )
+ self.content = file.readlines()
+ file.close()
+ return self.content
+
+ def get_value(self, name):
+ line = self.get_directive(name)
+ if line == None: return None
+ return self.parser.get_value(line)
+ def set_value (self, name, value):
+ idx = self._get_last_directive_idx(name)
+ if idx == None:
+ idx = self._last_line_idx()
+ line = name+"\t"+self.parser.value_escape( value )+"\n"
+ self.insert_line( self._last_line_idx(), line )
+ else:
+ line = self.get_line( idx )
+ line = self.parser.change_value(line, value)
+ self.set_line( idx, line )
+ def remove_value(self, name):
+ idx = self._get_last_directive_idx(name)
+ print "removing line:",idx
+ if idx:
+ self.remove_line(idx)
+ return True
+ return False
+ def get_directive(self, name):
+ idx = self._get_last_directive_idx(name)
+ if ( idx == None ): return None
+ line = self.get_line( idx )
+ return line
+ """
+ def set_directive (self, name, line):
+ idx = self._get_last_directive_idx(name)
+ self.set_line( idx, line )
+ """
+ # idx starts from 0 !! it's not a line number
+ def _get_last_directive_idx (self, name ):
+ last_found = None
+ for key, line in enumerate(self.get_content() ):
+ if ( self.parser.get_directive(line) == name ): last_found = key
+ return last_found
+ #TODO create if doesn't exist.
+ def set_directive (self, name, line):
+ idx = self._get_last_directive_idx(name)
+ if ( idx == None ):
+ return self.insert_line( self._last_line_idx() , line.rstrip()+"\n")
+ self.set_line( idx, line.rstrip()+"\n" )
+
+ def _last_line_idx (self):
+ return 999999
+
+ def has_option (self, name, option ):
+ line = self.get_directive(name)
+ if ( line == False or line == None ): return False
+ return self.parser.has_option(line, option)
+ def get_options (self, name):
+ value = self.get_value(name)
+ if value == None: return []
+ options = self.parser.parse_options( value )
+ print options
+ return options
+ def add_option (self, name, option ):
+ line = self.get_directive(name)
+ if ( line == False or line == None ):
+ line = name
+ line = name+"\t"+self.parser.value_escape( option )+"\n"
+ self.insert_line( self._last_line_idx(), line )
+ return
+ line = self.parser.add_option(line, option)
+ self.set_directive(name, line)
+ def remove_option (self, name, option ):
+ #we need idx later if we decide to remove the whole line
+ idx = self._get_last_directive_idx(name)
+ line = self.get_directive(name)
+ if ( line == False or line == None ): return False
+ line = self.parser.remove_option(line, option)
+ new_value = self.parser.get_value( line )
+ if ( new_value.strip() == "" ):
+ self.remove_line( idx )
+ else:
+ self.set_directive(name, line)
+ def get_source (self):
+ return "".join( self.get_content() )
+ def get_content(self):
+ return self.content
+ def set_content_from_string(self, string):
+ self.content = string.split( "\n" )
+ def get_line(self, idx):
+ return self.get_content()[idx]
+ def set_line(self, idx, line):
+ self.content[ idx ] = line
+ def insert_line (self, idx, line):
+ """Inserts a line at the given idx"""
+ if idx >= len( self.content ): #out of range
+ idx = self._last_line_idx()
+ self.content.insert( idx, line )
+ self.raise_event( 'row_inserted', {'idx':idx, 'line':line } )
+ def remove_line(self, idx ):
+ del self.content[ idx ]
+ self.raise_event( 'row_removed', {'idx':idx } )
+class PieceParser ( Parser ):
+ """Manipulates isolated parts of configuration files. Should be extended"""
+
+ min = None
+ max = None
+ father = None
+ def apply_observing_policy(self):
+ """register the object with the observer"""
+ self.father.observer.register(self)
+ def load (self, args = {}):
+ print "Please override this method !"
+ exit()
+ def __init__(self, father, args = {} ):
+ self.father = father
+ Parser.__init__( self )
+ self.load( args )
+ def load (self, args = {} ):
+ pass
+ def get_content (self):
+ return self.father.get_content()[ self.min : self.max ]
+
+class VhostParser( PieceParser ):
+ """Searches for the first vhost inside the conf and allows isolated
+ manipulation of it"""
+
+ def load(self, args = {}):
+ content = self.father.get_content()
+ self.min = self._find_min(content)
+ if self.min == None: raise "VhostNotFound", "Beginning not found"
+ self.max = self._find_max(content, self.min) +1
+ if ( self.max == None ): raise "VhostNotFound", "End not found"
+
+ def _last_line_idx (self):
+ return -1
+ def _find_min( self, content ):
+ for idx, line in enumerate( content ):
+ basic_regexp = r'^\s*<s*(VirtualHost)(\s+[^>]*)*>.*'
+ result = re.match( basic_regexp, line, re.IGNORECASE )
+ if ( result != None and result != False ): return idx
+ return None
+ def _find_max( self, content, min ):
+ for idx, line in enumerate( content ):
+ if ( idx > min ):
+ basic_regexp = r'^\s*<s*(/VirtualHost)\s*>.*'
+ result = re.match( basic_regexp, line, re.IGNORECASE )
+ if ( result != None and result != False ): return idx
+ return None
+ def set_line (self, idx, line ):
+ if idx >= 0: idx = idx + self.min
+ return self.father.set_line( idx, line )
+ def insert_line (self, idx, line ):
+ print "===========> INSERTING"
+ if idx >= 0: idx = idx + self.min
+ line = "\t"+line.lstrip() #ident
+ return self.father.insert_line( idx, line )
+ def remove_line(self, idx ):
+ if idx >= 0: idx = idx + self.min
+ return self.father.remove_line( idx )
+ def handle_event(self, event):
+ print self, "handling:", event.name, "raised by", event.caller
+ if ( event.name == 'row_inserted' ):
+ self.max = self.max + 1
+ if ( event.name == 'row_removed' ):
+ self.max = self.max -1
+
+class LineParser:
+ """Utility class. Contains methods to parse and manipulate apache conf
+ directives"""
+ def tokenize (self, line ):
+ basic_regexp = '^(\s*)([A-Z0-9]+)(\s+)(.*)'
+ result = re.match( basic_regexp, line, re.IGNORECASE )
+ if ( result == None ): return False
+ return list( result.groups() )
+ def value_unescape(self, value):
+ #value should have no precedig or trailing spaces
+ if value == "" : return value
+ char = value[0]
+ if char == '"' or char == "'":
+ if char != value[-1]:
+ raise( 'BadQuoting', 'Bad quoting' )
+ return value;
+ value = value[1:-1]
+ value = value.replace( '\\'+char, char )
+
+ #we don't need to unescape spaces as apparently
+ #apache parser doesn't handle escaped spaces
+ #inside non-quote-enclosed strings
+ return value
+
+ #parse a value into a list of multiple options
+ # - handles double quote-enclosed strings "example"
+ #TODO: doesn't hanlde single quotes at all :(
+ def parse_options ( self, s ):
+ """parse a value into a list of multiple options"""
+ s = s.rstrip()
+ s = s.replace ( '\"', '"' )
+ result = '';
+ tokens = s.split( '"' )
+ for k, v in enumerate( tokens ):
+ # replace spaces in every odd token
+ if ( k & 1 ) == 1 : tokens[k] = v.replace( ' ', ' ' )
+
+ s = '"'.join( tokens )
+ s = s.replace( '"', '' )
+ tokens = s.split( ' ' )
+ for k, v in enumerate( tokens ):
+ tokens[ k ] = v.replace( ' ', ' ' )
+ tokens[ k ] = tokens[ k ].replace( '"', '"' )
+ tokens = [x for x in tokens if x.strip() != '' ]
+ return tokens;
+
+ def remove_option ( self, line, option ):
+ options = self.get_value( line );
+ options = self.parse_options( options);
+ for k,o in enumerate( options ):
+ if ( option == o ): del options[ k ]
+
+ return self.change_value( line, " ".join( options ) )
+ def has_option (self, line, option):
+ options = self.parse_options( line )
+ for o in options:
+ if o == option : return True
+ return False
+
+ def add_option ( self, line, option ):
+ options = self.get_value( line );
+ if options == False : options = ""
+ options = self.parse_options( options);
+ found = False;
+ for k,o in enumerate( options ):
+ if ( option == o ): found = True;
+ if ( found == False ): options.append( self.value_escape( option ) )
+ return self.change_raw_value( line, " ".join( options ))
+
+ def value_escape ( self, value ):
+ if ( value.find(' ') != -1 ):
+ value = '"'+value.replace( '"', '\\"' )+'"'
+ return value;
+
+ def get_value ( self, line ):
+ tokens = self.tokenize( line )
+ if ( tokens == False ): return False;
+ value = tokens.pop()
+ value = value.strip()
+ value = self.value_unescape( value )
+
+ return value
+
+ def get_directive ( self, line ):
+ tokens = self.tokenize( line );
+ if ( tokens == False ): return False
+ return tokens[ 1 ]
+
+ def change_value( self, line , new_value ):
+ new_value = self.value_escape( new_value )
+ return self.change_raw_value( line, new_value )
+
+ def change_raw_value ( self, line , new_value ):
+ tokens = self.tokenize( line )
+ tokens[2] = tokens[2].replace( "\n", '' ) #separator shuoldn't contain newlines
+ if tokens[2] == '': tokens[2] = ' ' #at least as space as separator
+ line = tokens[0]+tokens[1]+tokens[2]+new_value
+ line = line.rstrip() + "\n"
+ return line
+
+
+if __name__ == "__main__":
+
+ parser = Parser()
+ parser.load( '/etc/apache2/sites-available/figa' )
+ parser.set_value('DocumentRoot', '/var/www/xxxx/yyyy' )
+
+ piece = VhostParser( parser )
+
+ print piece.get_value('DocumentRoot' )
+ print piece.get_value('ServerName' )
+ piece.set_directive( 'fatwife' , 'fatwife 1')
+
+ #piece.remove_option( 'ServerAlias', 'www.figa' )
+ piece.add_option( 'ServerAlias', 'ftp.figa' )
+
+
+ print "====="
+ print piece.get_source()
+ print "====="
+
=== added file 'build/lib.linux-x86_64-2.6/RapacheCore/Configuration.py'
--- build/lib.linux-x86_64-2.6/RapacheCore/Configuration.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheCore/Configuration.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+SYSCONFDIR = '/etc/apache2'
+SITES_ENABLED_DIR = SYSCONFDIR + '/sites-enabled'
+SITES_AVAILABLE_DIR = SYSCONFDIR + '/sites-available'
+MODS_ENABLED_DIR = SYSCONFDIR + '/mods-enabled'
+MODS_AVAILABLE_DIR = SYSCONFDIR + '/mods-available'
+APPPATH = '/usr/bin' #please fill at run-time
+GLADEPATH = '/usr/local/share/rapache/Glade' #please fill at run-time
+
=== added file 'build/lib.linux-x86_64-2.6/RapacheCore/HostsManager.py'
--- build/lib.linux-x86_64-2.6/RapacheCore/HostsManager.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheCore/HostsManager.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,299 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import getopt, sys
+import os
+import re
+import subprocess
+"""
+Things to remember:
+ - if 2 equal domain names are found in /etc/hosts the first wins
+"""
+
+# Flow:
+# ------------
+# hosts-manager -a example.loc 10.0.0.1
+#
+# example.loc exists ?
+# No. Add it at the end of file
+# Yes
+# is ip the same ?
+# yes. Skipping.
+# no.
+# remove domain name from the line it first appears in
+# if the line contained only one domain, remove the line altogheter
+# add a new line just below $IP $DOMAIN_NAME
+
+
+#IPv4 REGEXP: \d{1,3}\.\d{1,3}\.\d{1,3}'
+#IPv4 (2): \b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b
+#SOSTITUZIONE: re.sub( r'(\s)(www.mu.loc)(\s|$)', r'\3\1xxx\3', subject )
+#CAMBIO IP:
+
+
+#TODO: regexp the crap out of IP's (v4 and v6)
+#TODO: strip in-line comments 127.0.0.1 domain.localhost #strip-this.com
+
+class HostsManager:
+ SUDO = "sudo"
+ HOSTS = "/etc/hosts"
+ REGEXP_IPV4 = '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}'
+ opts = None
+ def __init__( self, console = False ):
+ if ( console ):
+
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "ho:v:ar", ["help", "output="])
+ self.opts = opts
+ self.args = args
+ except getopt.GetoptError, err:
+ # print help information and exit:
+ print str(err) # will print something like "option -a not recognized"
+ self.usage()
+ sys.exit(2)
+ output = None
+ verbose = False
+ if len(opts) == 0:
+ self.usage()
+ exit()
+ for o, a in opts:
+ if o == "-v":
+ verbose = True
+ elif o == "-a":
+ if ( len( args ) == 0 ):
+ self.usage()
+ sys.exit()
+ self.create( *args )
+ elif o == "-r":
+ if ( len( args ) == 0 ):
+ self.usage()
+ sys.exit()
+ self.remove( *args )
+ elif o in ("-h", "--help"):
+ self.usage()
+ sys.exit()
+ elif o in ("-o", "--output"):
+ output = a
+ print args
+ else:
+ assert False, "unhandled option"
+ def strip_domain ( self, line, domain_name ):
+ domain_regexp = domain_name.replace( '.', '\\.' ) #quote for regexp
+ regexp_just_1_domain = r'^\s*('+self.REGEXP_IPV4+')(\s*)('+domain_regexp+')(\s|$)'
+ if( re.search( regexp_just_1_domain , line, re.IGNORECASE ) ):
+ return False
+ tokens = re.split( r'(\s*)', line )
+ new_tokens = []
+ changed = False
+ for word in tokens:
+ if ( word.strip().lower() != domain_name.strip().lower() ):
+ if ( changed == True and new_tokens[-1] == ' ' and word == ' ' ):
+ """ nothing """
+ else:
+ new_tokens.append( word )
+ changed = False
+ else:
+ changed = True
+ line = "".join( new_tokens )
+ return line
+ def _security_check ( self, domain_name, ip ):
+ if ( re.search( '^localhost$', domain_name, re.IGNORECASE )!=None ):
+ print "hosts-manager won't operate localhost. So sorry"
+ return False
+ p = subprocess.Popen("hostname", stdout=subprocess.PIPE)
+ hostname = p.communicate()[0]
+ hostname = hostname.replace( "\n", "" )
+ if ( re.search( '^'+hostname+'$', domain_name, re.IGNORECASE )!=None ):
+ print "The domain name you gave corresponds to local computer's host name. I won't touch it, sorry"
+ return False
+ if ( ip != False ):
+ if ( re.search( '^'+self.REGEXP_IPV4, ip ) == None ):
+ print ip+" is a bad IP"
+ return False
+ return True
+ def _normalize_ip ( self, ip ):
+ if ( ip == None ): ip="127.0.0.1"
+ if ( re.search( '^localhost$', ip, re.IGNORECASE )!=None ):
+ ip="127.0.0.1"
+ return ip
+ def remove ( self, domain_name ):
+ if self._security_check( domain_name, False ) == False: return False
+ content = self._get_content()
+ found = self._find_domain( content, domain_name, False )
+ # self.strip_domain ( found['line'], domain_name )
+ if found == False:
+ print 'Domain "'+domain_name+'" not found'
+ return True
+ content[ found['idx'] ] = self.strip_domain ( found['line'], domain_name )
+ if content[ found['idx'] ] == False:
+ #content[ found['idx'] ] = "xxxxxxxxxxxxxxxxx"
+ del content[ found['idx'] ]
+ self._write( content )
+
+ def find (self, domain_name, ip = None ):
+ ip = self._normalize_ip( ip )
+ if self._security_check( domain_name, ip ) == False: return False
+ content = self._get_content()
+ found = self._find_domain( content, domain_name, ip )
+ return found
+
+ def create( self, domain_name, ip = None ):
+ ip = self._normalize_ip( ip )
+ if self._security_check( domain_name, ip ) == False: return False
+ content = self._get_content()
+ found = self._find_domain( content, domain_name, ip )
+ if ( found == False ):
+ print "adding "+ip+" "+domain_name+" at the end of file"
+ content.append( ip+"\t"+domain_name+"\n" )
+ else:
+ print "Found "+domain_name+" at line "+str(found['idx']+1)
+
+ print "Found domain: "+found['domain']+" ("+found['ip']+")"
+ #print domain_regexp
+ if ( found['domain'].lower() == domain_name.lower()):
+ if ( ip == found['ip'] ):
+ print ">>>"+found['line']+"Definition already present, skipping"
+ return True
+ else:
+ print ">>>"+found['line']
+ print "Ip differs. "+found['ip']+" has to become "+ip
+ print "Removing domain name from this line"
+ print "Creating a new entry in the next line"
+ content[ found['idx'] ] = self.strip_domain ( found['line'], domain_name )
+ content[ found['idx']+1: 1 ] = [ ip+"\t"+domain_name+"\n" ]
+ if content[ found['idx'] ] == False:
+ content.remove( False )
+ return True
+ else:
+ print ">>>"+line
+ print "Replacing "+domain_name+" at line "+str(found['idx']+1)
+ return True
+
+
+
+ self._write( content )
+
+ def _get_content ( self ):
+ file = open( '/etc/hosts', 'r' )
+ content = file.readlines()
+ file.close()
+ return content
+ def _find_domain( self, content, domain_name, ip = None ):
+
+ output = []
+ domain_regexp = domain_name.replace( '.', '\\.' ) #quote for regexp
+ found = False
+ # print domain_regexp
+
+ for idx, line in enumerate( content ):
+ regexp = r'^\s*('+self.REGEXP_IPV4+')\s*.*(\s*)('+domain_regexp+')(\s|$)'
+ match = re.search( regexp , line, re.IGNORECASE )
+ if ( match != None ):
+ print "Found "+domain_name+" at line "+str(idx+1)
+ found = True
+ found_entry = match.groups()
+ found_ip = found_entry[0]
+ found_domain = found_entry[2]
+ print "Found domain: "+found_domain+" ("+found_ip+")"
+ #print domain_regexp
+ if ( found_domain.lower() == domain_name.lower()):
+ result = {
+ 'domain':found_domain
+ , 'ip':found_ip
+ , 'idx': idx
+ , 'line': line }
+
+ return result
+ return False
+ def _create( self, domain_name, ip = None ):
+
+ ip = self._normalize_ip( ip )
+ if self._security_check( domain_name, ip ) == False: return False
+
+ return self._find_domain ( domain_name, ip )
+
+ file = open( '/etc/hosts', 'r' )
+ content = file.readlines()
+ file.close()
+
+ output = []
+ domain_regexp = domain_name.replace( '.', '\\.' ) #quote for regexp
+ found = False
+ # print domain_regexp
+
+ for idx, line in enumerate( content ):
+ regexp = r'^\s*('+self.REGEXP_IPV4+')\s*.*(\s*)('+domain_regexp+')(\s|$)'
+ match = re.search( regexp , line, re.IGNORECASE )
+ if ( match != None ):
+ print "Found "+domain_name+" at line "+str(idx+1)
+ found = True
+ found_entry = match.groups()
+ found_ip = found_entry[0]
+ found_domain = found_entry[2]
+ print "Found domain: "+found_domain+" ("+found_ip+")"
+ #print domain_regexp
+ if ( found_domain.lower() == domain_name.lower()):
+ if ( ip == found_ip ):
+ print ">>>"+line+"Definition already present, skipping"
+ break
+ else:
+ print ">>>"+line
+ print "Ip differs. "+found_ip+" has to become "+ip
+ print "Removing domain name from this line"
+ print "Creating a new entry in the next line"
+ content[ idx ] = self.strip_domain ( line, domain_name )
+ content[ idx+1: 1 ] = [ ip+"\t"+domain_name+"\n" ]
+ if content[ idx ] == False:
+ content.remove( False )
+
+ break
+ else:
+ print ">>>"+line
+ print "Replacing "+domain_name+" at line "+str(idx+1)
+ break
+ if ( found == False ):
+ print "adding "+ip+" "+domain_name+" at the end of file"
+ content.append( ip+"\t"+domain_name+"\n" )
+
+ self._write( content )
+ def _write ( self, content ):
+ if ( 0 ): #debug. output without writing to disk
+ for idx, line in enumerate( content ):
+ print str(idx)+". "+line.replace("\n", '')
+ else:
+ try:
+ dest = open( '/etc/hosts', 'w' )
+ dest.writelines( content )
+ dest.close()
+ except:
+ print "Error writing to file. Do you have the needed permissions?"
+ def _get_opt ():
+ print 1
+ def usage ( self ):
+ print """Hosts manager v. 0.1
+USAGE: hosts-manager -a hostname [ip]
+ hosts-manager -r hostname [ip]
+
+Options:
+ -a create a new entry in /etc/hosts
+ -r remove an entry in /etc/hosts
+"""
+
+
+if __name__ == "__main__":
+ HostsManager( True )
=== added file 'build/lib.linux-x86_64-2.6/RapacheCore/Module.py'
--- build/lib.linux-x86_64-2.6/RapacheCore/Module.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheCore/Module.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import os
+import tempfile
+import re
+from RapacheCore import Configuration
+from RapacheCore import Shell
+from xml.dom.minidom import *
+
+def is_denormalized_module ( fname ):
+ try:
+ flink = os.readlink( Configuration.MODS_ENABLED_DIR +"/"+fname )
+ flink = os.path.join(os.path.dirname( Configuration.MODS_AVAILABLE_DIR ), flink)
+ #no exceptions ? Means it's a link
+ return True
+ except:
+ return False
+ return False
+def is_not_normalizable( fname):
+ dest = Configuration.MODS_AVAILABLE_DIR + "/" + fname
+ return os.path.exists( dest )
+
+def blacklisted ( fname ):
+ if re.match( '.*[~]\s*$', fname ) != None : return True
+ if re.match( '.*.swp$', fname ) != None : return True
+ return False
+def normalize_module( fname ):
+ print "Normalizing:", fname
+ orig = Configuration.MODS_ENABLED_DIR + "/" + fname
+ dest = Configuration.MODS_AVAILABLE_DIR + "/" + fname
+ if ( os.path.exists( dest ) == True ):
+ print fname, "already exists in available dir. not even trying"
+ return False
+ command = [ 'mv', orig, dest ]
+ return Shell.command.sudo_execute( command )
+ return os.path.exists( dest )
+
+def get_module_dependants ( name, mods_dict ):
+ dependants = []
+ for idx in mods_dict:
+ if idx != name:
+ mod = mods_dict[ idx ]
+ for dependancy in mod.data[ 'dependancies' ]:
+ if dependancy == name: dependants.append( mod.data['name' ] )
+ return dependants
+"""
+def module_list ():
+ list = {}
+ dirList=os.listdir( Configuration.MODS_AVAILABLE_DIR )
+ dirList = [x for x in dirList if blacklisted( x ) == False ]
+ for fname in dirList :
+ tokens = os.path.splitext( fname )
+ if tokens[1] == '.load':
+ mod = ModuleModel( tokens[0] )
+ try:
+ mod.load()
+ except "VhostUnparsable":
+ pass
+ list[ fname ] = mod
+ mod = None
+ return list
+"""
+def module_list ():
+ list = {}
+
+ #load module descriptions
+ module_descriptions = {}
+ f = open( Configuration.GLADEPATH + "/modules.xml" , "r")
+ xml = f.read()
+ f.close()
+ document = parseString(xml)
+ for node in document.getElementsByTagName("module"):
+ name = node.getAttribute( "name" )
+ if node.firstChild:
+ description = node.firstChild.nodeValue
+ module_descriptions[name] = description
+
+ dirList=os.listdir( Configuration.MODS_AVAILABLE_DIR )
+ dirList = [x for x in dirList if blacklisted( x ) == False ]
+ for fname in dirList :
+ tokens = os.path.splitext( fname )
+ if tokens[1] == '.load':
+ description = None
+ # find a description
+
+ if module_descriptions.has_key(tokens[0]):
+ description = module_descriptions[tokens[0]]
+ elif module_descriptions.has_key("mod_" + tokens[0]):
+ description = module_descriptions["mod_" + tokens[0]]
+
+ mod = ModuleModel( tokens[0] )
+ mod.data[ 'description' ] = description
+ try:
+ mod.load( )
+ except "VhostUnparsable":
+ pass
+ list[ fname ] = mod
+ mod = None
+ return list
+class ModuleModel:
+
+ def __init__(self, name = None):
+ self.defaults = {
+ 'enabled' : False
+ , 'name' : None
+ , 'domain_name': None
+ , 'changed' : False
+ , 'dependancies' : []
+ }
+ self.data = {}
+ self.parsable = False
+ self.changed = False
+
+ self.data = self.defaults
+ if ( name != None ):
+ self.data[ 'name' ] = name
+ self.data[ 'enabled' ] = self.is_enabled()
+
+ def load (self, name = False):
+ try:
+ #reset everything
+ #print "Loading :\t",name
+ if ( name == False ): name = self.data[ 'name' ]
+ self.data = self.defaults
+ self.data['name'] = name
+
+
+ #print "Loading(b) :\t",self.data[ 'name' ]
+ options = {}
+ content = self.get_source()
+ self.__get_dependecies(content)
+ self.parsable = True
+ except:
+ #print "Unparsable by me - unsupported"
+ raise "ModuleUnparsable"
+ return False
+ self.data['configurable'] = \
+ os.path.exists( os.path.join ( Configuration.MODS_AVAILABLE_DIR, self.data['name']+".conf" ))
+
+
+ self.data.update( options )
+ #print self.data
+ return True
+ def __get_dependecies(self, content):
+ content = content.split("\n")
+ dependancies = []
+ for line in content:
+ match = re.match ( r'# Depends:(.*)', line )
+ if match != None:
+ dependancy = match.groups()[0].strip()
+ if dependancy != "" : dependancies.append( dependancy )
+ self.data[ 'dependancies' ] = dependancies
+ def is_enabled ( self ):
+ orig = self.data[ 'name' ] + ".load"
+ dirList=os.listdir( Configuration.MODS_ENABLED_DIR )
+ for fname in dirList:
+ try:
+ flink = os.readlink( Configuration.MODS_ENABLED_DIR +"/"+fname )
+ flink = os.path.join(os.path.dirname( Configuration.MODS_ENABLED_DIR +"/" ), flink)
+ #please note debian brilliantly features a nice set of
+ # mixed absolute and relative links. FREAKS !
+ # the added "/" is also necessary
+ flink = os.path.normpath(flink)
+ if ( flink == Configuration.MODS_AVAILABLE_DIR+"/"+orig ):
+ return True
+ except:
+ pass
+
+ return False
+
+ def _write(self, complete_path, content ):
+ tempfilename = tempfile.mktemp()
+ print "creating temporary file "+tempfilename
+ logfile = open( tempfilename , 'w')
+ logfile.write( content )
+ logfile.close()
+ command = ["cp",tempfilename, complete_path]
+ print "copying tempfile in the appropriate location: ",command
+ Shell.command.sudo_execute( command )
+
+ def toggle( self, status ):
+ "status = True|False"
+ if status:
+ command_name = "a2enmod"
+ else :
+ command_name = "a2dismod"
+ # set new value
+ #tokens = self.data['name'].split('.')
+ #del tokens[ len( tokens ) -1 ]
+ #name = ".".join(tokens)
+ name = self.data['name']
+ Shell.command.sudo_execute( [command_name, name] )
+ self.data['enabled'] = self.is_enabled()
+ self.changed = True
+
+ def get_source ( self ):
+ file = open( Configuration.MODS_AVAILABLE_DIR+'/'+self.data['name']+".load", 'r' )
+ content = file.read()
+ file.close()
+ return content
+ def get_configuration ( self ):
+ file = open( Configuration.MODS_AVAILABLE_DIR+'/'+self.data['name']+".conf", 'r' )
+ content = file.read()
+ file.close()
+ return content
+ def save_configuration (self, content):
+ complete_path = file = Configuration.MODS_AVAILABLE_DIR+'/'+self.data['name']+".conf"
+ self._write(complete_path, content)
\ No newline at end of file
=== added file 'build/lib.linux-x86_64-2.6/RapacheCore/Observer.py'
--- build/lib.linux-x86_64-2.6/RapacheCore/Observer.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheCore/Observer.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+class Observable (object) :
+ """Any instance to be observed with PollyObserver should extend
+ this class. Note this differs from the classical Observable
+ implementation because it only allows the object to be observed
+ from a single Observer"""
+ def __init__(self):
+ self.__observer = None
+ def register (self, observer):
+ self.__observer = observer
+ def unregister (self):
+ if ( self.__observer != None):
+ self.__observer.unregister( self )
+ self.__observer = None
+ def handle_event(self, event):
+ """Override this function in subclasses to implement your
+ own event handling logic"""
+ print self, "- now handling:", event.name, event.args, event
+ def raise_event (self, name, args = {}, no_caller = False ):
+ if no_caller:
+ event = Event( None, name, args )
+ else:
+ event = Event( self, name, args )
+ print '---------------->',event.name , 'raised by' , self
+ if self.__observer != None: self.__observer.notify( event )
+class PollyObserver:
+ """Simple observer derivation. Observes and dispatches events
+ from/to a poll of objects
+ """
+ def __init__(self):
+ self.__observed = []
+ def register(self, obj):
+ """adds an Observable instance to the poll of observed objects
+ and register itself to it."""
+ #print "checking for same obj"
+ for registered_obj in self.__observed:
+ #print obj, ' == ', registered_obj, '??'
+ if obj == registered_obj: return False
+ self.__observed.append( obj )
+ #print "-->",self.__observed
+ obj.register( self )
+ return True
+ def unregister(self, obj):
+ """remove an Observable instance to the poll of observed objects
+ and removes itself from it."""
+ for idx, registered_obj in enumerate( self.__observed ):
+ if obj == registered_obj:
+ del self.__observed[ idx]
+ obj.unregister()
+ return True
+ return False
+ def get_observed(self):
+ """returns observed object list, mainly for debug purpouses"""
+ return self.__observed
+ def notify (self, event ):
+ """dispatches an event all around"""
+ for registered_obj in self.__observed:
+ registered_obj.handle_event( event )
+
+class Event:
+ caller = None
+ name = None
+ args = {}
+ def __init__(self, caller, name, args ):
+ self.caller = caller
+ self.name = name
+ self.args = args
=== added file 'build/lib.linux-x86_64-2.6/RapacheCore/PluginBase.py'
--- build/lib.linux-x86_64-2.6/RapacheCore/PluginBase.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheCore/PluginBase.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,61 @@
+from Module import ModuleModel
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+class PluginBaseObject():
+
+ def __init__(self, path):
+
+ # The path to the plugin
+ self.path = path
+
+ # module this plugin works with
+ self.module = ""
+
+ # Define what additional config should be read from vhost file
+ self.vhosts_config = { } # 0 value | 1 options
+
+ def is_module_enabled(self):
+ if self.module:
+ module = ModuleModel(self.module)
+ module.load()
+ print "STATUS : " + self.module + " - " + str( module.is_enabled())
+ return module.is_enabled()
+ return True
+
+ def is_enabled(self):
+ enabled = self.is_module_enabled()
+
+ #TODO: Method of activating / deactivating plugins
+
+ return enabled
+
+ # Customise the module properties window
+ def load_module_properties(self, notebook, module):
+ return True
+
+ # Perform action on module properties save
+ def save_module_properties(self, module):
+ return True
+
+ # Customise the vhost properties window
+ def load_vhost_properties(self, notebook, vhost_data):
+ return True
+
+ # Perform action on vhost properties save
+ def save_vhost_properties(self, vhost_data):
+ return True
=== added file 'build/lib.linux-x86_64-2.6/RapacheCore/PluginManager.py'
--- build/lib.linux-x86_64-2.6/RapacheCore/PluginManager.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheCore/PluginManager.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,52 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import os.path
+import imp
+import sys
+import traceback
+class PluginManager():
+
+ def __init__(self):
+
+ print "-- Loading plugins --"
+ self.plugins = []
+ self.__add(os.path.join(sys.path[0], "plugins"))
+ self.__add(os.path.expanduser("~/.rapache/plugins"))
+ print ""
+
+ def __add(self, pluginpath):
+
+ print "checking plugin folder : " + pluginpath
+
+ if not pluginpath in sys.path:
+ sys.path.insert(0, pluginpath)
+
+ if os.path.exists(pluginpath):
+ for folder in os.listdir(pluginpath):
+ path = os.path.join(pluginpath,folder)
+ if os.path.isdir(path):
+ try:
+ module = __import__(folder + ".plugin")
+ obj = module.plugin.register(path)
+ self.plugins.append(obj)
+ print "loaded plugin : " + folder
+ except:
+ print "error loading plugin " + folder
+ traceback.print_exc(file=sys.stdout)
+
+
=== added file 'build/lib.linux-x86_64-2.6/RapacheCore/Shell.py'
--- build/lib.linux-x86_64-2.6/RapacheCore/Shell.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheCore/Shell.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,201 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+
+# <--- shit
+#def command( command ):
+# print "COMMAND: "+command
+# return os.system( command )
+# """
+# try:
+# retcode = call("mycmd" + " myarg", shell=True)
+# if retcode < 0:
+# print >>sys.stderr, "Child was terminated by signal", -retcode
+# else:
+# print >>sys.stderr, "Child returned", retcode
+# except OSError, e:
+# print >>sys.stderr, "Execution failed:", e
+# """
+
+import sys
+import gksu2
+import getpass
+import subprocess
+import StringIO
+import sys
+from subprocess import *
+import traceback
+
+class CommandLogEntry:
+
+ def __init__(self, command):
+ self.command = subprocess.list2cmdline(command)
+ self.returncode = None
+ self.output = None
+ self.error = None
+
+
+class CommandHandler:
+
+ def __init__(self):
+ # Verboseness
+ # 0 = No output
+ # 1 = prints the command and its return code
+ # 2 = Command output
+ self.verbose = 0
+ self.command_log = []
+ # let's make the object stateful, no duplicate password
+ # typing needed for our users
+ self.__password = None
+
+ def __get_password(self, description, prompt="Password: "):
+
+ ctx = gksu2.Context()
+ ctx.set_message(description)
+ ctx.set_command(subprocess.list2cmdline(["ls","/root"]))
+ ctx.set_grab(True)
+
+ return gksu2.ask_password_full(ctx, prompt) # how does su_full invoke keychain options?
+
+ def __sudo_popen (self, command, password ):
+ #don't enable the following line
+ #print "using password:", password
+
+ # prepend sudo to command and allow piping in
+ command.insert(0, "sudo")
+ command.insert(1, "-S")
+ p = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
+ #we need a try catch to avoid tracebacks to be printed
+ #as they would show the password
+ try:
+ p.stdin.write( password )
+ except:
+ #don't enable the following line as you password
+ #will be printed out
+ #traceback.print_exc() #<-- CAUTION !
+
+ print "ERROR: in __sudo_popen()"
+ pass
+ return p
+
+ def is_auth_needed (self):
+ if not self.__password: return True
+
+ #only ASCII chars in the fake pass, or it won't work
+ #because we have not encoding declared in this file
+ #http://www.python.org/dev/peps/pep-0263/
+ fakepass= 'xxxASAISUHAISGHauyguyagUDBhb2156412-,1-2.,1212'
+ command = [ 'head', '/var/log/syslog', '-n 1' ]
+ p = self.__sudo_popen( command, fakepass)
+ output, error = p.communicate()
+ returncode = p.returncode
+ self.__output(command, returncode, output, error)
+ print "needs login:", returncode
+ if returncode == 0:
+ return False
+ else:
+ self.__password = None
+ return True
+
+ # Description will be discarded
+ def execute(self, command, description = None ):
+ returncode = 0
+ output = None
+ error = None
+ # excute the command, capture output, error and return code
+ p = Popen(command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
+ output, error = p.communicate()
+ returncode = p.returncode
+ self.__output(command, returncode, output, error)
+ return (returncode, output, error)
+
+ def __output (self, command, returncode, output, error ):
+ string_command = subprocess.list2cmdline(command)
+ if self.verbose > 0:
+ print "COMMAND (return code: "+str(returncode)+"): "+ string_command
+ if self.verbose > 1:
+ print output
+ if error:
+ sys.stderr.write( error+"\n")
+
+ def sudo_reset (self):
+ self.__password = None
+ command = ['sudo', '-K' ]
+ p = Popen( command, stdout=PIPE, stderr=PIPE, stdin=PIPE)
+ output, error = p.communicate()
+ returncode = p.returncode
+ self.__output(command, returncode, output, error)
+
+ def sudo_execute(self, command, description = "Super user priviledges are required to perform this operation"):
+ #log = CommandLogEntry(command)
+ #self.command_log.append( log )
+
+ returncode = 0
+ output = None
+ error = None
+ new_password = None
+
+ auth_needed = self.is_auth_needed()
+
+ if auth_needed :
+ #let's ask the user for a new password
+ if not self.__password :
+ try:
+ new_password = self.__get_password(description)
+ except:
+ returncode = 1
+ error = "Incorrect password"
+
+ if (not auth_needed) or new_password:
+ #if already authorized let's fake a random password
+ if new_password:
+ password = new_password
+ elif self.__password:
+ password = self.__password
+ else:
+ #let's just fake it. It will work anyways
+ password = 'xxx'
+
+ # excute the command, capture output, error and return code
+ p = self.__sudo_popen( command, password )
+ #p.stdin.write(password)
+ output, error = p.communicate()
+ returncode = p.returncode
+ self.__output(command, returncode, output, error)
+
+ if new_password:
+ self.__password = 'asasasaasas'
+ #self.__password = new_password
+
+ #log.returncode = returncode
+ #log.output = output
+ #log.error = error
+
+ return (returncode, output, error)
+
+# Look ma'! A singleton !
+command = CommandHandler()
+
+if __name__ == "__main__":
+ c = CommandHandler()
+ c.verbose = 2
+ #print c.is_auth_needed()
+
+ print c.sudo_reset()
+ code, out, err = c.sudo_execute(["head", "/var/log/syslog"], "Pwd FTW !")
+ code, out, err = c.sudo_execute(["head", "/var/log/syslog"], "Pwd FTW !")
+
=== added file 'build/lib.linux-x86_64-2.6/RapacheCore/VirtualHost.py'
--- build/lib.linux-x86_64-2.6/RapacheCore/VirtualHost.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheCore/VirtualHost.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,379 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import os
+import tempfile
+import re
+from RapacheCore import Configuration
+from RapacheCore.ApacheConf import *
+from RapacheCore.HostsManager import HostsManager
+from RapacheCore import Shell
+
+VHOST_TEMPLATE = """#created for you by Rapache
+<VirtualHost *>
+ #ServerAdmin webmaster@xxxxxxxxxxx
+ ServerName example
+ DocumentRoot /var/www/examplepath
+</VirtualHost>"""
+
+
+def valid_domain_name ( name ):
+ # TODO: fix regular expression
+ valid = ( re.search( '^[a-zA-Z0-9.-]+$', name ) != None )
+ return valid
+
+def is_denormalized_vhost ( fname ):
+ try:
+ flink = os.readlink( Configuration.SITES_ENABLED_DIR +"/"+fname )
+ flink = os.path.join(os.path.dirname( Configuration.SITES_AVAILABLE_DIR ), flink)
+ #no exceptions ? Means it's a link
+ return True
+ except:
+ return False
+ return False
+def is_not_normalizable( fname):
+ dest = Configuration.SITES_AVAILABLE_DIR + "/" + fname
+ return os.path.exists( dest )
+
+def normalize_vhost( fname ):
+ print "Normalizing:", fname
+ orig = Configuration.SITES_ENABLED_DIR + "/" + fname
+ dest = Configuration.SITES_AVAILABLE_DIR + "/" + fname
+ if ( os.path.exists( dest ) == True ):
+ print fname, "already exists in available dir. not even trying"
+ return False
+ command = ['mv',orig,dest]
+ code, output, error = Shell.command.sudo_execute( command )
+ return ( code == 0 )
+ return os.path.exists( dest )
+
+class VirtualHostModel:
+
+ def __init__(self, name = None, plugin_manager = None):
+ self.defaults = {
+ 'enabled' : False
+ , 'name' : None
+ , 'ServerName': None
+ , 'changed' : False
+ , 'hack_hosts' : False
+ , 'DocumentRoot' : None
+ }
+ self.data = {}
+ self.parsable = False
+ self.changed = False
+ self.simulation = False
+
+ self.data = self.defaults
+ if ( name != None ):
+ self.data[ 'name' ] = name
+ self.data[ 'enabled' ] = self.is_enabled()
+
+ # Init plugin values so the keys exist
+ if plugin_manager:
+ for plugin in plugin_manager.plugins:
+ for key in plugin.vhosts_config.keys():
+ self.data[ key ] = None
+
+ def _search(self, content, regexp ):
+ content = content.split( "\n" )
+ for line in content:
+ match = re.search( regexp , line, re.IGNORECASE )
+ if ( match != None ) :
+ if match != False:
+ return match
+ return False
+
+ def _get_conf_value(self, content, regexp):
+ match = self._search(content, regexp )
+ if ( match == False or match == None ): return None
+ found_entry = match.groups()
+ found_value = found_entry[0]
+ return found_value
+ def load(self, name = False, plugin_manager = None):
+ if ( name == False ): name = self.data[ 'name' ]
+ options = {}
+ parser = Parser()
+ parser.load( os.path.join(Configuration.SITES_AVAILABLE_DIR, name) )
+ try:
+ piece = VhostParser( parser )
+ except "VhostNotFound":
+ self.parsable = False
+ return False
+ domain_name = piece.get_value( 'ServerName' )
+ if domain_name == None:
+ self.parsable = False
+ #return False
+ options[ 'ServerName' ] = domain_name
+ options[ 'ServerAlias' ] = piece.get_options( 'ServerAlias' )
+ print options[ 'ServerAlias' ]
+ options[ 'DocumentRoot' ] = piece.get_value('DocumentRoot')
+ hosts = HostsManager()
+ if ( domain_name == None or hosts.find ( domain_name ) == False ):
+ options['hack_hosts'] = False
+ else:
+ options['hack_hosts'] = True
+ self.parsable = True
+
+ # Load plugin values
+ if plugin_manager:
+ for plugin in plugin_manager.plugins:
+ for key in plugin.vhosts_config.keys():
+ if plugin.vhosts_config[key] == 1:
+ options[ key ] = piece.get_options( key )
+ else:
+ options[ key ] = piece.get_value( key )
+
+ self.data.update( options )
+ return True
+
+
+ def loaad (self, name = False):
+ print "Loading Vhosts list"
+ try:
+ #reset everything
+ #print "Loading :\t",name
+ if ( name == False ): name = self.data[ 'name' ]
+ self.data = self.defaults
+ self.data['name'] = name
+
+ #print "Loading(b) :\t",self.data[ 'name' ]
+ options = {}
+ content = self.get_source()
+ #domain_name = self._get_domain_name(content)
+ domain_regexp = r'^\s*ServerName\s+([A-Za-z0-9.\-_]*)'
+ domain_name = self._get_conf_value(content, domain_regexp)
+ options[ 'ServerName' ] = domain_name
+ domain_regexp = domain_name.replace( '.', '\\.' ) #quote for regexp
+ www_regexp = r'^\s*ServerAlias\s*[^#]*\s+www\.'+domain_regexp+'(\s*|$)'
+ folder_regexp = domain_regexp = r'^\s*DocumentRoot\s+(\S+\s*\S+)'
+
+ #print "Domain Name :\t"+domain_name
+ if self._search(content, www_regexp ) != None \
+ and self._search(content, www_regexp ) != False :
+ options[ 'has_www' ] = True
+ else:
+ options[ 'has_www' ] = False
+
+ #print "Has www :\t"+str(options[ 'has_www' ])
+
+ options[ 'DocumentRoot' ] = self._get_conf_value(content, folder_regexp)
+
+ #print "Document Root :\t"+str( options[ 'DocumentRoot' ] )
+ hosts = HostsManager()
+ if ( hosts.find ( domain_name ) == False ):
+ options['hack_hosts'] = False
+ else:
+ options['hack_hosts'] = True
+ self.parsable = True
+ except:
+ print "Unparsable by me - unsupported"
+ raise "VhostUnparsable"
+ return False
+ self.data.update( options )
+ #print self.data
+ return True
+
+ def is_enabled ( self ):
+ orig = self.data[ 'name' ]
+ dirList=os.listdir( Configuration.SITES_ENABLED_DIR )
+ for fname in dirList:
+ try:
+ flink = os.readlink( Configuration.SITES_ENABLED_DIR +"/"+fname )
+ flink = os.path.join(os.path.dirname( Configuration.SITES_ENABLED_DIR +"/" ), flink)
+ # please note debian features a nice set of
+ # mixed absolute and relative links. FREAKS !
+ # the added "/" is also necessary
+ flink = os.path.normpath(flink)
+ if ( flink == Configuration.SITES_AVAILABLE_DIR+"/"+orig ):
+ return True
+ except:
+ pass
+
+ return False
+
+ def toggle( self, status ):
+ "status = True|False"
+ if status:
+ command = "a2ensite"
+ else :
+ command = "a2dissite"
+ # set new value
+ if self.simulation:
+ print "SIMULATED ",[ command, self.data['name'] ]
+ self.data['enabled'] = status
+ else:
+ Shell.command.sudo_execute( [ command, self.data['name'] ] )
+ self.data['enabled'] = self.is_enabled()
+ self.changed = True
+
+ def delete( self ):
+ "Deletes a VirtualHost configuration file"
+ if ( self.is_enabled() ): self.toggle( False )
+ Shell.command.sudo_execute( [ 'rm', Configuration.SITES_AVAILABLE_DIR+'/'+self.data['name'] ])
+ def _create_complete_path ( self, complete_path ):
+ print "Attempting to create: " + complete_path
+ tokens = complete_path.split( '/' )
+ del tokens[ 0 ]
+ path = ''
+ for piece in tokens:
+ path = path + '/' + piece
+ if ( os.path.exists( path ) == False ):
+ try:
+ Shell.command.sudo_execute( ["mkdir", path] )
+ except:
+ print "error on creating path"+path
+ return False
+ print "Created path: " + path
+ return True
+
+ def get_source ( self ):
+ file = open( Configuration.SITES_AVAILABLE_DIR+'/'+self.data['name'], 'r' )
+ content = file.read()
+ file.close()
+ return content
+ def update ( self, new_options, name ):
+ print "updating virtual host", name
+ #print new_options
+
+ old_enabled = self.is_enabled()
+ print "IS ENABLED", old_enabled
+ parser = Parser()
+ parser.load( Configuration.SITES_AVAILABLE_DIR+'/'+name )
+ piece = VhostParser( parser )
+ old_servername = piece.get_value( 'ServerName' )
+
+ # Get a bit more dynamic with it
+ for key in new_options.keys():
+ obj = new_options[key]
+ if isinstance(obj, list):
+ piece.set_value(key, '')
+ for opt in obj:
+ piece.add_option(key, opt )
+ elif isinstance(obj, str):
+ if obj:
+ piece.set_value(key, obj)
+ else:
+ piece.remove_value(key)
+
+ #piece.set_value('ServerAlias', '' )
+ #for domain in new_options ['ServerAlias']:
+ # piece.add_option('ServerAlias', domain )
+
+ print "DocumentRoot From",piece.get_value('DocumentRoot' ),"to",new_options['DocumentRoot']
+ piece.set_value('DocumentRoot', new_options['DocumentRoot'] )
+
+ print "ServerName From",piece.get_value('ServerName' ),"to",new_options['ServerName']
+ piece.set_value('ServerName', new_options['ServerName'] )
+ complete_path = Configuration.SITES_AVAILABLE_DIR+'/'+ name
+
+ print "Writing.."
+ print parser.get_source()
+ self._write( complete_path, parser.get_source() )
+
+ #if the servername coincides with the configuration filename
+ #we try to stick with the convention
+ new_name = Configuration.SITES_AVAILABLE_DIR + "/"+ new_options['ServerName']
+ old_name = Configuration.SITES_AVAILABLE_DIR + "/"+ old_servername
+ print "old name", old_name
+ print "new name", new_name
+
+ if old_name != new_name and os.path.exists( new_name ) == False:
+ print "Server name changed, updating conf filename"
+ self.toggle( False )
+ Shell.command.sudo_execute( [mv, old_name, new_name] )
+ if os.path.exists( new_name ) == True:
+ #success ! we need to reload vhost with the new name
+ self.load( new_options['ServerName'] )
+ #...so we can toogle it on again
+ if old_enabled == True:
+ print "Re-activating"
+ self.toggle( True )
+ else:
+ print "Skipping activation"
+ else:
+ print "error! not created:", new_name
+ return True
+ def _write(self, complete_path, content ):
+ tempfilename = tempfile.mktemp()
+ print "creating temporary file "+tempfilename
+ logfile = open( tempfilename , 'w')
+ logfile.write( content )
+ logfile.close()
+ command = ['cp', tempfilename, complete_path ]
+ print "copying tempfile in the appropriate location: ",command
+ Shell.command.sudo_execute( command )
+
+ def create ( self, new_options ):
+
+ options = self.data
+ options.update( new_options )
+
+ #as of creation-time name is not expected to be in options
+ options['name'] = options[ 'ServerName' ]
+ complete_path = Configuration.SITES_AVAILABLE_DIR+'/'+options['name']
+
+ print options
+ print "Creating virtualhost: "+options['name']
+ print "Folder: "+options['DocumentRoot']
+
+ if ( os.path.exists( options['DocumentRoot'] ) == False ):
+ print "Folder "+options['DocumentRoot']+" does not exist"
+ self._create_complete_path( options['DocumentRoot'] )
+
+ if ( os.path.exists( options['DocumentRoot'] ) == False ):
+ self.error( "Could not create target folder" ) #TODO fix this
+ return False
+
+ if ( valid_domain_name( options['ServerName'] ) == False ):
+ self.error ( 'Bad domain name: '+options['ServerName'] )
+ return False
+
+ if os.path.exists( complete_path ):
+ raise "VhostExists", 'Virtual host already exists :('
+ #self.error( 'Virtual host already exists :(' )
+ return False
+ """
+ template = VHOST_TEMPLATE.replace( '||example||', options['ServerName'] )
+ template = template.replace( '||DocumentRoot||', options['DocumentRoot'] )
+ if ( options[ 'has_www' ] ):
+ template = template.replace( '#ServerAlias www', 'ServerAlias www' )
+ """
+ parser = Parser()
+ parser.set_content_from_string( VHOST_TEMPLATE )
+ piece = VhostParser( parser )
+ piece.set_value('ServerName', options['ServerName'] )
+ piece.set_value('DocumentRoot', options['DocumentRoot'] )
+
+ print "min", piece.min, "max", piece.max
+ #reset previous aliases
+ piece.set_value('ServerAlias', '' )
+ for domain in options ['ServerAlias']:
+ piece.add_option('ServerAlias', domain )
+ print parser.get_content()
+
+ self._write( complete_path, "\n".join(parser.get_content() ) )
+
+ if ( options[ 'hack_hosts' ] ):
+ Shell.command.sudo_execute ( [Configuration.APPPATH+'/hosts-manager', '-a', options['ServerName'] ] )
+ for alias_name in options[ 'ServerAlias' ]:
+ Shell.command.sudo_execute ( [Configuration.APPPATH+'/hosts-manager', '-a',alias_name ])
+ self.changed = True
+ self.toggle( True ) #activate by default
+
+ return True
=== added file 'build/lib.linux-x86_64-2.6/RapacheCore/__init__.py'
=== added directory 'build/lib.linux-x86_64-2.6/RapacheGtk'
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/CheckListView.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/CheckListView.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/CheckListView.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,123 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import gtk
+import gobject
+
+(
+ COLUMN_FIXED,
+ COLUMN_SEVERITY,
+ COLUMN_MARKUP
+) = range(3)
+from RapacheCore import Configuration
+import RapacheCore.Observer
+from RapacheGtk.EventDispatcher import Master
+
+class CheckListView (gtk.TreeView ):
+ """Nice list with icons and checkboxes"""
+ def __init__ (self, *args, **kwargs):
+ super (CheckListView, self).__init__ (*args, **kwargs)
+
+ self.toggled_callback = None
+ self.selected_callback = None
+ self.icon_callback = None
+
+ self.Observable = RapacheCore.Observer.Observable()
+ Master.register(self)
+
+ self.column_checkbox = None
+ self.column_description = None
+ self.column_icon = None
+
+ self.__add_columns()
+
+ self.set_headers_visible( False )
+ self.set_rules_hint(True)
+ self.set_search_column(COLUMN_SEVERITY)
+
+ #----decorating observer
+ def register (self, *args, **kwargs): return self.Observable.register(*args, **kwargs)
+ def unregister (self, *args, **kwargs): return self.Observable.unregister(*args, **kwargs)
+ def handle_event (self, *args, **kwargs): return self.Observable.handle_event(*args, **kwargs)
+ def raise_event (self, *args, **kwargs): return self.Observable.raise_event(*args, **kwargs)
+
+ def load (self):
+ raise "AbstractMethod", "Please override this"
+
+ def _reset_model (self):
+ lstore = self.get_model()
+ if ( lstore == None ):
+ lstore = self._default_model()
+ self.set_model( lstore )
+ else:
+ lstore.clear()
+ return lstore
+ def _default_model (self):
+ lstore = gtk.ListStore(
+ gobject.TYPE_BOOLEAN,
+ gobject.TYPE_STRING,
+ gobject.TYPE_STRING)
+ return lstore
+
+ def __toggled(self, *args, **kwargs):
+ if self.toggled_callback != None:
+ self.toggled_callback( *args, **kwargs )
+ def __selected(self, *args, **kwargs):
+ if self.selected_callback != None:
+ self.selected_callback( *args, **kwargs )
+ def __icon_requested(self, *args, **kwargs):
+ if self.icon_callback != None:
+ self.icon_callback( *args, **kwargs )
+
+ def __add_columns(self):
+ #model = self.get_model()
+ # column for fixed toggles
+ renderer = gtk.CellRendererToggle()
+ renderer.connect('toggled', self.__toggled, self)
+ self.column_checkbox = gtk.TreeViewColumn('Enabled', renderer, active=COLUMN_FIXED)
+ self.column_checkbox.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
+ self.column_checkbox.set_fixed_width(40)
+ self.append_column(self.column_checkbox)
+
+ self.column_icon = gtk.TreeViewColumn()
+ cellRenderer = gtk.CellRendererPixbuf()
+ self.column_icon.pack_start(cellRenderer, expand = False)
+ self.column_icon.set_cell_data_func(cellRenderer, self.__icon_requested )
+ self.append_column(self.column_icon)
+
+ self.column_description = gtk.TreeViewColumn('Description', gtk.CellRendererText(),
+ markup=COLUMN_MARKUP)
+ self.column_description.set_sort_column_id(COLUMN_MARKUP)
+ self.append_column(self.column_description)
+ self.get_selection().connect("changed", self.__selected )
+
+ def get_selected_line( self ):
+ #try:
+ selection = self.get_selection()
+ #print '==>', self.get_selected()
+ #print selection.get_selected_rows()[1]
+ try:
+ rows = selection.get_selected_rows()[1][0]
+ num_row = rows[0]
+ model = self.get_model()
+ name = model[ num_row ][1]
+ except IndexError:
+ return None
+ return name
+ #except:
+ # return None
+
+gobject.type_register (CheckListView)
\ No newline at end of file
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/ConfirmationWindow.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/ConfirmationWindow.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/ConfirmationWindow.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import re
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+try:
+ from RapacheCore import Configuration
+except:
+ if __name__ != "__main__":
+ sys.exit(1)
+
+import os
+
+
+class ConfirmationWindow:
+
+ def __init__ ( self, parent = None):
+
+ self.parent = parent
+ self.title = None
+ self.question = None
+ self.return_value = None
+
+ gladefile = os.path.join(Configuration.GLADEPATH, "confirmation.glade")
+ wtree = gtk.glade.XML(gladefile)
+
+ self.window = wtree.get_widget("confirmation_window")
+ self.ok_button = wtree.get_widget("ok_button")
+ self.cancel_button = wtree.get_widget("cancel_button")
+ self.question_label = wtree.get_widget("question_label")
+ signals = {
+ "on_ok_button_clicked" : self.on_ok_button_clicked,
+ "on_cancel_button_clicked" : self.on_cancel_button_clicked
+ }
+ wtree.signal_autoconnect(signals)
+
+ # add on destroy to quit loop
+ self.window.connect("destroy", self.on_destroy)
+
+ def run(self):
+ if self.title: self.window.set_title ( self.title )
+ if self.question: self.question_label.set_text( self.question )
+
+ self.window.show()
+ gtk.main()
+
+ def on_destroy(self, widget, data=None):
+ gtk.main_quit()
+
+ def on_ok_button_clicked(self, widget):
+ self.return_value = True
+ self.window.destroy()
+ def on_cancel_button_clicked(self, widget):
+ self.return_value = False
+ self.window.destroy()
+
+def ask_confirmation ( question = None, title = None):
+ win = ConfirmationWindow()
+ win.title = title
+ win.question = question
+ win.run()
+ answer = win.return_value
+ print "Question: ", question
+ print "Answer: ", answer
+ return answer
+
+
+if __name__ == "__main__":
+ class Configuration:
+ GLADEPATH = '../Glade'
+ value = ask_confirmation( 'did you solve bug #1 ?', 'bug confirmation')
+ print '================='
+ print value
+
+
\ No newline at end of file
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/DesktopEnvironment.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/DesktopEnvironment.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/DesktopEnvironment.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,44 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import subprocess
+import os
+from RapacheCore import Shell
+
+"""abstracts Desktop Environment's specific operation."""
+# TODO: refactor this into a factory to support more than a Desktop Environment easily
+#
+# care should be taken with userid, we don't want root priviledges when they're not needed
+
+
+# Grabbed from Ubuntu's UpdateManager (ChangelogViewer.py)
+# Copyright (c) 2006 Sebastian Heinlein
+# 2007 Canonical
+# TODO: move this into an utility module
+def open_url(url):
+ """Opens the specified URL in a browser"""
+ # Find an appropiate browser
+ if os.path.exists('/usr/bin/gnome-open'):
+ command = ['gnome-open', url]
+ else:
+ command = ['x-www-browser', url]
+ # Avoid to run the browser as user root
+ if os.getuid() == 0 and os.environ.has_key('SUDO_USER'):
+ command = ['sudo', '-u', os.environ['SUDO_USER']] + command
+ subprocess.Popen(command)
+# TODO: find out how to open nautilus in background
+def open_dir( path):
+ Shell.command.sudo_execute ( ['nautilus',path, '--no-desktop'] )
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/EditDomainNameGui.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/EditDomainNameGui.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/EditDomainNameGui.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import re
+import os
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+from RapacheCore.VirtualHost import *
+from RapacheGtk import GuiUtils
+
+class EditDomainNameWindow:
+
+ def __init__ ( self, domain = ""):
+ self.return_value = None
+
+ gladefile = os.path.join(Configuration.GLADEPATH, "edit_domain_name.glade")
+ wtree = gtk.glade.XML(gladefile)
+
+ self.window = wtree.get_widget("dialog_edit_domain_name")
+ self.entry_domain = wtree.get_widget("entry_domain")
+ self.label_heading = wtree.get_widget("label_heading")
+ self.image_icon = wtree.get_widget("image_icon")
+
+ signals = {
+ "on_button_ok_clicked" : self.on_button_ok_clicked,
+ "on_button_cancel_clicked" : self.on_button_cancel_clicked
+ }
+ wtree.signal_autoconnect(signals)
+
+ # add on destroy to quit loop
+ self.window.connect("destroy", self.on_destroy)
+
+ if domain:
+ self.entry_domain.set_text( domain )
+
+ def run(self):
+ self.window.show()
+ self.entry_domain.select_region(0,-1)
+ gtk.main()
+
+ return self.return_value
+
+ def on_destroy(self, widget, data=None):
+ gtk.main_quit()
+
+ def on_button_ok_clicked(self, widget):
+ self.return_value = self.entry_domain.get_text()
+ self.window.destroy()
+ return
+
+ def on_button_cancel_clicked(self, widget):
+ self.window.destroy()
+ return
+
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/EventDispatcher.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/EventDispatcher.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/EventDispatcher.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,19 @@
+import RapacheCore.Observer
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Master = RapacheCore.Observer.PollyObserver()
\ No newline at end of file
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/GuiUtils.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/GuiUtils.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/GuiUtils.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,53 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import gtk
+import gtksourceview2
+import pango
+from RapacheCore import Configuration
+
+def style_as_tooltip( obj ):
+ pw = gtk.Window(gtk.WINDOW_POPUP)
+ pw.set_name('gtk-tooltip')
+ pw.ensure_style()
+ obj.set_style(pw.get_style())
+ obj.connect('expose-event', paint)
+
+def paint(box, event):
+ box.style.paint_flat_box(box.window, gtk.STATE_NORMAL, gtk.SHADOW_OUT, None, box, "tooltip", box.allocation.x+1, box.allocation.y+1, box.allocation.width-2, box.allocation.height-2)
+
+def change_button_label ( button, new_label ):
+ """Changes the label of a button"""
+ button.show()
+ alignment = button.get_children()[0]
+ hbox = alignment.get_children()[0]
+ image, label = hbox.get_children()
+ label.set_text( new_label )
+
+def new_apache_sourceview():
+ bufferS = gtksourceview2.Buffer()
+ manager = gtksourceview2.LanguageManager()
+
+ #language = manager.get_language_from_mime_type("text/xml")
+ manager.set_search_path( [ Configuration.GLADEPATH ] + manager.get_search_path() )
+ language = manager.get_language('apache')
+ bufferS.set_language(language)
+ bufferS.set_highlight_syntax(True)
+ sourceview = gtksourceview2.View(bufferS)
+ sourceview.set_show_line_numbers(True)
+ #TODO sniff gnome default monospace font
+ sourceview.modify_font(pango.FontDescription("monospace 10"))
+ return sourceview
\ No newline at end of file
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/ModuleGui.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/ModuleGui.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/ModuleGui.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,139 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+""".
+Issues with the new window:
+ - self.parent doesn't work
+ - onblur doesn't trigger when pressing Return
+ - changing a domain name doesn't change subdomains
+ - empty server aliases shuoldn't be managed
+ALSO:
+ - please implement a delete directive func in the parser
+ - move denorm. vhosts in another tab
+ - merge with Qense warning window
+"""
+
+import sys
+import re
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+import os
+import pango
+import tempfile
+import traceback
+import RapacheGtk.GuiUtils
+from RapacheCore.Module import *
+from RapacheGtk import GuiUtils
+import RapacheGtk.DesktopEnvironment as Desktop
+
+
+def open_module_doc( name ):
+ if ( name == None ): return False
+ url = "http://httpd.apache.org/docs/2.2/mod/mod_%s.html" % name
+ Desktop.open_url( url )
+
+class ModuleWindow:
+
+ def __init__ ( self, parent = None):
+
+ self.module = None
+ self.create_new = True
+ self.parent = parent
+
+ gladefile = os.path.join(Configuration.GLADEPATH, "edit_module.glade")
+ wtree = gtk.glade.XML(gladefile)
+
+ self.window = wtree.get_widget("dialog_edit_module")
+ #self.text_view_module_conf = wtree.get_widget("text_view_module_conf")
+ self.notebook = wtree.get_widget("notebook")
+ self.button_save = wtree.get_widget("button_save")
+ self.error_area = wtree.get_widget("error_area")
+ self.module_doc_button = wtree.get_widget("module_doc_button")
+
+ signals = {
+ "on_button_save_clicked" : self.on_button_save_clicked,
+ "on_button_cancel_clicked" : self.on_button_cancel_clicked,
+ "on_module_doc_button_clicked" : self.on_module_doc_button_clicked
+ }
+ wtree.signal_autoconnect(signals)
+ # add on destroy to quit loop
+ self.window.connect("destroy", self.on_destroy)
+
+ self.text_view_module_conf = GuiUtils.new_apache_sourceview()
+ self.text_view_module_conf.show()
+ wtree.get_widget("text_view_module_conf_area").add(self.text_view_module_conf)
+
+ GuiUtils.change_button_label( self.module_doc_button, 'Documentation' )
+ GuiUtils.style_as_tooltip( self.error_area )
+ def run(self):
+ self.window.show()
+ gtk.main()
+
+ def load (self, name ):
+ self.window.set_title(name)
+ self.module = ModuleModel ( name )
+ #self.module.load()
+ buf = self.text_view_module_conf.get_buffer()
+ buf.set_text( self.module.get_configuration() )
+
+ # Load UI Plugins
+ for plugin in self.parent.plugin_manager.plugins:
+ if plugin.module == name:
+ try:
+ print "Loading plugin " + name
+ plugin.load_module_properties(self.notebook, self.module)
+ except Exception:
+ traceback.print_exc(file=sys.stdout)
+
+ def on_destroy(self, widget, data=None):
+ gtk.main_quit()
+
+ def on_button_save_clicked(self, widget):
+
+ name = self.module.data['name']
+ print "Current name:", name
+ buff = self.text_view_module_conf.get_buffer()
+ text = buff.get_text(buff.get_start_iter(), buff.get_end_iter())
+
+ mod = ModuleModel( name )
+ mod.save_configuration( text )
+
+ #self.parent.refresh_vhosts()
+ self.parent.please_restart()
+ self.window.destroy()
+
+ def on_button_cancel_clicked(self, widget):
+ self.window.destroy()
+ return
+ def on_module_doc_button_clicked (self, widget ):
+ name = self.module.data['name']
+ open_module_doc(name)
+ def show_error ( self, message ):
+
+ self.xml.get_widget( 'message_text' ).set_label( '<b>'+message+'</b>' )
+ self.xml.get_widget( 'message_container' ).show()
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/RapacheGui.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/RapacheGui.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/RapacheGui.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,294 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#TODO throw appropriate exceptions (bug: vhost already exist displays only
+# after actually trying to create it's dir. check before )
+
+#TODO read ERRORLEVEL from command line operations
+#TODO stop operation if gksudo fails
+#TODO check for sites-enabled-only sites and normalize them
+
+#TODO delete-tarantella: hosts deletion & confirmation
+
+#TODO refuse to edit complex vhosts ( done ? )
+
+import gnome.ui
+import gobject
+import gtk
+import os
+import re
+(
+ COLUMN_FIXED,
+ COLUMN_SEVERITY,
+ COLUMN_MARKUP
+) = range(3)
+
+
+from RapacheGtk.VirtualHostGui import VirtualHostWindow
+from RapacheGtk.ModuleGui import ModuleWindow
+from RapacheCore.PluginManager import PluginManager
+from RapacheGtk.ModuleGui import open_module_doc
+from RapacheCore.VirtualHost import *
+from RapacheGtk import ConfirmationWindow
+from RapacheGtk import GuiUtils
+from RapacheCore import Shell
+import VhostsTreeView
+import RapacheCore.Observer
+from RapacheGtk.EventDispatcher import Master
+import subprocess
+import RapacheGtk.DesktopEnvironment as Desktop
+
+data = \
+[(False, "Loading", "please wait" )]
+
+APPNAME="Rapache"
+APPVERSION="0.6"
+
+
+class MainWindow( RapacheCore.Observer.Observable ) :
+ """This is an Hello World Rapacheefication application"""
+
+ def __init__(self, *args, **kwargs):
+ super (MainWindow, self).__init__ (*args, **kwargs)
+ Master.register(self)
+
+ self.denormalized_virtual_hosts = {}
+ self.plugin_manager = PluginManager()
+ gnome.init(APPNAME, APPVERSION)
+ self.gladefile = Configuration.GLADEPATH + "/" + "main.glade"
+ self.xml = gtk.glade.XML(self.gladefile)
+ #Create our dictionary and connect it
+ dic = { "new_button_clicked" : self.new_button_clicked,
+ "on_MainWindow_destroy" : self.quit ,
+ "please_restart" : self.restart_apache ,
+ "on_delete" : self.delete_button_clicked,
+ "edit_button_clicked" : self.edit_button_clicked,
+ "edit_module_button_clicked" : self.edit_module_button_clicked,
+ "browse_sites_available" : self.browse_sites_available,
+ "fix_vhosts_clicked" : self.fix_vhosts,
+ "surf_this_button_clicked" : self.surf_this,
+ "browse_button_clicked" : self.browse_this,
+ "about_clicked" : self.display_about,
+ "open_doc_button_clicked" : self.open_doc_button_clicked,
+ "on_button_hide_warning_clicked" : self.on_button_hide_warning_clicked,
+ "quit" : self.quit }
+ gtk.window_set_default_icon(self.xml.get_widget("MainWindow").get_icon())
+ self.xml.signal_autoconnect(dic)
+ GuiUtils.change_button_label ( self.xml.get_widget( 'restart_apache' ), "Restart Apache" )
+ GuiUtils.change_button_label ( self.xml.get_widget( 'fix_vhosts' ), "Fix Virtual Hosts" )
+ #hereby we create lists
+ self.create_vhost_list()
+ self.create_modules_list()
+ #hereby we fill them
+ self.refresh_lists()
+
+ GuiUtils.style_as_tooltip( self.xml.get_widget( 'restart_apache_notice' ) )
+ GuiUtils.style_as_tooltip( self.xml.get_widget( 'unnormalized_notice' ) )
+
+ def on_button_hide_warning_clicked(self, widget):
+ self.xml.get_widget( 'restart_apache_notice' ).hide()
+
+ def handle_event(self, event ):
+ if event.name == 'please_restart_apache':
+ self.please_restart()
+ return
+ if event.name == 'please_reload_lists':
+ self.load_lists()
+ return
+ def browse_sites_available(self, widget):
+ Desktop.open_dir( Configuration.SITES_AVAILABLE_DIR )
+ return
+
+ def new_button_clicked(self, widget):
+ new_vhost_window = VirtualHostWindow ( self )
+ #new_vhost_window.load()
+ new_vhost_window.run()
+ def edit_button_clicked(self, widget, notused = None, notused2 = None):
+ name = self.vhosts_treeview.get_selected_line()
+ print "edit button clicked on:" + name
+ if ( self.is_vhost_editable( name ) == False ): return False
+ new_vhost_window = VirtualHostWindow ( self )
+ new_vhost_window.load( name )
+ new_vhost_window.run()
+ def delete_button_clicked( self, widget ):
+ name = self.vhosts_treeview.get_selected_line()
+ if ( self.is_vhost_editable( name ) == False ): return False
+ if ( name == None ): return False
+ result = ConfirmationWindow.ask_confirmation(
+ "You are about to delete the following domain: \n\n"+name+"\n\nData won't be recoverable. Proceed ?"
+ ,'VirtualHost deletion' )
+ if ( result != True ): return False
+ site = VirtualHostModel( name )
+ site.delete()
+ self.vhosts_treeview.load()
+ self.please_restart()
+ def edit_module_button_clicked(self, widget, notused = None, notused2 = None):
+ name = self.modules_treeview.get_selected_line()
+ if ( self.is_module_editable( name ) == False ): return False
+ print "module edit button clicked on:", name
+ module_window = ModuleWindow ( self )
+ module_window.load( name )
+ module_window.run()
+ def quit (self, widget):
+ print 'quitting'
+ gtk.main_quit()
+ exit()
+
+ def create_vhost_list(self ):
+ #print parent
+ #sw = gtk.ScrolledWindow()
+ sw = self.xml.get_widget( 'vhosts_scroll_box' )
+ # create virtualhosts treeview
+ treeview = VhostsTreeView.VhostsTreeView()
+ treeview.selected_callback = self.row_selected
+ treeview.connect_after("row-activated", self.edit_button_clicked )
+ self.vhosts_treeview = treeview
+ self.xml.get_widget( 'vhost_container' ).add(treeview)
+ self.xml.get_widget( 'vhost_container' ).reorder_child( treeview, 0)
+
+ sw.set_shadow_type(gtk.SHADOW_NONE)
+ sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ sw.set_shadow_type(gtk.SHADOW_NONE)
+ sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+
+ # create denormalized vhosts.
+ # We check for conf files only present in /etc/apache2/sites-enabled,
+ # display them as a separate list and offer user to normalize them
+ # moving them in /etc/apache2/sites-available and linking them back
+ # from /etc/apache2/sites-enabled
+
+ denormalized_treeview = VhostsTreeView.DenormalizedVhostsTreeView()
+ self.denormalized_treeview = denormalized_treeview
+ self.xml.get_widget( 'problems_area' ).add(denormalized_treeview)
+ self.xml.get_widget( 'problems_area' ).reorder_child( denormalized_treeview, 2)
+ denormalized_treeview.set_sensitive( False )
+ denormalized_treeview.show()
+ sw.show_all()
+ #hidden by default
+ self.xml.get_widget( 'unnormalized_notice' ).hide_all()
+
+ def create_modules_list(self ):
+ sw = self.xml.get_widget( 'modules_scroll_box' )
+ # create virtualhosts treeview
+ treeview = VhostsTreeView.ModulesTreeView()
+ treeview.connect_after("row-activated", self.edit_module_button_clicked )
+ treeview.selected_callback = self.module_row_selected
+ self.modules_treeview = treeview
+ self.xml.get_widget( 'modules_container' ).add(treeview)
+ self.xml.get_widget( 'modules_container' ).reorder_child( treeview, 0)
+ sw.set_shadow_type(gtk.SHADOW_NONE)
+ sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ sw.set_shadow_type(gtk.SHADOW_NONE)
+ sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
+ sw.show_all()
+
+ def refresh_vhosts ( self ):
+ print "reloading vhosts.."
+ self.vhosts_treeview.load()
+ def refresh_denormalized_vhosts (self):
+ self.denormalized_treeview.load()
+ if ( len( self.denormalized_treeview.items ) > 0 ):
+ self.xml.get_widget( 'unnormalized_notice' ).show_all()
+ self.xml.get_widget( 'notebook' ).get_nth_page( 2 ).show()
+ else:
+ self.xml.get_widget( 'unnormalized_notice' ).hide_all()
+ self.xml.get_widget( 'notebook' ).get_nth_page( 2 ).hide()
+ def refresh_modules (self):
+ print "reloading modules.."
+ self.modules_treeview.load()
+ def refresh_lists (self):
+ self.refresh_vhosts()
+ self.refresh_modules()
+ self.refresh_denormalized_vhosts()
+ def please_restart ( self ):
+ self.xml.get_widget( 'restart_apache_notice' ).show()
+ def restart_apache ( self, widget ):
+ print "Restarting apache on user's request"
+ Shell.command.sudo_execute( ['/etc/init.d/apache2', 'stop'] )
+ Shell.command.sudo_execute( ['/etc/init.d/apache2', 'start'] )
+ self.xml.get_widget( 'restart_apache_notice' ).hide()
+ self.refresh_lists()
+ def is_vhost_editable (self, name):
+ return name != 'default'
+ def is_module_editable (self, name):
+ editable = False
+ if name:
+ mod = self.modules_treeview.items[ name+".load" ]
+ editable = mod.data[ 'configurable' ]
+ return editable
+ def row_selected( self, widget ):
+ name = self.vhosts_treeview.get_selected_line()
+ if ( name == None ):
+ self.xml.get_widget( 'delete_button' ).set_sensitive( False )
+ self.xml.get_widget( 'edit_button' ).set_sensitive( False )
+ self.xml.get_widget( 'open_in_browser_button' ).set_sensitive( False )
+ else:
+ editable = self.is_vhost_editable( name )
+ self.xml.get_widget( 'delete_button' ).set_sensitive( editable )
+ self.xml.get_widget( 'edit_button' ).set_sensitive( editable )
+ surfable = self.get_current_vhost_directive( 'ServerName' ) != None
+ self.xml.get_widget( 'surf_this_button' ).set_sensitive( surfable )
+ browsable = self.get_current_vhost_directive( 'DocumentRoot' ) != None
+ self.xml.get_widget( 'browse_button' ).set_sensitive( browsable )
+ def module_row_selected( self, widget):
+ name = self.modules_treeview.get_selected_line()
+ editable = self.is_module_editable(name)
+ self.xml.get_widget( 'edit_module_button' ).set_sensitive( editable )
+ if name != None: self.xml.get_widget( 'open_doc_button' ).set_sensitive( True )
+ # TODO: open doc only for apache2.2 own modules, not third-party (eg mod_php5)
+ # TODO: sniff apache version, don't hardcode it
+ def open_doc_button_clicked( self, widget ):
+ name = self.modules_treeview.get_selected_line()
+ if ( name == None ): return False
+ open_module_doc(name)
+
+ def fix_vhosts(self, widget):
+ items = self.denormalized_treeview.get_items()
+ for name in items:
+ normalize_vhost( name )
+ #since they were in the enabled, let's enabl'em again
+ for name in items:
+ site = VirtualHostModel( name )
+ site.toggle(True)
+ self.refresh_vhosts()
+ self.refresh_denormalized_vhosts()
+ def get_current_vhost_directive (self, directive_name ):
+ name = self.vhosts_treeview.get_selected_line()
+ if ( name == None ): return None
+ return self.vhosts_treeview.items[ name ].data[ directive_name ]
+ def surf_this(self, widget):
+ name = self.vhosts_treeview.get_selected_line()
+ if name == 'default':
+ server_name = 'localhost'
+ else:
+ server_name = self.get_current_vhost_directive( 'ServerName' )
+ if ( server_name ): Desktop.open_url( "http://" + server_name )
+ def browse_this(self, widget):
+ document_root = self.get_current_vhost_directive( 'DocumentRoot' )
+ Desktop.open_dir( document_root )
+
+
+ def display_about (self, widget):
+ dialog = gtk.AboutDialog()
+ dialog.set_name( APPNAME )
+ dialog.set_version( APPVERSION )
+ dialog.set_authors( ["Rapache Developers\nhttps://launchpad.net/~rapache-devel"] )
+ dialog.set_comments('Rapache is an Apache configurator for Ubuntu/Gnome systems')
+ dialog.set_website('http://launchpad.net/rapache')
+ dialog.run()
+ dialog.destroy()
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/VhostsTreeView.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/VhostsTreeView.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/VhostsTreeView.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,237 @@
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import gtk
+import gobject
+from CheckListView import *
+import os
+import re
+from RapacheCore.VirtualHost import *
+from RapacheCore import Module
+from RapacheCore import Configuration
+
+class ConfFilesTreeView( CheckListView ):
+ def __init__ (self, *args, **kwargs):
+ super (ConfFilesTreeView, self).__init__ (*args, **kwargs)
+ self.items = {}
+ def _blacklisted ( self, fname ):
+ if re.match( '.*[~]\s*$', fname ) != None : return True
+ if re.match( '.*.swp$', fname ) != None : return True
+ return False
+ def is_empty (self):
+ return len( self.items ) == 0
+ def get_items(self):
+ return self.items
+gobject.type_register (ConfFilesTreeView)
+
+
+class VhostsTreeView ( ConfFilesTreeView ):
+ def __init__ (self, *args, **kwargs):
+ super (VhostsTreeView, self).__init__ (*args, **kwargs)
+ self.icon_callback = self.__get_row_icon
+ self.toggled_callback = self.__fixed_toggled
+
+
+ def load(self):
+ self.items = {}
+ site_template = "<b><big>%s</big></b>\n<small>DocumentRoot: %s</small>"
+ site_unparsable_template = "<b><big>%s</big></b>\n<small><i>Further information not available</i></small>"
+
+ lstore = self._reset_model()
+
+ data = []
+ dirList=os.listdir( Configuration.SITES_AVAILABLE_DIR )
+ dirList = [x for x in dirList if self._blacklisted( x ) == False ]
+ for fname in dirList :
+ site = VirtualHostModel( fname )
+ try:
+ site.load()
+ except "VhostUnparsable":
+ pass
+ self.items[ fname ] = site
+ site = None
+
+ for idx in sorted( self.items ):
+ site = self.items[ idx ]
+ if ( site.parsable ):
+ markup = site_template \
+ % ( site.data['name'] , site.data[ 'DocumentRoot' ] )
+ else:
+ markup = site_unparsable_template % site.data['name']
+ iter = lstore.append()
+ lstore.set(iter,
+ COLUMN_FIXED, site.data['enabled'],
+ COLUMN_SEVERITY, site.data['name'],
+ COLUMN_MARKUP, markup )
+
+ #TODO: warning ! This function get's called even on mousehover
+ # check for a way to optimize it
+ def __get_row_icon (self, column, cell, model, iter):
+ """ Provides the icon for a virtual host looking up it's favicon"""
+ """node = model.get_value(iter, MODEL_FIELD_NODE)
+ pixbuf = getPixbufForNode(node)
+ cell.set_property('pixbuf', pixbuf)"""
+ favicon = os.path.join( Configuration.GLADEPATH, 'browser.png' )
+ fname = model.get_value(iter, COLUMN_SEVERITY )
+ site = self.items[ fname ]
+ if site.data['DocumentRoot'] != None:
+ custom_favicon = os.path.join(os.path.dirname( site.data['DocumentRoot']+"/" ), "favicon.ico")
+ if ( os.path.exists( custom_favicon ) ): favicon = custom_favicon
+
+ pixbuf = gtk.gdk.pixbuf_new_from_file( favicon )
+ cell.set_property("pixbuf", pixbuf)
+
+ def __fixed_toggled(self, cell, path, treeview):
+ # get toggled iter
+ model = treeview.get_model()
+ iter = model.get_iter((int(path),))
+ fixed = model.get_value(iter, COLUMN_FIXED)
+ name = model.get_value(iter, COLUMN_SEVERITY)
+
+ fixed = not fixed
+ if fixed:
+ Shell.command.sudo_execute ( [Configuration.APPPATH+'/hosts-manager', '-a',name])
+ else :
+ Shell.command.sudo_execute ( [Configuration.APPPATH+'/hosts-manager', '-r',name])
+ # set new value
+ site = VirtualHostModel( name )
+ site.toggle( fixed )
+ model.set(iter, COLUMN_FIXED, site.data['enabled'] )
+ if ( site.changed ):
+ self.raise_event( 'please_restart_apache' )
+gobject.type_register (VhostsTreeView)
+
+class DenormalizedVhostsTreeView ( ConfFilesTreeView ):
+ def __init__ (self, *args, **kwargs):
+ super (DenormalizedVhostsTreeView, self).__init__ (*args, **kwargs)
+ print self.column_checkbox, self.column_description, self.column_icon
+ self.column_checkbox.set_visible( False )
+ self.column_icon.get_cell_renderers()[0].set_property( 'stock-id', gtk.STOCK_DIALOG_WARNING )
+ def load(self):
+ self.items = {}
+ site_template = "<b><big>%s</big></b>"
+ lstore = self._reset_model()
+
+ data = []
+ dirList=os.listdir( Configuration.SITES_ENABLED_DIR )
+ dirList = [x for x in dirList if self._blacklisted( x ) == False ]
+ dirList = [x for x in dirList if is_denormalized_vhost( x ) == False ]
+ for fname in dirList :
+ site = VirtualHostModel( fname )
+ self.items[ fname ] = site
+ site = None
+
+ for idx in sorted( self.items ):
+ site = self.items[ idx ]
+ normalizable = not is_not_normalizable(site.data['name'])
+ markup = site_template % site.data['name']
+ if ( normalizable == False ):
+ markup = markup + " CANNOT FIX"
+ iter = lstore.append()
+ lstore.set(iter,
+ COLUMN_FIXED, normalizable,
+ COLUMN_SEVERITY, site.data['name'],
+ COLUMN_MARKUP, markup
+ )
+ def toggled_callback(self, *args, **kwargs):
+ pass
+gobject.type_register (DenormalizedVhostsTreeView )
+
+class ModulesTreeView ( ConfFilesTreeView ):
+ def __init__ (self, *args, **kwargs):
+ super (ModulesTreeView, self).__init__ (*args, **kwargs)
+
+ icon_file_name = os.path.join( Configuration.GLADEPATH , "modules.png")
+ pixbuf = gtk.gdk.pixbuf_new_from_file( icon_file_name )
+
+ self.column_icon.get_cell_renderers()[0].set_property('pixbuf', pixbuf)
+ self.toggled_callback = self.__fixed_toggled
+ self.selected_callback = self.__selected
+ self.column_description.get_cell_renderers()[0].set_property('wrap-mode', gtk.WRAP_WORD)
+ self.column_description.get_cell_renderers()[0].set_property('wrap-width', 400)
+ def __selected(self, *args, **kwargs ):
+ print "MODULE NAME:", self.get_selected_line()
+ print "DEPENDANTS: ", Module.get_module_dependants(self.get_selected_line(), self.items)
+ def load(self):
+ self.items = {}
+ mod_template = "<b><big>%s</big></b>"
+ mod_unparsable_template = "<b><big>%s</big></b>\n<small><i>Further information not available</i></small>"
+ lstore = self._reset_model()
+ data = []
+
+ """dirList=os.listdir( Configuration.MODS_AVAILABLE_DIR )
+ dirList = [x for x in dirList if self._blacklisted( x ) == False ]
+ for fname in dirList :
+ mod = Module.ModuleModel( fname )
+ try:
+ mod.load()
+ except "VhostUnparsable":
+ pass
+ self.items[ fname ] = mod
+ mod = None
+ """
+ self.items = Module.module_list()
+
+ for idx in sorted( self.items ):
+ mod = self.items[ idx ]
+ if ( mod.parsable ):
+ markup = mod_template \
+ % ( mod.data['name'] ) #, mod.data[ 'DocumentRoot' ] )
+ markup += "\n<small>%s</small>" % mod.data[ 'description' ]
+ if len( mod.data[ 'dependancies' ] ) > 0:
+ markup += "\n<small><b>%s</b></small>" % ( "Dependencies: " + \
+ ", ".join( mod.data[ 'dependancies' ] ) )
+ else:
+ markup += "\n<small><i>No dependencies</i></small>"
+ else:
+ markup = mod_unparsable_template % mod.data['name']
+ iter = lstore.append()
+ lstore.set(iter,
+ COLUMN_FIXED, mod.data['enabled'],
+ COLUMN_SEVERITY, mod.data['name'],
+ COLUMN_MARKUP, markup )
+
+ def __fixed_toggled(self, cell, path, treeview):
+ # get toggled iter
+ model = treeview.get_model()
+ iter = model.get_iter((int(path),))
+ fixed = model.get_value(iter, COLUMN_FIXED)
+ name = model.get_value(iter, COLUMN_SEVERITY)
+ fixed = not fixed
+ # set new value
+ mod = Module.ModuleModel( name )
+ mod.toggle( fixed )
+ model.set(iter, COLUMN_FIXED, mod.data['enabled'] )
+ if ( mod.changed ):
+ self.raise_event( 'please_restart_apache' )
+ self.raise_event( 'please_reload_lists', {}, True )
+ #TODO: warning ! This function get's called even on mousehover
+ # check for a way to optimize it
+ def __get_row_icon (self, column, cell, model, iter):
+ """ Provides the icon for a module"""
+ """node = model.get_value(iter, MODEL_FIELD_NODE)
+ pixbuf = getPixbufForNode(node)
+ cell.set_property('pixbuf', pixbuf)"""
+ favicon = os.path.join( Configuration.GLADEPATH, 'browser.png' )
+ fname = model.get_value(iter, COLUMN_SEVERITY )
+ site = self.items[ fname ]
+ if site.data['DocumentRoot'] != None:
+ custom_favicon = os.path.join(os.path.dirname( site.data['DocumentRoot']+"/" ), "favicon.ico")
+ if ( os.path.exists( custom_favicon ) ): favicon = custom_favicon
+
+ pixbuf = gtk.gdk.pixbuf_new_from_file( favicon )
+ cell.set_property("pixbuf", pixbuf)
+gobject.type_register ( ModulesTreeView )
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/VirtualHostGui.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/VirtualHostGui.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/VirtualHostGui.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,295 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+""".
+Issues with the new window:
+ - self.parent doesn't work
+ - onblur doesn't trigger when pressing Return
+ - changing a domain name doesn't change subdomains
+ - empty server aliases shuoldn't be managed
+ALSO:
+ - please implement a delete directive func in the parser
+ - move denorm. vhosts in another tab
+ - merge with Qense warning window
+"""
+
+import sys
+import re
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+import os
+import pango
+import tempfile
+import traceback
+import RapacheGtk.GuiUtils
+from RapacheCore.VirtualHost import *
+from RapacheGtk import GuiUtils
+from EditDomainNameGui import EditDomainNameWindow
+
+class VirtualHostWindow:
+
+ def __init__ ( self, parent = None):
+
+ self.vhost = None
+ self.create_new = True
+ self.parent = parent
+ self.plugins = []
+
+ gladefile = os.path.join(Configuration.GLADEPATH, "edit_vhost.glade")
+ wtree = gtk.glade.XML(gladefile)
+
+ self.window = wtree.get_widget("dialog_edit_vhost")
+ self.entry_domain = wtree.get_widget("entry_domain")
+ self.entry_location = wtree.get_widget("entry_location")
+ self.button_location = wtree.get_widget("button_location")
+ self.treeview_domain = wtree.get_widget("treeview_domain")
+ self.checkbutton_hosts = wtree.get_widget("checkbutton_hosts")
+ self.toolbutton_domain_add = wtree.get_widget("toolbutton_domain_add")
+ self.toolbutton_domain_edit = wtree.get_widget("toolbutton_domain_edit")
+ self.toolbutton_domain_delete = wtree.get_widget("toolbutton_domain_delete")
+ self.notebook = wtree.get_widget("notebook")
+ self.button_save = wtree.get_widget("button_save")
+ self.error_area = wtree.get_widget("error_area")
+ signals = {
+ "on_toolbutton_domain_add_clicked" : self.on_toolbutton_domain_add_clicked,
+ "on_toolbutton_domain_edit_clicked" : self.on_toolbutton_domain_edit_clicked,
+ "on_toolbutton_domain_delete_clicked" : self.on_toolbutton_domain_delete_clicked,
+ "on_button_save_clicked" : self.on_button_save_clicked,
+ "on_button_cancel_clicked" : self.on_button_cancel_clicked,
+ "on_entry_domain_changed" : self.on_entry_domain_changed,
+ "on_button_location_clicked" : self.on_button_location_clicked,
+ "on_entry_domain_focus_out_event" : self.on_entry_domain_focus_out_event,
+ "on_button_location_clear_clicked" : self.on_button_location_clear_clicked
+ }
+ wtree.signal_autoconnect(signals)
+
+ self.text_view_vhost_source = GuiUtils.new_apache_sourceview()
+ wtree.get_widget( 'text_view_vhost_source_area' ).add( self.text_view_vhost_source )
+ self.text_view_vhost_source.set_editable( False )
+ self.text_view_vhost_source.show()
+
+ self.notebook.get_nth_page( 1 ).hide()
+ self.notebook.get_nth_page( 2 ).hide()
+
+ # add on destroy to quit loop
+ self.window.connect("destroy", self.on_destroy)
+
+ # Setup tree
+ column = gtk.TreeViewColumn(('Domains'))
+ column.set_spacing(4)
+ cell = gtk.CellRendererText()
+ column.pack_start(cell, True)
+ column.set_attributes(cell, markup=0)
+ self.treeview_domain.append_column(column)
+
+ self.treeview_domain_store = gtk.ListStore(str, object)
+ self.treeview_domain.set_model(self.treeview_domain_store)
+
+ GuiUtils.style_as_tooltip( self.error_area )
+ self.on_entry_domain_changed()
+
+ def run(self):
+
+ # Load UI Plugins
+ if self.vhost:
+ site = self.vhost
+ else:
+ # load default
+ site = VirtualHostModel( "", self.parent.plugin_manager)
+
+ for plugin in self.parent.plugin_manager.plugins:
+ try:
+ if plugin.is_enabled():
+ plugin.load_vhost_properties(self.notebook, site.data)
+ self.plugins.append(plugin)
+ except Exception:
+ traceback.print_exc(file=sys.stdout)
+
+ self.window.show()
+ gtk.main()
+
+ def load (self, name ):
+ self.vhost = VirtualHostModel( name )
+ self.create_new = False
+ try:
+ self.vhost.load(False, self.parent.plugin_manager)
+ print self.vhost.data
+ #self._get( 'has_www' ).set_active( site.data[ 'has_www' ] )
+ server_name = self.vhost.data[ 'ServerName' ]
+ if ( server_name != None ):
+ self.entry_domain.set_text( server_name )
+ document_root = self.vhost.data[ 'DocumentRoot' ]
+ if ( document_root != None ):
+ self.entry_location.set_text( document_root )
+ server_alias = self.vhost.data[ 'ServerAlias' ]
+ if ( server_alias != None ):
+ for domain in server_alias:
+ self.treeview_domain_store.append((domain, None))
+ print self.vhost.data
+ except "VhostUnparsable":
+ pass
+
+ buf = self.text_view_vhost_source.get_buffer()
+ buf.set_text( self.vhost.get_source() )
+
+
+
+ def get_domain (self):
+ return self.entry_domain.get_text().strip()
+ #url.lower().startswith('http://')
+ #url[7:]
+ def set_default_values_from_domain(self, force_domain=False):
+ domain = self.get_domain()
+
+ # auto set the location
+ if domain and (not self.entry_location.get_text() or force_domain):
+ self.entry_location.set_text( "/srv/www/%s" % (domain +"/httpdocs" ))
+ if force_domain and not domain:
+ self.entry_location.set_text("")
+
+ # auto create a www entry
+ #if not force_domain and domain and len(self.treeview_domain_store) == 0 and not domain.startswith("www"):
+ # self.treeview_domain_store.append(("www." + domain, None))
+
+ def on_entry_domain_focus_out_event(self, widget, opt):
+ self.set_default_values_from_domain()
+
+ def on_entry_domain_changed(self, unused_widget = None):
+ widget = self.entry_domain
+ name = widget.get_text()
+ if ( valid_domain_name( name ) ):
+ self.button_save.set_sensitive(True);
+ #if self.create_new :
+ # self.xml.get_widget( 'default_folder' ).set_text( '/srv/www/'+name+'/httpdocs' )
+ else:
+ self.button_save.set_sensitive(False);
+
+ def on_button_location_clear_clicked(self, widget):
+ self.set_default_values_from_domain(True)
+
+
+ def on_button_location_clicked(self, widget):
+ chooser = gtk.FileChooserDialog(
+ title=None,
+ action=gtk.FILE_CHOOSER_ACTION_CREATE_FOLDER,
+ buttons=(gtk.STOCK_CANCEL,
+ gtk.RESPONSE_CANCEL,
+ gtk.STOCK_OPEN,
+ gtk.RESPONSE_OK))
+
+ location = self.entry_location.get_text().strip()
+ if not location:
+ location = "/srv/www"
+ chooser.set_current_folder(location)
+ response = chooser.run()
+
+ if response == gtk.RESPONSE_OK:
+ self.entry_location.set_text( chooser.get_filename() )
+ chooser.destroy()
+
+ def on_destroy(self, widget, data=None):
+ gtk.main_quit()
+
+ def on_toolbutton_domain_add_clicked(self, widget):
+ edw = EditDomainNameWindow(self.entry_domain.get_text().strip())
+ domain = edw.run()
+ if domain:
+ self.treeview_domain_store.append((domain, None))
+ return
+ def get_server_aliases_list (self ):
+ aliases = []
+ for row in self.treeview_domain_store: aliases.append( row[0] )
+ return aliases
+ def on_toolbutton_domain_edit_clicked(self, widget):
+
+ model, iter = self.treeview_domain.get_selection().get_selected()
+ if not iter: return
+ domain = model.get_value(iter, 0)
+ print domain
+ edw = EditDomainNameWindow( domain )
+ result = edw.run()
+ if result:
+ self.treeview_domain_store.set_value(iter, 0, edw.return_value)
+ return
+
+ def on_toolbutton_domain_delete_clicked(self, widget):
+ model, iter = self.treeview_domain.get_selection().get_selected()
+ if not iter: return
+ self.treeview_domain_store.remove(iter)
+ return
+
+ def on_button_save_clicked(self, widget):
+ if self.entry_location.get_text() == "" and self.create_new:
+ self.set_default_values_from_domain( True )
+
+ options = {}
+ options[ 'ServerAlias' ] = []
+ options[ 'ServerName' ] = self.entry_domain.get_text()
+ options[ 'hack_hosts' ] = self.checkbutton_hosts.get_active()
+ options[ 'DocumentRoot' ] = self.entry_location.get_text()
+ options[ 'ServerAlias' ] = self.get_server_aliases_list()
+
+ # Save plugins
+ if self.plugins:
+ for plugin in self.plugins:
+ try:
+ if plugin.is_enabled():
+ plugin.save_vhost_properties(options)
+ except Exception:
+ traceback.print_exc(file=sys.stdout)
+
+ print options
+
+ try:
+ if ( self.create_new ):
+ site = VirtualHostModel( options[ 'ServerName' ] )
+ site.create ( options )
+ else:
+ name = self.vhost.data['name']
+ print "Current name:", name
+ site = VirtualHostModel( name )
+ site.update( options, name )
+
+
+ #self.parent.create_vhost_list()
+ self.parent.refresh_vhosts()
+ self.parent.please_restart()
+ self.window.destroy()
+ except "VhostExists":
+ print "========================"
+ self.show_error( "A virtual host with the same name already exists" )
+
+
+ def on_button_cancel_clicked(self, widget):
+ self.window.destroy()
+ return
+ def show_error ( self, message ):
+
+ self.xml.get_widget( 'message_text' ).set_label( '<b>'+message+'</b>' )
+ self.xml.get_widget( 'message_container' ).show()
+
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/WarningWindow.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/WarningWindow.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/WarningWindow.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+import os
+import gnome.ui
+
+from RapacheGtk import GuiUtils
+from RapacheCore import Configuration
+
+class WarningWindow:
+ """The Rapache warning window"""
+
+ def __init__(self, warning, father = None):
+ self.father = father
+ self.gladefile = Configuration.GLADEPATH + "/" + "warning_dialog.glade"
+ print self.gladefile
+ self.xml = gtk.glade.XML(self.gladefile)
+ #Create our dictionary and connect it
+ dic = {
+ "quit" : gtk.main_quit
+ , "on_ok" : gtk.main_quit
+ }
+ self.xml.signal_autoconnect(dic)
+ self.xml.get_widget( 'label1' ).set_label ( warning )
+
+
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/__init__.py'
=== added file 'build/lib.linux-x86_64-2.6/RapacheGtk/old_VirtualHostGui.py'
--- build/lib.linux-x86_64-2.6/RapacheGtk/old_VirtualHostGui.py 1970-01-01 00:00:00 +0000
+++ build/lib.linux-x86_64-2.6/RapacheGtk/old_VirtualHostGui.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import re
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+import os
+import pango
+import tempfile
+
+from RapacheCore.VirtualHost import *
+from RapacheGtk import GuiUtils
+
+class VirtualHostWindow:
+
+ create_new = True
+ name = None
+
+ def __init__ ( self, father = None):
+ self.father = father
+ self.gladefile = Configuration.GLADEPATH + "/" + "edit_vhost.glade"
+ self.xml = gtk.glade.XML(self.gladefile)
+ #Create our dictionary and connect it
+ dic = {
+ "quit" : self.quit
+ , "on_ok":self.save
+ , "on_cancel":self.close
+ , "domain_name_updated":self.domain_name_updated
+ , "custom_folder_toggled":self.custom_folder_toggled
+ }
+ self.xml.signal_autoconnect(dic)
+ self.xml.get_widget( 'custom_folder' ).set_action ( gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER )
+ font_desc = pango.FontDescription('monospace')
+ self.xml.get_widget( 'vhost_source' ).modify_font(font_desc)
+ GuiUtils.style_as_tooltip( self.xml.get_widget( 'message_container' ) )
+
+ def load (self, name ):
+
+ site = VirtualHostModel( name )
+ self.create_new = False
+ self.name = name
+ self._get( 'create_hosts_entry' ).hide()
+ self._get( 'create_hosts_label' ).hide()
+ try:
+ site.load()
+ self._get( 'has_www' ).set_active( site.data[ 'has_www' ] )
+ self._get( 'domain_name' ).set_text( site.data[ 'ServerName' ] )
+ self._get( 'default_folder' ).set_text( site.data[ 'DocumentRoot' ] )
+ self.xml.get_widget( 'ok_button' ).set_sensitive(True);
+ except "VhostUnparsable":
+ self._get( 'notebook' ).get_nth_page( 0 ).hide()
+ buffer = self.xml.get_widget( 'vhost_source' ).get_buffer()
+ buffer.set_text( site.get_source() )
+ def _get(self, id ):
+ return self.xml.get_widget( id )
+
+
+ def error ( self, message ):
+ self.xml.get_widget( 'message_text' ).set_label( '<b>'+message+'</b>' )
+ self.xml.get_widget( 'message_container' ).show()
+
+ def quit (self, widget):
+ self.father.new_vhost_window = None
+
+ def close ( self, widget = None ):
+ self.window = self.xml.get_widget( 'vhost_edit_window' )
+ self.window.destroy()
+ def domain_name_updated ( self, widget, a = None, b = None, c = None ):
+ name = widget.get_text()
+ if ( valid_domain_name( name ) ):
+ self.xml.get_widget( 'ok_button' ).set_sensitive(True);
+ if self.create_new :
+ self.xml.get_widget( 'default_folder' ).set_text( '/var/www/'+name+'/httpdocs' )
+ else:
+ self.xml.get_widget( 'ok_button' ).set_sensitive(False);
+ def custom_folder_toggled( self, widget ):
+ if ( widget.get_active() == True ):
+ self.xml.get_widget( 'custom_folder' ).show()
+ self.xml.get_widget( 'default_folder' ).hide()
+ else:
+ self.xml.get_widget( 'custom_folder' ).hide()
+ self.xml.get_widget( 'default_folder' ).show()
+
+
+ def save( self, widget ):
+ options = {}
+ options[ 'has_www' ] = self.xml.get_widget( 'has_www' ).get_active()
+ options[ 'domain_name' ] = ( self.xml.get_widget( 'domain_name' ).get_text() )
+ options[ 'hack_hosts' ] = self.xml.get_widget( 'create_hosts_entry' ).get_active()
+ if self.xml.get_widget( 'set_custom_folder' ).get_active():
+ DocumentRoot = self.xml.get_widget( 'custom_folder' ).get_filename ()
+ else:
+ DocumentRoot = self.xml.get_widget( 'default_folder' ).get_text()
+ options[ 'DocumentRoot' ] = DocumentRoot
+
+
+ try:
+ if ( self.create_new ):
+ site = VirtualHostModel( options[ 'domain_name' ] )
+ site.create ( options )
+ else:
+ print "Current name:", self.name
+ site = VirtualHostModel( self.name )
+ site.update( options, self.name )
+
+ self.father.refresh_vhosts()
+ self.father.please_restart()
+ self.close()
+ except "VhostExists":
+ print "========================"
+ self.error( "A virtual host with the same name already exists" )
+
+
+ return True
=== added directory 'build/scripts-2.6'
=== added file 'build/scripts-2.6/hosts-manager'
--- build/scripts-2.6/hosts-manager 1970-01-01 00:00:00 +0000
+++ build/scripts-2.6/hosts-manager 2010-05-16 16:14:24 +0000
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from RapacheCore.HostsManager import HostsManager
+
+if __name__ == "__main__":
+ HostsManager( True )
\ No newline at end of file
=== added file 'build/scripts-2.6/rapache'
--- build/scripts-2.6/rapache 1970-01-01 00:00:00 +0000
+++ build/scripts-2.6/rapache 2010-05-16 16:14:24 +0000
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import os.path
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+import os
+
+from RapacheGtk.RapacheGui import MainWindow
+from RapacheGtk.WarningWindow import WarningWindow
+from RapacheCore import Configuration
+
+
+if __name__ == "__main__":
+ current_path = os.path.abspath(os.path.dirname(__file__))
+ if ( os.path.exists( current_path+"/RapacheCore" ) ):
+ #self-contained mode
+ Configuration.APPPATH = os.path.abspath(os.path.dirname(__file__))
+ Configuration.GLADEPATH = Configuration.APPPATH + "/Glade"
+
+ if( os.path.isdir( Configuration.SITES_AVAILABLE_DIR ) and os.path.isdir( Configuration.SITES_ENABLED_DIR )):
+ hwg = MainWindow()
+ gtk.main()
+ else:
+ ww = WarningWindow("Apache isn't installed. Rapache has nothing to manage.")
+ gtk.main()
=== added directory 'data'
=== renamed directory 'data' => 'data.moved'
=== added file 'data/rapache.desktop'
--- data/rapache.desktop 1970-01-01 00:00:00 +0000
+++ data/rapache.desktop 2010-05-16 16:14:24 +0000
@@ -0,0 +1,9 @@
+[Desktop Entry]
+Name=rapache
+Comment=Simple tool for managing and configuring an apache2 instance
+TryExec=rapache
+Exec=rapache
+Icon=/usr/share/rapache/Glade/icon_cadsoft_eagle.svg
+Type=Application
+Categories=GNOME;GTK;Settings;DesktopSettings;
+
=== added file 'hosts-manager'
--- hosts-manager 1970-01-01 00:00:00 +0000
+++ hosts-manager 2010-05-16 16:14:24 +0000
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from RapacheCore.HostsManager import HostsManager
+
+if __name__ == "__main__":
+ HostsManager( True )
\ No newline at end of file
=== renamed file 'hosts-manager' => 'hosts-manager.moved'
=== added file 'rapache'
--- rapache 1970-01-01 00:00:00 +0000
+++ rapache 2010-05-16 16:14:24 +0000
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import os.path
+
+try:
+ import pygtk
+ pygtk.require("2.0")
+except:
+ pass
+try:
+ import gtk
+ import gtk.glade
+except:
+ sys.exit(1)
+
+import os
+
+from RapacheGtk.RapacheGui import MainWindow
+from RapacheGtk.WarningWindow import WarningWindow
+from RapacheCore import Configuration
+
+
+if __name__ == "__main__":
+ current_path = os.path.abspath(os.path.dirname(__file__))
+ if ( os.path.exists( current_path+"/RapacheCore" ) ):
+ #self-contained mode
+ Configuration.APPPATH = os.path.abspath(os.path.dirname(__file__))
+ Configuration.GLADEPATH = Configuration.APPPATH + "/Glade"
+
+ if( os.path.isdir( Configuration.SITES_AVAILABLE_DIR ) and os.path.isdir( Configuration.SITES_ENABLED_DIR )):
+ hwg = MainWindow()
+ gtk.main()
+ else:
+ ww = WarningWindow("Apache isn't installed. Rapache has nothing to manage.")
+ gtk.main()
=== renamed file 'rapache' => 'rapache.moved'
=== added file 'setup.py'
--- setup.py 1970-01-01 00:00:00 +0000
+++ setup.py 2010-05-16 16:14:24 +0000
@@ -0,0 +1,38 @@
+#!/usr/bin/python
+
+# Rapache - Apache Configuration Tool
+# Copyright (C) 2008 Stefano Forenza, Jason Taylor, Emanuele Gentili
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import subprocess, glob, os.path
+from os import path
+from distutils.core import setup
+setup(
+ name='rapache',
+ author='Rapache Developers',
+ author_email='rapache-devel@xxxxxxxxxxxxxxxxxxx',
+ maintainer='Emanuele Gentili',
+ maintainer_email='emgent@xxxxxxxxxx',
+ description='Simple tool for managing and configuring an apache2 instance',
+ url = 'http://www.rapache.org',
+ license='GNU GPL',
+ packages=['RapacheCore', 'RapacheGtk'],
+ scripts=['rapache', 'hosts-manager'],
+ data_files=[
+ ('/usr/share/rapache/Glade', glob.glob('Glade/*')),
+ ('/usr/share/applications', ['data/rapache.desktop']),
+ ],
+ )
+
=== renamed file 'setup.py' => 'setup.py.moved'
Follow ups