diff --git a/INSTALL b/INSTALL deleted file mode 100755 index 1dc018c..0000000 --- a/INSTALL +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash - -echo -e "\nWill install Pyrite application files to /usr/share/pyrite/" -echo "Enter to accept; otherwise enter a different dir, e.g., /home/$USER/.local/share/pyrite/" -read -p "[/usr/share/pyrite]: " install_dir -[[ -z $install_dir ]] && install_dir=/usr/share/pyrite || install_dir=${install_dir%/} -if [[ -d $install_dir ]]; then - echo "Directory '$install_dir' already exists." - echo "All files in directory will be deleted prior to copying new pyrite files." - read -p "Continue? [y/n] " - [[ $REPLY != y ]] && exit -else - if ! mkdir -vp "$install_dir"; then - echo "Could not create directory '$install_dir'" - if [[ ! -w ${install_dir%/*} ]]; then - echo "Need write permission to mkdir in '${install_dir%/*}'" - echo "Re-run this script as root, i.e., 'sudo $0' or 'su -c $0'" - fi - exit 1 - fi -fi -echo OK - - -echo -e "\nWill install a shortcut ('pyrite') to /usr/bin/" -echo "Press Enter to accept; otherwise enter a different dir, e.g., /home/$USER/bin/" -read -p "[/usr/bin/]: " bin_dir -[[ -z $bin_dir ]] && bin_dir=/usr/bin -if [[ ! -w $bin_dir ]]; then - echo "Need write permission to create shortcut in '$bin_dir'" - echo "Re-run this script as root, i.e., 'sudo $0' or 'su -c $0'" - exit 2 -fi -echo OK - - -echo -e "\nWill install a desktop shortcut ('pyrite.desktop') to /usr/share/applications/" -echo "Press Enter to accept; otherwise enter a different dir, e.g., /home/$USER/.local/share/applications/" -read -p "[/usr/share/applications/]: " shortcut_dir -[[ -z $shortcut_dir ]] && shortcut_dir=/usr/share/applications -if [[ ! -w $shortcut_dir ]]; then - echo "Need write permission to create desktop shortcut in '$shortcut_dir'" - echo "Re-run this script as root, i.e., 'sudo $0' or 'su -c $0'" - exit 3 -fi -echo OK - - -echo -e "\nReady to copy files. Last chance to cancel with Ctrl-c. Enter to continue." -read -p ": " - -# Remove contents of install dir (usually /usr/share/pyrite/) -rm -r "$install_dir"/* 2>/dev/null - -# Copy files to install dir -cp -rv --preserve=mode,timestamps modules ui pyrite.py "$install_dir" - -# Modify assetdir variable in cfg.py to point to the proper install dir -sed -i "/^ASSETDIR/s,'.*','$install_dir/'," "$install_dir/modules/cfg.py" - -# Copy desktop shortcut -cp -v --preserve=mode,timestamps pyrite.desktop "$shortcut_dir" - -# Setup cmdline shortcut -echo -e "\nCreating shortcut $bin_dir/pyrite: " -cat >$bin_dir/pyrite < + 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. + + + Copyright (C) + + This program is free software: you can 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 . + +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: + + Copyright (C) + 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 +. + + 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 +. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d1a451c --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +install: + DESTDIR=$(DESTDIR) ./INSTALL.sh +uninsall: + rm -rf "$(DESTDIR)/usr/share/pyrite/ui" + rm -rf "$(DESTDIR)/usr/lib/python3/dist-packages/pyrite" + rm -f "$(DESTDIR)/usr/share/applications/pyrite.desktop" + rm -f "$(DESTDIR)/usr/share/icons/hicolor/scalable/apps/pyrite.svg" + rm -f "$(DESTDIR)/usr/bin/pyrite" diff --git a/README.md b/README.md index f401e6b..d86c109 100644 --- a/README.md +++ b/README.md @@ -3,52 +3,68 @@ Pyrite - Python/GTK+ encryption/signing frontend for GnuPG and OpenSSL ![](http://b19.org/linux/pyrite/1enc_txt.png) +## FEATURES -FEDORA/RHEL7 INSTALLATION -------------------------- -There's an RPM (and yum repository) @ [people.redhat.com/rsawhill/rpms](http://people.redhat.com/rsawhill/rpms/). To configure it and install Pyrite, simply run the following as root: +Pyrite acts as a frontend for GnuPG, doing symmetric or asymmetric encrypting/decrypting, as well as signing and verifying. +Additionally, it can use OpenSSL for simple symmetric encryption/decryption. + +Pyrite can operate on text input or can take input and output filenames (text or binary) to pass directly to the backend program (i.e., gpg or openssl). + +As you can see from the screenshots, Pyrite can utilize virtually all the encrypting features of GnuPG -- you can mix and match passphrase & public-key encryption & signing with one file, just like gpg, which will require interacting with your gpg-agent. +Or you can keep it simple and just use a passphrase as a shared key, in which case gpg-agent is bypassed and you only have to type the passphrase once. + +Also shown in the screenshots is a Sign/Verify mode, where you can choose between the three types of signing: normal (Pyrite calls it "embedded"), where a signed copy of the message is created; clearsign, where the message is wrapped with a plaintext ASCII sig; or detached-sign, where a separate sig file is created. + +If you're operating directly on files (in sign or encrypt mode) instead of ASCII text in the Pyrite window, you can choose what kind of output you want -- ASCII-armored (base64-encoded) text or normal binary output. + +Not shown in the screenshots is drag & drop. You can drag text files onto the Message area and they are loaded up and you can drag text or binary files onto the *Input File For Direct Operation* button to set that. + +If you end up working on very large input, you'll get a chance to *really* see the progress bar + pause/cancel buttons. +At the moment the progress bar doesn't report actual progress (that's coming), but the buttons do what they advertise, pausing or canceling the backend processing. + +To top it all off, everything is configurable. +There's a preferences dialog that lets you play with all the settings, from tweaking gpg verbosity to setting the default operating mode to choosing your favorite cipher to configuring font size/color and window opacity. + +If you find yourself wondering about a particular feature, just hover your mouse over its widget -- there are detailed tooltips for everything. + + +## FEDORA/RHEL7 INSTALLATION +There's an RPM (and yum repository) @ [people.redhat.com/rsawhill/rpms](https://people.redhat.com/rsawhill/rpms/). To configure it and install Pyrite, simply run the following as root: ``` -yum install http://people.redhat.com/rsawhill/rpms/latest-rsawaroha-release.rpm +yum install https://people.redhat.com/rsawhill/rpms/latest-rsawaroha-release.rpm yum install pyrite ``` Requirements and package names: -- gtk2 >= v2.24: `gtk2` -- python2 >= v2.7: `python` -- pygtk: `pygtk2` -- gpg/openssl: `gnupg2` or `gnupg` or `openssl` - -*As per above, Pyrite is not compatible with RHEL6.* +- GTK3: `gtk3` +- Python3: `python3` +- `python3-gi`, `python3-gi-cairo` +- PGP `gnupg` or OpenSSL `openssl` -DEBIAN/UBUNTU/OTHER LINUX INSTALLATION --------------------------------------- -There is a simple interactive shell installer. Before using it, ensure you have the following on your Linux system (Ubuntu package names): +## DEBIAN/UBUNTU/OTHER LINUX INSTALLATION -- gtk2 >= v2.24: `libgtk2.0-bin` -- python2 >= v2.7: `python` -- pygtk: `python-gtk2` -- gpg/openssl: `gnupg2` or (`gnupg` and `gnupg-agent`) or `openssl` +There is a simple interactive shell installer. -If requirements are met, clone the Pyrite repo with `git clone git://github.com/ryran/pyrite.git` **OR** [download a zip of the source](https://github.com/ryran/pyrite/archive/master.zip). +If requirements are met, clone the Pyrite repo with `git clone https://github.com/ryran/pyrite.git` **OR** [download a zip of the source](https://github.com/ryran/pyrite/archive/master.zip). From the root source folder execute the interactive `INSTALL` script. -MORE SCREENSHOTS (v1.0.1): -------------------------------- +## MORE SCREENSHOTS (v1.0.1): + ![](http://b19.org/linux/pyrite/2clearsign_txt.png) ![](http://b19.org/linux/pyrite/3enc_prog.png) ![](http://b19.org/linux/pyrite/4dec_txt.png) ![](http://b19.org/linux/pyrite/5openssl_txt.png) ![](http://b19.org/linux/pyrite/6prefs.png) -**`pyrite` command-line options:** +## `pyrite` command-line options +Type `pyrite --help`: ``` -[rsaw:~]$ pyrite --help usage: pyrite [-h] [-d | -t] [-e | -s] [-c] [-r RECIP] [-k KEYUID] [-b {gpg,openssl}] [INPUT] @@ -75,48 +91,16 @@ optional arguments: ``` -FEATURES ----------- -Pyrite acts as a frontend for GnuPG, doing symmetric or asymmetric encrypting/decrypting, as well as signing and verifying. Additionally, it can use OpenSSL for simple symmetric encryption/decryption. - -Pyrite can operate on text input or can take input and output filenames (text or binary) to pass directly to the backend program (i.e., gpg/gpg2 or openssl). - -As you can see from the screenshots, Pyrite can utilize virtually all of the encrypting features of GnuPG -- you can mix and match passphrase & public-key encryption & signing with one file, just like gpg, which will require interacting with your gpg-agent. Or you can keep it simple and just use a passphrase as a shared key, in which case gpg-agent is bypassed and you only have to type the passphrase once. - -Also shown in the screenshots is a Sign/Verify mode, where you can choose between the three types of signing: normal (Pyrite calls it "embedded"), where a signed copy of the message is created; clearsign, where the message is wrapped with a plaintext ASCII sig; or detached-sign, where a separate sig file is created. - -If you're operating directly on files (in sign or encrypt mode) instead of ASCII text in the Pyrite window, you can choose what kind of output you want -- ASCII-armored (base64-encoded) text or normal binary output. - -Not shown in the screenshots is drag & drop. You can drag text files onto the Message area and they are loaded up and you can drag text or binary files onto the *Input File For Direct Operation* button to set that. - -If you end up working on very large input, you'll get a chance to *really* see the progress bar + pause/cancel buttons. At the moment the progress bar doesn't report actual progress (that's coming), but the buttons do what they advertise, pausing or canceling the backend processing. - -To top it all off, everything is configurable. There's a preferences dialog that lets you play with all the settings, from tweaking gpg verbosity to setting the default operating mode to choosing your favorite cipher to configuring font size/color and window opacity. - -If you find yourself wondering about a particular feature, just hover your mouse over its widget -- there are detailed tooltips for everything. - +## BUGS and TODO -BUGS ----------- -1) After launching Pyrite, the **first** drag/drop of a file onto the *Input File For Direct Operation* GtkFileChooserButton fails. After that the button works properly. I've been seeking out expertise on this weird bug but I haven't gotten anywhere. If you have any hints, hit me up, or check out [my post about it on stackoverflow](http://stackoverflow.com/questions/9047844/pygtk-troubles-with-drag-and-drop-file-to-gtkfilechooserbutton). - -2) No undo. It wasn't a top priority at the beginning, but I think it's pretty essential for an application that basically contains a text editor to have an undo/redo stack. I'll do it eventually. - - -BACKGROUND ----------- - -The original goal of this project was to make symmetric {en,de}cryption more accessible and easy to use. While GPG rocks if you're comfortable on the commandline (for both symmetric & public-key), and there are GUI encryption options for public-key encryption (seahorse-plugins for nautilus being the best, in my opinion), there's not much out there for people who need to do the simplest kind of encryption -- with a shared passphrase. - -After creating a few simple apps with BASH scripting, I decided it was time to learn Python. After the first few days I was in love. - -Long story short, after a couple weeks of learning, I released my first version of this project in January 2012, quickly added public-key encryption, signing, & verifying, and have been improving it ever since. This being my first learning experience with GTK+, I have lots more to learn, but I'm damn proud of Pyrite. +- No undo. It wasn't a top priority at the beginning, but I think it's pretty essential for an application that basically contains a text editor to have an undo/redo stack. I'll do it eventually. +- Icons for encrypt, decrypt, sign, verify buttons, application +- Update notifications PLEASE contact me (or [post a new issue on the tracker](/ryran/pyrite/issues)) with any suggestions, feedback, bug reports, or questions! -AUTHORS -------- +## AUTHORS As far as direct contributions go, so far it's just me, [ryran](/ryran), aka rsaw, aka [Ryan Sawhill Aroha](http://b19.org). @@ -125,8 +109,7 @@ The project could really use a little assistance from an artist -- it doesn't ha -LICENSE -------- +## LICENSE Copyright (C) 2012, 2013 [Ryan Sawhill Aroha](http://b19.org) @@ -138,19 +121,17 @@ the Free Software Foundation, either version 3 of the License, or This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License @[gnu.org/licenses/gpl.html](http://gnu.org/licenses/gpl.html>) for more details. - - +General Public License @[gnu.org/licenses/gpl.html](https://gnu.org/licenses/gpl.html>) for more details. -------- - Hmmmm. You're still here? -Oh. You must be wondering why the name [*Pyrite*](http://en.wikipedia.org/wiki/Pyrite), eh? +Oh. You must be wondering why the name [*Pyrite*](https://en.wikipedia.org/wiki/Pyrite), eh? -Well, I'll let my friend River--who came up with the name--explain it to you: +Well, I'll let my friend River who came up with the name explain it to you: -*"It should be 'Pyrite', because people think they are getting your data, but really it's just gibberish to them. Fool's gold."* +> It should be 'Pyrite', because people think they are getting your data, but really it's just gibberish to them. +> Fool's gold. diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..52cced5 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +pyrite-crypt (2.0.0-1) stable; urgency=medium + + * update to GTK3 and Python3 + + -- Sergey Ponomarev Sun, 29 Oct 2020 00:00:00 +0000 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..b4de394 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +11 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..99cd6d1 --- /dev/null +++ b/debian/control @@ -0,0 +1,13 @@ +Source: pyrite-crypt +Section: utils +Priority: optional +Maintainer: Sergey Ponomarev +Build-Depends: debhelper (>=10) +Standards-Version: 4.1.4 +Homepage: https://github.com/stokito/pyrite + +Package: pyrite-crypt +Architecture: all +Depends: python3, python3-gi, python3-gi-cairo, gnupg, openssl +Description: Encryption/signing application + GUI frontend for GnuPG (gpg) encrypting, decrypting, signing, and verifying. \ No newline at end of file diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..006bdae --- /dev/null +++ b/debian/copyright @@ -0,0 +1,8 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: pyrite-crypt +Source: https://github.com/stokito/pyrite + +Files: * +Copyright: 2012 Ryan Sawhill Aroha + 2023 Sergey Ponomarev +License: GPLv3 diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 0000000..047500f --- /dev/null +++ b/debian/dirs @@ -0,0 +1,5 @@ +usr/bin +usr/share/pyrite/ +usr/lib/python3/dist-packages/ +usr/share/applications +usr/share/icons/hicolor/scalable/apps/ \ No newline at end of file diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..6d3eb70 --- /dev/null +++ b/debian/rules @@ -0,0 +1,4 @@ +#!/usr/bin/make -f + +%: + DESTDIR=$(CURDIR) dh $@ diff --git a/debian/source/format b/debian/source/format new file mode 100755 index 0000000..163aaf8 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/modules/messages.py b/modules/messages.py deleted file mode 100644 index c79fa61..0000000 --- a/modules/messages.py +++ /dev/null @@ -1,242 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at -# Copyright 2012, 2013 Ryan Sawhill Aroha -# -# License: -# -# Pyrite is free software: you can 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. -# -# Pyrite is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ - -SUCCESS = 0 -INFO = 1 -QUESTION = 2 -WARNING = 3 -ERROR = 4 - -def msg(text, type, icon, timeout=5): - """Dictionar-ify input arguments.""" - return {'text': text, 'type': type, 'icon': icon, 'timeout': timeout} - - -#------------------------------------------------------------------------------ - # INFOBAR MESSAGES FOR MAIN WINDOW -MESSAGE_DICT = dict( - - #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Backend Engine - engine_openssl_missing = msg( - ("Shockingly, your system does not appear to have OpenSSL."), - INFO, WARNING), - - engine_gpg_missing = msg( - ("GnuPG not found. Operating in OpenSSL fallback-mode.\n" - "To make full use of this program you need either gpg or gpg2 installed.\n" - "Without one of them, you won't have access key-based functions like\n" - "asymmetric encryption or singing."), - INFO, WARNING, 20), - - engine_all_missing = msg( - ("This program requires one of: gpg, gpg2, or openssl\n" - "None of these were found on your system. You can look around\n" - "the interface, but to have real fun you'll need to install gpg or gpg2\n" - "from your linux distribution's software repository."), - ERROR, WARNING, 0), - - engine_openssl_notice = msg( - ("OpenSSL only supports symmetric {{en,de}}cryption.\n" - "All key-based functions are disabled."), - INFO, INFO, 7), - - #- - - - - - - - - - - - - - - - - - - - - Textview Message Area Operations - txtview_empty = msg( - ("{customtext}"), - INFO, WARNING, 2), - - txtview_fileopen_error = msg( - ("Error. Could not open file:\n" - "{filename}"), - WARNING, ERROR), - - txtview_fileopen_binary_error = msg( - ("To operate on binary files, use the\n" - "Input File For Direct Operation chooser button."), - INFO, WARNING, 8), - - txtview_save_success = msg( - ("Saved contents of Message area to file:\n" - "{filename}"), - INFO, SUCCESS), - - txtview_save_error = msg( - ("Error. Could not save to file:\n" - "{filename}"), - WARNING, ERROR), - - txtview_copyall_success = msg( - ("Copied contents of Message area to clipboard."), - INFO, SUCCESS, 3), - - #- - - - - - - - - - - - - - - - - - - - - - - - - - - Filemode Operations - filemode_fileopen_error = msg( - ("Error. Could not open file:\n" - "{filename}\n" - "Choose a new file."), - WARNING, ERROR), - - filemode_blue_banner = msg( - ("Encrypt, Decrypt, Sign, or Verify?\n" - "Choose an action to perform on file:\n" - "{filename}\n" - "You will be prompted for an output filename if necessary."), - QUESTION, QUESTION, 0), - - #- - - - - - - - - - - - - - - Main xface (Enc/Dec/Sign/Verify) Operations - x_missing_passphrase= msg( - ("Passphrase?"), - INFO, QUESTION, 3), - - x_canceled_filemode = msg( - ("{customtext} operation canceled.\n" - "To choose different input or output filenames, select Cancel\n" - "from the blue bar below."), - INFO, WARNING, 6), - - x_canceled_textmode = msg( - ("{customtext} operation canceled."), - INFO, WARNING, 4), - - x_opensslenc_success_filemode = msg( - ("OpenSSL encrypted input file with {customtext} cipher;\n" - "saved output to file:\n" - "{filename}\n" - "In order to decrypt that file in the future, you will need to \n" - "remember which cipher you used .. or guess until you figure it out."), - INFO, SUCCESS, 10), - - x_opensslenc_success_textmode = msg( - ("OpenSSL encrypted input using {customtext} cipher.\n" - "In order to decrypt the output in the future, you will need to \n" - "remember which cipher you used .. or guess until you figure it out."), - INFO, SUCCESS, 9), - - x_crypt_success_filemode = msg( - ("Saved {customtext}rypted copy of input to file:\n" - "{filename}"), - INFO, SUCCESS), - - x_sign_success_filemode = msg( - ("Saved signed copy of input to file:\n" - "{filename}"), - INFO, SUCCESS), - - x_detachsign_success_filemode = msg( - ("Saved detached signature of input to file:\n" - "{filename}"), - INFO, SUCCESS), - - x_verify_success = msg( - ("Signature verified. Data integrity intact."), - INFO, SUCCESS, 4), - - x_verify_failed = msg( - ("Signature or data integrity could not be verified.\n" - "See Task Status for details."), - WARNING, ERROR, 7), - - x_missing_recip = msg( - ("For whom do you want to encrypt your message?\n" - "If you don't want to enter recipients and you don't want to select\n" - " Enc. To Self, you must add one of the directives\n" - "\tdefault-recipient-self\n" - "\tdefault-recipient name\n" - "to your gpg.conf file."), - WARNING, QUESTION, 0), - - x_generic_failed_filemode = msg( - ("Problem {customtext}ing file.\n" - "See Task Status for details. Try a different passphrase or Cancel."), - WARNING, ERROR, 8), - - x_generic_failed_textmode = msg( - ("Problem {customtext}ing input.\n" - "See Task Status for details."), - WARNING, ERROR), - - #- - - - - - - - - - - - - - - - - - - - - - - - - OpenSSL Cipher Warnings - cipher_openssl_no_default = msg( - ("OpenSSL has no default cipher.\n" - "AES256 is a good choice."), - INFO, INFO, 7), - - cipher_openssl_no_twofish = msg( - ("OpenSSL has no support for the Twofish cipher."), - INFO, INFO), - - cipher_openssl_aes_note = msg( - ("Note for the command-line geeks:\n" - "AES translates to OpenSSL's aes-128-cbc."), - INFO, INFO), - - #- - - - - - - - - - - - - - - - - - - - - - - - - - - Preferences Actions - preferences_save_success = msg( - ("Saved preferences to {filename}\n" - "but no changes made to current session."), - INFO, SUCCESS), - - preferences_apply_success = msg( - ("Saved preferences to {filename}\n" - "and applied them to current session."), - INFO, SUCCESS), - - ) - - - -#------------------------------------------------------------------------------ - # INFOBAR MESSAGES FOR PREFERENCES DIALOG -PREFS_MESSAGE_DICT = dict( - - prefs_save_failed = msg( - ("Saving preferences failed.\n" - "Unable to open config file {filename} for writing."), - ERROR, WARNING, 10), - - prefs_reverted = msg( - ("Reverted to user-saved preferences."), - INFO, SUCCESS, 3), - - prefs_reset_to_defaults = msg( - ("Preferences reset to defaults. You still need to Save or Apply."), - INFO, SUCCESS, 3), - - prefs_notice_enctoself = msg( - ("If you want Encrypt to Self on in Symmetric mode, you must set\n" - "Encryption Type to 'Both'."), - INFO, INFO), - - prefs_notice_addsig = msg( - ("If you want Add Signature on in Symmetric mode, you must also enable\n" - "Advanced."), - INFO, INFO), - - prefs_notice_enc_both = msg( - ("In order for both encryption types to be on by default, Advanced will also be\n" - "turned on, whether or not you select it now."), - INFO, INFO), - - ) diff --git a/pyrite.desktop b/pyrite.desktop index 435173e..6d0e876 100644 --- a/pyrite.desktop +++ b/pyrite.desktop @@ -1,10 +1,10 @@ [Desktop Entry] Name=Pyrite -Comment=OpenSSL & GnuPG (gpg/gpg2) encryption/signing front-end +Comment=OpenSSL & GnuPG (gpg) encryption/signing front-end +Keywords=encryption;security;sign;signature;gpg;pgp;openssl; Exec=pyrite Terminal=false Type=Application -Icon=/usr/share/pixmaps/password.png -# NEEEEEEED a real icon -Categories=GNOME;Security - +Icon=/usr/share/icons/hicolor/scalable/apps/pyrite.svg +Categories=GNOME;GTK;Security;Utility; +MimeType=application/pgp-encrypted; \ No newline at end of file diff --git a/pyrite.py b/pyrite.py index 8c33798..8e1c8b5 100755 --- a/pyrite.py +++ b/pyrite.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at +#!/usr/bin/env python3 # Copyright 2012, 2013 Ryan Sawhill Aroha # # License: @@ -20,21 +15,11 @@ # # You should have received a copy of the GNU General Public License # along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ -# -# TODO: -# * Icons for for encrypt, decrypt, sign, verify buttons, application -# * Undo stack. Blech. Kill me. -# * Update notifications -# * BUG: First drag/drop onto FileChooserButton fails; 2nd, 3rd, etc succeed. -# It's a GTK+ issue. Reported. bugzilla.gnome.org/show_bug.cgi?id=669718 -# -#------------------------------------------------------------------------------ import argparse from sys import argv -import modules.core + +import pyrite.core # Parse command-line arguments parser = argparse.ArgumentParser( @@ -77,15 +62,14 @@ args = parser.parse_args() # If no cmdline options specified, let's save some cycles later -if len(argv) == 1: args = None - +if len(argv) == 1: + args = None if __name__ == "__main__": - - FeS2 = modules.core.Pyrite(args) + + p = pyrite.core.Pyrite(args) try: - FeS2.main() + p.main() except KeyboardInterrupt: - print + print() exit() - diff --git a/pyrite.svg b/pyrite.svg new file mode 100644 index 0000000..ede1054 --- /dev/null +++ b/pyrite.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/modules/__init__.py b/pyrite/__init__.py similarity index 100% rename from modules/__init__.py rename to pyrite/__init__.py diff --git a/modules/cfg.py b/pyrite/cfg.py similarity index 50% rename from modules/cfg.py rename to pyrite/cfg.py index 4b9daf7..8973607 100644 --- a/modules/cfg.py +++ b/pyrite/cfg.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at +#!/usr/bin/env python3 # Copyright 2012, 2013 Ryan Sawhill Aroha # # License: @@ -20,28 +15,33 @@ # # You should have received a copy of the GNU General Public License # along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ -import gtk +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk from os import getenv # Important variables -VERSION = 'v1.0.2' -ASSETDIR = '/usr/share/pyrite/' -USERPREF_FILE = getenv('HOME') + '/.pyrite' -USERPREF_FORMAT_INFO = {'version':'Must6fa'} +VERSION = 'v2.0.0' +ASSETDIR = '/usr/share/pyrite/' +USERPREF_FILE = getenv('HOME') + '/.pyrite' +USERPREF_FORMAT_INFO = {'version': 'Must6fa'} # List of possible Infobar message types -MSGTYPES = [0, - gtk.MESSAGE_INFO, # 1 - gtk.MESSAGE_QUESTION, # 2 - gtk.MESSAGE_WARNING, # 3 - gtk.MESSAGE_ERROR] # 4 +MSGTYPES = [ + 0, + Gtk.MessageType.INFO, # 1 + Gtk.MessageType.QUESTION, # 2 + Gtk.MessageType.WARNING, # 3 + Gtk.MessageType.ERROR # 4 +] # List of possible images to show in Infobar -IMGTYPES = [gtk.STOCK_APPLY, # 0 - gtk.STOCK_DIALOG_INFO, # 1 - gtk.STOCK_DIALOG_QUESTION, # 2 - gtk.STOCK_DIALOG_WARNING, # 3 - gtk.STOCK_DIALOG_ERROR] # 4 +IMGTYPES = [ + Gtk.STOCK_APPLY, # 0 + Gtk.STOCK_DIALOG_INFO, # 1 + Gtk.STOCK_DIALOG_QUESTION, # 2 + Gtk.STOCK_DIALOG_WARNING, # 3 + Gtk.STOCK_DIALOG_ERROR # 4 +] diff --git a/modules/core.py b/pyrite/core.py similarity index 63% rename from modules/core.py rename to pyrite/core.py index 2d69fa4..2ef1ffb 100644 --- a/modules/core.py +++ b/pyrite/core.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at +#!/usr/bin/env python3 # Copyright 2012, 2013 Ryan Sawhill Aroha # # License: @@ -20,138 +15,153 @@ # # You should have received a copy of the GNU General Public License # along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ # StdLib: -import gtk -gtk.gdk.threads_init() +import gi + +gi.require_version('GLib', '2.0') +gi.require_version('Gdk', '3.0') +gi.require_version('Gtk', '3.0') +from gi.repository import GLib +from gi.repository import Gdk +from gi.repository import Gtk +from gi.repository import Pango + +# gtk.gdk.threads_init() import glib -glib.threads_init() +# glib.threads_init() from threading import Thread from sys import stderr -from pango import FontDescription from os import access, R_OK, read, close, pipe -from os.path import isfile -from urllib import url2pathname +from os.path import isfile, exists +from urllib.request import url2pathname from shlex import split from subprocess import check_output from time import sleep # Custom Modules: -import cfg -import prefs -import crypt_interface -from messages import MESSAGE_DICT +from . import cfg +from . import prefs +from . import crypt_interface +from .messages import MESSAGE_DICT # Important variables -SIGSTOP, SIGCONT = 19, 18 -TARGET_TYPE_URI_LIST = 80 - +SIGSTOP, SIGCONT = 19, 18 +TARGET_TYPE_URI_LIST = 80 class Pyrite: """Display GTK+ window to interact with gpg or openssl via Xface object.""" - - - def show_errmsg(self, msg, dialog=gtk.MESSAGE_ERROR, parent=None): + + def show_errmsg(self, msg, dialog=Gtk.MessageType.ERROR, parent=None): """Display msg with GtkMessageDialog.""" - d = gtk.MessageDialog( - parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, dialog, - gtk.BUTTONS_OK, msg) + d = Gtk.MessageDialog( + flags=0, + message_type=Gtk.MessageType.ERROR, + buttons=Gtk.ButtonsType.OK, + text=msg + ) d.run() d.destroy() - - + def __init__(self, cmdlineargs): - """Build GUI interface from XML, etc.""" - + """Build GUI interface from XML, etc.""" + self.x = None + self.filemode_saved_buff = None + self.encdec_sig_state_active = False + self.encdec_sig_state_sensitive = False + self.canceled = False + self.paused = False + + # local ui folder overrides system /usr/share/pyrite/ + if exists('./ui'): + cfg.ASSETDIR = './' # Use GtkBuilder to build our GUI from the XML file - builder = gtk.Builder() - try: builder.add_from_file(cfg.ASSETDIR + 'ui/main.glade') + builder = Gtk.Builder() + try: + builder.add_from_file(cfg.ASSETDIR + 'ui/main.glade') except: self.show_errmsg( "Problem loading GtkBuilder UI definition file at:\n " + cfg.ASSETDIR + "ui/main.glade\nCannot continue.") raise - - #--------------------------------------------------------- GET WIDGETS! + + # GET WIDGETS! # Main window - self.g_window = builder.get_object('window1') + self.g_window = builder.get_object('window1') # Toolbars - self.g_maintoolbar = builder.get_object('hbox1') - self.g_modetoolbar = builder.get_object('hbox2') - self.g_enctoolbar = builder.get_object('hbox3') - self.g_sigtoolbar = builder.get_object('hbox4') + self.g_maintoolbar = builder.get_object('hbox1') + self.g_modetoolbar = builder.get_object('hbox2') + self.g_enctoolbar = builder.get_object('hbox3') + self.g_sigtoolbar = builder.get_object('hbox4') # Menu items - self.g_mclear = builder.get_object('mnu_clear') - self.g_mopen = builder.get_object('mnu_open') - self.g_msave = builder.get_object('mnu_save') - self.g_mengine = builder.get_object('mnu_switchengine') - self.g_mcut = builder.get_object('mnu_cut') - self.g_mcopy = builder.get_object('mnu_copy') - self.g_mpaste = builder.get_object('mnu_paste') - self.g_mprefs = builder.get_object('mnu_preferences') - self.g_wrap = builder.get_object('toggle_wordwrap') - self.g_taskstatus = builder.get_object('toggle_taskstatus') - self.g_taskverbose = builder.get_object('toggle_gpgverbose') + self.g_mclear = builder.get_object('mnu_clear') + self.g_mopen = builder.get_object('mnu_open') + self.g_msave = builder.get_object('mnu_save') + self.g_mengine = builder.get_object('mnu_switchengine') + self.g_mcut = builder.get_object('mnu_cut') + self.g_mcopy = builder.get_object('mnu_copy') + self.g_mpaste = builder.get_object('mnu_paste') + self.g_mprefs = builder.get_object('mnu_preferences') + self.g_wrap = builder.get_object('toggle_wordwrap') + self.g_taskstatus = builder.get_object('toggle_taskstatus') + self.g_taskverbose = builder.get_object('toggle_gpgverbose') # Top action toolbar - self.g_encrypt = builder.get_object('btn_encrypt') - self.g_decrypt = builder.get_object('btn_decrypt') - self.g_bclear = builder.get_object('btn_clear') - self.g_progbar = builder.get_object('progressbar') - self.g_cancel = builder.get_object('btn_cancel') - self.g_pause = builder.get_object('btn_pause') - self.g_slider = builder.get_object('opacity_slider') + self.g_encrypt = builder.get_object('btn_encrypt') + self.g_decrypt = builder.get_object('btn_decrypt') + self.g_bclear = builder.get_object('btn_clear') + self.g_progbar = builder.get_object('progressbar') + self.g_cancel = builder.get_object('btn_cancel') + self.g_pause = builder.get_object('btn_pause') # Mode-setting toolbar - self.g_signverify = builder.get_object('toggle_mode_signverify') - self.g_chk_outfile = builder.get_object('toggle_sign_chooseoutput') - self.g_encdec = builder.get_object('toggle_mode_encdec') - self.g_symmetric = builder.get_object('toggle_mode_symmetric') - self.g_asymmetric = builder.get_object('toggle_mode_asymmetric') - self.g_advanced = builder.get_object('toggle_advanced') + self.g_signverify = builder.get_object('toggle_mode_signverify') + self.g_chk_outfile = builder.get_object('toggle_sign_chooseoutput') + self.g_encdec = builder.get_object('toggle_mode_encdec') + self.g_symmetric = builder.get_object('toggle_mode_symmetric') + self.g_asymmetric = builder.get_object('toggle_mode_asymmetric') + self.g_advanced = builder.get_object('toggle_advanced') # Encryption toolbar - self.g_passlabel = builder.get_object('label_entry_pass') - self.g_pass = builder.get_object('entry_pass') - self.g_reciplabel = builder.get_object('label_entry_recip') - self.g_recip = builder.get_object('entry_recip') - self.g_enctoself = builder.get_object('toggle_enctoself') - self.g_cipherlabel = builder.get_object('label_combobox_cipher') - self.g_cipher = builder.get_object('combobox_cipher') + self.g_passlabel = builder.get_object('label_entry_pass') + self.g_pass = builder.get_object('entry_pass') + self.g_reciplabel = builder.get_object('label_entry_recip') + self.g_recip = builder.get_object('entry_recip') + self.g_enctoself = builder.get_object('toggle_enctoself') + self.g_cipherlabel = builder.get_object('label_combobox_cipher') + self.g_cipher = builder.get_object('combobox_cipher') # Middle input area - self.g_bopen = builder.get_object('btn_open') - self.g_bsave = builder.get_object('btn_save') - self.g_bcopyall = builder.get_object('btn_copyall') - self.g_msgtxtview = builder.get_object('textview1') - self.buff = self.g_msgtxtview.get_buffer() - self.vbox_ibar = builder.get_object('vbox_ibar') - self.vbox_ibar2 = builder.get_object('vbox_ibar2') - self.g_expander = builder.get_object('expander_filemode') - self.g_chooserbtn = builder.get_object('btn_filechooser') - self.g_plaintext = builder.get_object('toggle_plaintext') - self.g_frame2 = builder.get_object('frame2') - self.g_errtxtview = builder.get_object('textview2') - self.buff2 = self.g_errtxtview.get_buffer() + self.g_bopen = builder.get_object('btn_open') + self.g_bsave = builder.get_object('btn_save') + self.g_bcopyall = builder.get_object('btn_copyall') + self.g_msgtxtview = builder.get_object('textview1') + self.buff = self.g_msgtxtview.get_buffer() + self.vbox_ibar = builder.get_object('vbox_ibar') + self.vbox_ibar2 = builder.get_object('vbox_ibar2') + self.g_expander = builder.get_object('expander_filemode') + self.g_chooserbtn = builder.get_object('btn_filechooser') + self.g_plaintext = builder.get_object('toggle_plaintext') + self.g_frame2 = builder.get_object('frame2') + self.g_errtxtview = builder.get_object('textview2') + self.buff2 = self.g_errtxtview.get_buffer() # Signing toolbar - self.g_signature = builder.get_object('toggle_signature') - self.g_sigmode = builder.get_object('combobox_sigmode') - self.g_digestlabel = builder.get_object('label_combobox_digest') - self.g_digest = builder.get_object('combobox_digest') - self.g_chk_defkey = builder.get_object('toggle_defaultkey') - self.g_defaultkey = builder.get_object('entry_defaultkey') + self.g_signature = builder.get_object('toggle_signature') + self.g_sigmode = builder.get_object('combobox_sigmode') + self.g_digestlabel = builder.get_object('label_combobox_digest') + self.g_digest = builder.get_object('combobox_digest') + self.g_chk_defkey = builder.get_object('toggle_defaultkey') + self.g_defaultkey = builder.get_object('entry_defaultkey') # Statusbar - self.g_statusbar = builder.get_object('statusbar') + self.g_statusbar = builder.get_object('statusbar') self.g_activityspin = builder.get_object('spinner1') - + # Set app icon to something halfway-decent - gtk.window_set_default_icon_name(gtk.STOCK_DIALOG_AUTHENTICATION) - + Gtk.Window.set_default_icon_name("dialog-password") + # Connect signals builder.connect_signals(self) - + # Other class attributes - self.ib_filemode = None - self.engine = 'missing_backend' - self.quiting = False + self.ib_filemode = None + self.engine = 'missing_backend' + self.quiting = False self.working_widgets_filemode = [ self.g_mclear, self.g_mprefs, self.g_encrypt, self.g_decrypt, self.g_bclear, self.g_modetoolbar, self.g_enctoolbar, self.g_expander, self.g_sigtoolbar] @@ -160,37 +170,37 @@ def __init__(self, cmdlineargs): self.g_modetoolbar, self.g_enctoolbar, self.g_expander, self.g_sigtoolbar, self.g_mengine, self.g_bcopyall, self.g_bopen, self.g_mopen, self.g_bsave, self.g_msave, self.g_mcut, self.g_mcopy, self.g_mpaste] - + # Initialize main Statusbar self.status = self.g_statusbar.get_context_id('main') self.g_statusbar.push(self.status, "Enter message to encrypt/decrypt") - + # Sensitivity for these GtkEntrys not defaulted to False in xml because # that makes their icons stay insensitive-looking forever - self.g_pass.set_sensitive (False) - self.g_recip.set_sensitive (False) + self.g_pass.set_sensitive(False) + self.g_recip.set_sensitive(False) - #------------------------------ LOAD PREFERENCES AND SET WIDGET STATES! + # LOAD PREFERENCES AND SET WIDGET STATES! self.preferences = prefs.Preferences() - + # Make a clone of preferences dictionary self.p = self.preferences.p - + # Launch gpg/openssl interface if cmdlineargs and cmdlineargs.backend: backend = cmdlineargs.backend else: backend = None - + self.instantiate_xface(preferred=backend, startup=True) - - #------------------------------------------------ DRAG AND DROP FUNNESS - dnd_list = [ ( 'text/uri-list', 0, TARGET_TYPE_URI_LIST ) ] - self.g_msgtxtview.drag_dest_set( - gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_HIGHLIGHT, - dnd_list, gtk.gdk.ACTION_COPY) - - #---------------------------------------------------- CMDLINE ARGUMENTS + + # DRAG AND DROP FUNNESS + dnd_list = [('text/uri-list', 0, TARGET_TYPE_URI_LIST)] + # self.g_msgtxtview.drag_dest_set( + # Gtk.DestDefaults.MOTION | Gtk.DestDefaults.HIGHLIGHT, + # dnd_list, Gdk.DragAction.COPY) + + # CMDLINE ARGUMENTS if cmdlineargs: a = cmdlineargs @@ -199,15 +209,18 @@ def __init__(self, cmdlineargs): if a.direct_file: self.g_chooserbtn.set_filename(a.input) self.g_expander.set_expanded(True) - elif a.text_input: self.buff.set_text(a.input) - else: self.open_in_txtview(a.input) - + elif a.text_input: + self.buff.set_text(a.input) + else: + self.open_in_txtview(a.input) + if self.engine not in 'OpenSSL': if a.recipients: self.g_recip.set_text(a.recipients) self.g_asymmetric.set_active(True) if a.symmetric: - if a.recipients: self.g_advanced.set_active(True) + if a.recipients: + self.g_advanced.set_active(True) self.g_symmetric.set_active(True) if a.defaultkey: self.g_defaultkey.set_text(a.defaultkey) @@ -216,72 +229,71 @@ def __init__(self, cmdlineargs): self.g_encdec.set_active(True) elif a.signverify: self.g_signverify.set_active(True) - - #--------------------------------------------------- OUR LOVELY COMM DEVICE + + # OUR LOVELY COMM DEVICE def infobar(self, id, filename=None, customtext=None, vbox=None): """Popup a new auto-hiding InfoBar.""" - + # Find the needed dictionary inside our message dict, by id MSG = MESSAGE_DICT[id] - # Use value from MSG type & icon to lookup Gtk constant, e.g. gtk.MESSAGE_INFO - msgtype = cfg.MSGTYPES[ MSG['type'] ] - imgtype = cfg.IMGTYPES[ MSG['icon'] ] + # Use value from MSG type & icon to lookup Gtk constant, e.g. Gtk.MessageType.INFO + msgtype = cfg.MSGTYPES[MSG['type']] + imgtype = cfg.IMGTYPES[MSG['icon']] # Replace variables in message text & change text color message = ("" + MSG['text'].format(filename=filename, customtext=customtext) + "") - + # Now that we have all the data we need, START creating! - ibar = gtk.InfoBar() + ibar = Gtk.InfoBar() ibar.set_message_type(msgtype) if vbox: # If specific vbox requested: assume ibar for filemode, add cancel button - ibar.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL) - ibar.connect ('response', self.cleanup_filemode) + ibar.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL) + ibar.connect('response', self.cleanup_filemode) else: # If no specific vbox requested: do normal ibar at the top of message area - vbox = self.vbox_ibar - ibar.add_button (gtk.STOCK_OK, gtk.RESPONSE_OK) - ibar.connect ('response', lambda *args: ibar.destroy()) - vbox.pack_end (ibar, False, False) - content = ibar.get_content_area() - img = gtk.Image() - img.set_from_stock (imgtype, gtk.ICON_SIZE_LARGE_TOOLBAR) - content.pack_start (img, False, False) - img.show () - label = gtk.Label() - label.set_markup (message) - content.pack_start (label, False, False) - label.show () + vbox = self.vbox_ibar + ibar.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK) + ibar.connect('response', lambda *args: ibar.destroy()) + vbox.pack_end(ibar, False, False, 0) + content = ibar.get_content_area() + img = Gtk.Image() + img.set_from_stock(imgtype, Gtk.IconSize.LARGE_TOOLBAR) + content.pack_start(img, False, False, 0) + img.show() + label = Gtk.Label() + label.set_markup(message) + content.pack_start(label, False, False, 0) + label.show() # FIXME: Why doesn't Esc trigger this close signal? - ibar.connect ('close', lambda *args: ibar.destroy()) + ibar.connect('close', lambda *args: ibar.destroy()) ibar.show() if MSG['timeout'] > 0: - glib.timeout_add_seconds(MSG['timeout'], ibar.destroy) + GLib.timeout_add_seconds(MSG['timeout'], ibar.destroy) return ibar - - - #----------------------------------------------------- BRING UP GPG/OPENSSL + + # BRING UP GPG/OPENSSL def instantiate_xface(self, preferred=None, startup=False): - """Instantiate Gpg or Openssl interface.""" - - b = ['gpg2', 'gpg', 'openssl'] - # self.p['backend'] contains 0, 1, or 2, corresponding to the above items in b - # Desired: convert the number setting to the human-readable name and store as b - b = b[self.p['backend']] - + """Instantiate Gpg or Openssl interface.""" + # If we weren't passed preferred argument, set desired interface to backend pref - if not preferred: preferred = b - + if not preferred: + b = ['gpg', 'openssl'] + # self.p['backend'] contains 0, 1, or 2, corresponding to the above items in b + # Desired: convert the number setting to the human-readable name and store as b + b = b[self.p['backend']] + preferred = b + # Loading gpg - def gpg(backend_pref=b, fallback=False): - self.x = crypt_interface.Gpg(firstchoice=backend_pref) - self.engine = self.x.GPG_BINARY.upper() + def gpg(fallback=False): + self.x = crypt_interface.Gpg() + self.engine = 'GPG' self.g_mengine.set_label("Use OpenSSL as Engine") if fallback: self.g_mengine.set_sensitive(False) self.infobar('engine_openssl_missing') - + # Loading openssl def openssl(fallback=False): self.x = crypt_interface.Openssl() @@ -292,16 +304,20 @@ def openssl(fallback=False): self.infobar('engine_gpg_missing') else: self.infobar('engine_openssl_notice') - + # Setup for neutered-run (when missing all backends) def err_allmissing(): self.infobar('engine_all_missing') self.g_mengine.set_sensitive(False) - for w in self.g_encrypt, self.g_decrypt: w.set_sensitive(False) - class dummy: pass + for w in self.g_encrypt, self.g_decrypt: + w.set_sensitive(False) + + class dummy: + pass + self.x = dummy() self.x.io = dict(stdin='', stdout='', gstatus=0, infile=0, outfile=0) - + # Get it done! if preferred in 'openssl': # If loading openssl, try that first, then fallback to gpg @@ -321,153 +337,149 @@ class dummy: pass openssl(fallback=True) except: err_allmissing() - + self.g_window.set_title("Pyrite [{}]".format(self.engine)) - + self.buff2.set_text("Any output generated from calls to {} will be " - "displayed here.\n\nIn the View menu you can change " + "displayed here.\n\n" + "In the View menu you can change " "the verbosity level, hide this pane, or simply change " - "the font size.".format(self.engine.lower())) - + "the font size.".format(self.engine)) + self.set_defaults_from_prefs(startup) - - - #--------------------------------------------- SET OPMODES, ETC, FROM PREFS + + # SET OPMODES, ETC, FROM PREFS def set_defaults_from_prefs(self, startup=False): """Set window toggle states via preferences.""" - + if self.p['enctype'] == 0: - self.g_symmetric.set_active (True) + self.g_symmetric.set_active(True) elif self.p['enctype'] == 1: - self.g_asymmetric.set_active (True) + self.g_asymmetric.set_active(True) elif self.p['enctype'] == 2: - self.g_advanced.set_active (True) - self.g_symmetric.set_active (True) - self.g_asymmetric.set_active (True) - + self.g_advanced.set_active(True) + self.g_symmetric.set_active(True) + self.g_asymmetric.set_active(True) + if self.p['advanced']: - self.g_advanced.set_active (True) - + self.g_advanced.set_active(True) + if self.p['advanced'] or self.p['enctype'] > 0: if self.p['addsig']: - self.g_signature.set_active (True) + self.g_signature.set_active(True) if self.p['enctoself']: - self.g_enctoself.set_active (True) - + self.g_enctoself.set_active(True) + if self.p['opmode']: - self.g_signverify.set_active (True) + self.g_signverify.set_active(True) if not self.g_expander.get_expanded(): - self.g_expander.set_expanded (self.p['expander']) - - self.g_cipher.set_active (self.p['cipher']) - self.g_digest.set_active (self.p['digest']) - self.g_chk_defkey.set_active (self.p['defkey']) - self.g_defaultkey.set_text (self.p['defkeytxt']) - + self.g_expander.set_expanded(self.p['expander']) + + self.g_cipher.set_active(self.p['cipher']) + self.g_digest.set_active(self.p['digest']) + self.g_chk_defkey.set_active(self.p['defkey']) + self.g_defaultkey.set_text(self.p['defkeytxt']) + if startup: - self.g_taskstatus.set_active (self.p['taskstatus']) - self.g_taskverbose.set_active (self.p['verbose']) - self.g_wrap.set_active (self.p['wrap']) - + self.g_taskstatus.set_active(self.p['taskstatus']) + self.g_taskverbose.set_active(self.p['verbose']) + self.g_wrap.set_active(self.p['wrap']) + # Set TextView fonts, sizes, and colors self.g_msgtxtview.modify_font( - FontDescription("monospace {}".format(self.p['msgfntsize']))) + Pango.FontDescription("monospace {}".format(self.p['msgfntsize']))) self.g_errtxtview.modify_font( - FontDescription("normal {}".format(self.p['errfntsize']))) + Pango.FontDescription("normal {}".format(self.p['errfntsize']))) + + bg_color = Gdk.Color(0, 0, 0) + bg_color.parse(self.p['color_bg']) + fg_color = Gdk.Color(0, 0, 0) + fg_color.parse(self.p['color_fg']) self.g_msgtxtview.modify_base( - gtk.STATE_NORMAL, gtk.gdk.color_parse(self.p['color_bg'])) + Gtk.StateType.NORMAL, bg_color) self.g_msgtxtview.modify_text( - gtk.STATE_NORMAL, gtk.gdk.color_parse(self.p['color_fg'])) - - if self.p['opc_slider']: - self.g_slider.set_range (0, 100) - self.g_slider.set_value (self.p['opacity']) - self.g_slider.set_tooltip_text ("Change window opacity (current:{}%)".format(self.p['opacity'])) - self.g_slider.set_visible (True) - else: - self.g_window.set_opacity(self.p['opacity']/100.0) - + Gtk.StateType.NORMAL, fg_color) + + # These are all the widgets that can't be used in openssl mode def setsensitive_gpgwidgets(x=True): - self.g_signverify.set_sensitive (x) - self.g_symmetric.set_sensitive (x) - self.g_asymmetric.set_sensitive (x) - self.g_advanced.set_sensitive (x) - self.g_chk_defkey.set_sensitive (x) - self.g_taskverbose.set_visible (x) # OpenSSL doesn't have verbosity - + self.g_signverify.set_sensitive(x) + self.g_symmetric.set_sensitive(x) + self.g_asymmetric.set_sensitive(x) + self.g_advanced.set_sensitive(x) + self.g_chk_defkey.set_sensitive(x) + self.g_taskverbose.set_visible(x) # OpenSSL doesn't have verbosity + if self.engine in 'OpenSSL': - self.g_encdec.set_active (True) - self.g_symmetric.set_active (True) - self.g_advanced.set_active (False) - self.g_chk_defkey.set_active (False) + self.g_encdec.set_active(True) + self.g_symmetric.set_active(True) + self.g_advanced.set_active(False) + self.g_chk_defkey.set_active(False) if startup or self.g_cipher.get_active() in {0, 2}: # If starting up, or current cipher set to 'Default' or 'Twofish' if self.p['cipher'] not in {0, 2}: # Set cipher to preference unless pref is 'Default' or 'Twofish' - self.g_cipher.set_active (self.p['cipher']) + self.g_cipher.set_active(self.p['cipher']) else: # Otherwise, set to AES - self.g_cipher.set_active (1) - setsensitive_gpgwidgets (False) + self.g_cipher.set_active(1) + setsensitive_gpgwidgets(False) else: - setsensitive_gpgwidgets (True) - - - #--------------------------------------------------------- HELPER FUNCTIONS - - def fix_msgtxtviewcolor(self, sensitive): + setsensitive_gpgwidgets(True) + + # HELPER FUNCTIONS + + def fix_msgtxtview_color(self, sensitive): """Change Message area text to black when TextView insensitive.""" if sensitive: + fg_color = Gdk.Color(0, 0, 0) + fg_color.parse(self.p['color_fg']) self.g_msgtxtview.modify_text( - gtk.STATE_NORMAL, gtk.gdk.color_parse(self.p['color_fg'])) + Gtk.StateType.NORMAL, fg_color) else: + fg_color = Gdk.Color(0, 0, 0) + fg_color.parse('black') self.g_msgtxtview.modify_text( - gtk.STATE_NORMAL, gtk.gdk.color_parse('black')) - - + Gtk.StateType.NORMAL, fg_color) + def get_file_path_from_dnd_dropped_uri(self, uri): path = '' - if uri.startswith('file:\\\\\\'): # windows + if uri.startswith('file:\\\\\\'): # windows path = uri[8:] # 8 is len('file:///') - elif uri.startswith('file://'): # nautilus, rox + elif uri.startswith('file://'): # nautilus, rox path = uri[7:] # 7 is len('file://') - elif uri.startswith('file:'): # xffm + elif uri.startswith('file:'): # xffm path = uri[5:] # 5 is len('file:') path = url2pathname(path) # escape special chars path = path.strip('\r\n\x00') # remove \r\n and NULL return path - - + def set_stdstatus(self): - """Set a standard mode-depenedent status message.""" + """Set a standard mode-dependent status message.""" self.g_statusbar.pop(self.status) if self.g_signverify.get_active(): s = "Enter message to sign or verify" else: s = "Enter message to encrypt or decrypt" self.g_statusbar.push(self.status, s) - - - def test_file_isbinary(self, filename): + + def test_file_is_plain_text(self, filename): """Utilize nix file cmd to determine if filename is binary or text.""" cmd = split("file -b -e soft '{}'".format(filename)) - if check_output(cmd)[:4] in {'ASCI', 'UTF-'}: - return False - return True - - + output = check_output(cmd) + return output[:4] in (b'ASCI', b'UTF-') + def open_in_txtview(self, filename): """Replace contents of msg TextView's TextBuffer with contents of file.""" try: - with open(filename) as f: self.buff.set_text(f.read()) + with open(filename) as f: + self.buff.set_text(f.read()) if self.buff.get_char_count() < 1: self.infobar('txtview_fileopen_binary_error') except: self.infobar('txtview_fileopen_error', filename) - - + # This is called when entering & exiting direct-file mode def filemode_enablewidgets(self, x=True): """Enable/disable certain widgets due to working in direct-file mode.""" @@ -476,17 +488,15 @@ def filemode_enablewidgets(self, x=True): self.g_mpaste, self.g_msgtxtview] for w in widgets: w.set_sensitive(x) - self.fix_msgtxtviewcolor(x) - - + self.fix_msgtxtview_color(x) + # This is called when user tries to copyall, save, or {en,de}crypt/sign/verify def test_msgbuff_isempty(self, message): """Return True + show infobar containing msg if Message area is empty.""" if self.buff.get_char_count() < 1: self.infobar('txtview_empty', customtext=message) return True - - + def confirm_overwrite_callback(self, chooser): """In filechooser, disallow output file being the input file.""" outfile = chooser.get_filename() @@ -494,41 +504,46 @@ def confirm_overwrite_callback(self, chooser): self.show_errmsg( "Simultaneously reading from & writing to a file is a baaad idea. " "Choose a different output filename.", parent=chooser) - return gtk.FILE_CHOOSER_CONFIRMATION_SELECT_AGAIN + return Gtk.FileChooserConfirmation.SELECT_AGAIN else: - return gtk.FILE_CHOOSER_CONFIRMATION_CONFIRM - - + return Gtk.FileChooserConfirmation.CONFIRM + # Generic file chooser for opening or saving def chooser_grab_filename(self, mode, save_suggestion=None): """Present file chooser dialog and return filename or None.""" - + filename = None - if mode in 'open': title = "Choose text file to open as input..." - elif mode in 'save': title = "Choose output filename..." - cmd = ("gtk.FileChooserDialog('{0}', None, gtk.FILE_CHOOSER_ACTION_{1}, " - "(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))" + if mode in 'open': + title = "Choose text file to open as input..." + elif mode in 'save': + title = "Choose output filename..." + cmd = ("Gtk.FileChooserDialog('{0}', None, Gtk.FileChooserAction.{1}, " + "(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))" .format(title, mode.upper())) chooser = eval(cmd) - + if mode in 'open': # Setup file filters - t = gtk.FileFilter() ; t.set_name("Text Files") ; t.add_mime_type("text/*") - a = gtk.FileFilter() ; a.set_name("All Files") ; a.add_pattern("*") + t = Gtk.FileFilter() + t.set_name("Text Files") + t.add_mime_type("text/*") + a = Gtk.FileFilter() + a.set_name("All Files") + a.add_pattern("*") chooser.add_filter(t) chooser.add_filter(a) elif mode in 'save': # Setup overwrite-confirmation cb + current filename chooser.set_do_overwrite_confirmation(True) chooser.connect('confirm-overwrite', self.confirm_overwrite_callback) - if save_suggestion: chooser.set_current_name(save_suggestion) - - if chooser.run() == gtk.RESPONSE_OK: + if save_suggestion: + chooser.set_current_name(save_suggestion) + + if chooser.run() == Gtk.ResponseType.OK: filename = chooser.get_filename() chooser.destroy() return filename - - + def grab_activetext_combobox(self, combobox): """Return the text of active combobox selection.""" cbmodel = combobox.get_model() @@ -537,72 +552,65 @@ def grab_activetext_combobox(self, combobox): return None # If first choice is selected, i.e. 'Default' else: return cbmodel[cbindex][0] - - + # This is called by encrypt/decrypt buttons when operating in direct-file mode def filemode_get_outfile(self, mode): """Use FileChooser to get an output filename for direct enc/dec.""" - + # Prompt for output file outfile = self.chooser_grab_filename('save', self.x.io['infile']) - + # Kick off processing unless user canceled if outfile: self.x.io['outfile'] = outfile self.launchxface(mode) - - + def initiate_filemode(self): - """Ensure read access of file set by chooserwidget and notify user of next steps.""" - + """Ensure read access of file set by chooser widget and notify user of next steps.""" + # Prompt for filename but err out if file can't be read infile = self.g_chooserbtn.get_filename() if not access(infile, R_OK): self.infobar('filemode_fileopen_error', infile) return - + # Tweak some widgets if in Sign/Verify mode if self.g_signverify.get_active(): - self.g_chk_outfile.set_visible (True) - self.g_chk_outfile.set_active (self.p['svoutfiles']) - self.g_sigmode.set_active (self.p['file_sigmode']) - + self.g_chk_outfile.set_visible(True) + self.g_chk_outfile.set_active(self.p['svoutfiles']) + self.g_sigmode.set_active(self.p['file_sigmode']) + # Configure state of plaintext output checkbox via user-settings - self.g_plaintext.set_sensitive (True) - + self.g_plaintext.set_sensitive(True) + if self.p['txtoutput'] == 0: # Autodetect - if self.test_file_isbinary(infile): - self.g_plaintext.set_active (False) - else: - self.g_plaintext.set_active (True) - + self.g_plaintext.set_active(self.test_file_is_plain_text(infile)) elif self.p['txtoutput'] == 1: # Always Binary - self.g_plaintext.set_active (False) - + self.g_plaintext.set_active(False) elif self.p['txtoutput'] == 2: # Always Text - self.g_plaintext.set_active (True) - + self.g_plaintext.set_active(True) + # Set statusbar w/ filemode status self.g_statusbar.pop(self.status) self.g_statusbar.push(self.status, "Choose an action to perform on {!r}".format(infile)) - + if self.ib_filemode: # If filemode infobar already present: user picked a new file, so destroy old ibar self.ib_filemode.destroy() else: # Otherwise, save TextView buffer for later and then blow it away self.filemode_saved_buff = self.buff.get_text(self.buff.get_start_iter(), - self.buff.get_end_iter()) + self.buff.get_end_iter(), + False) self.buff.set_text('') self.filemode_enablewidgets(False) - + # Create filemode infobar with cancel button self.ib_filemode = self.infobar('filemode_blue_banner', infile, vbox=self.vbox_ibar2) - + # Set input file self.x.io['infile'] = infile - - + def cleanup_filemode(self, *args): """Revert the changes (to widgets, etc) that filemode causes.""" # Restore message buffer @@ -612,40 +620,38 @@ def cleanup_filemode(self, *args): self.ib_filemode.destroy() self.ib_filemode = None # Enable/sensitize widgets - self.filemode_enablewidgets (True) - self.g_chk_outfile.set_visible (False) + self.filemode_enablewidgets(True) + self.g_chk_outfile.set_visible(False) # Ensure sigmode combobox is back to proper 'normal' if self.g_signverify.get_active(): - self.g_sigmode.set_active (self.p['text_sigmode']) + self.g_sigmode.set_active(self.p['text_sigmode']) else: - self.g_sigmode.set_active (0) + self.g_sigmode.set_active(0) # Set statusbar self.set_stdstatus() - #while gtk.events_pending(): - gtk.main_iteration() + # while Gtk.events_pending(): + Gtk.main_iteration() # Reset filenames self.x.io['infile'] = 0 self.x.io['outfile'] = 0 # Disable plaintext CheckButton - self.g_plaintext.set_sensitive (False) - self.g_plaintext.set_active (True) - - - #--------------------------------------------------- HERE BE GTK SIGNAL CBs - + self.g_plaintext.set_sensitive(False) + self.g_plaintext.set_active(True) + + # HERE BE GTK SIGNAL CBs + # Called by window destroy / Quit menu item def action_quit(self, w): """Shutdown application and any child process.""" self.quiting = True - if self.x.childprocess and self.x.childprocess.returncode == None: + if self.x.childprocess and self.x.childprocess.returncode is None: if self.paused: self.x.childprocess.send_signal(SIGCONT) self.x.childprocess.terminate() stderr.write("\n") - #sleep(0.2) - gtk.main_quit() - - + # sleep(0.2) + Gtk.main_quit() + # Called when dnd occurs on Message TextView def action_drag_data_received(self, w, context, x, y, selection, target_type, timestamp): """Read dragged text file into Message area.""" @@ -655,17 +661,8 @@ def action_drag_data_received(self, w, context, x, y, selection, target_type, ti path = self.get_file_path_from_dnd_dropped_uri(uri) if isfile(path): self.open_in_txtview(path) - - - # Called by changing opacity hscale - def action_opacity_slider(self, w): - """Actions to perform when opacity scale is changed.""" - val = w.get_value() - self.g_window.set_opacity(val/100.0) - w.set_tooltip_text( - "Change window opacity (current:{:.1f}%)".format(val)) - - + + # Called by SwitchEngine menu item def action_switch_engine(self, w): """Switch backend between openssl & gpg.""" @@ -673,28 +670,26 @@ def action_switch_engine(self, w): self.instantiate_xface('gpg') else: self.instantiate_xface('openssl') - - + # Called by About menu item def action_about(self, w): """Launch About dialog.""" - builder = gtk.Builder() - builder.add_from_file(cfg.ASSETDIR + 'ui/about.glade') + builder = Gtk.Builder() + builder.add_from_file(cfg.ASSETDIR + 'ui/about.glade') about = builder.get_object('aboutdialog') - about.set_logo_icon_name(gtk.STOCK_DIALOG_AUTHENTICATION) - about.set_transient_for(self.g_window) + about.set_logo_icon_name(Gtk.STOCK_DIALOG_AUTHENTICATION) + # about.set_transient_for(self.g_window) about.set_version(cfg.VERSION) about.connect('response', lambda *args: about.destroy()) about.show() - - + # Called by Preferences menu item def action_preferences(self, w): """Launch preferences window.""" - + # Run preferences window method from already-open pref instance self.preferences.open_preferences_window(parentwindow=self.g_window) - + # CB for pref window's save button def savepref(*args): # Attempt to save preferences @@ -702,7 +697,7 @@ def savepref(*args): # If success: destroy pref window, show infobar self.preferences.window.destroy() self.infobar('preferences_save_success', cfg.USERPREF_FILE) - + # CB for pref window's apply button def applypref(*args): # Attempt to save preferences @@ -710,15 +705,15 @@ def applypref(*args): # If success, destroy pref window, import new prefs, show infobar self.preferences.window.destroy() self.p = self.preferences.p - if self.x.io['infile']: self.cleanup_filemode() + if self.x.io['infile']: + self.cleanup_filemode() self.instantiate_xface(startup=True) self.infobar('preferences_apply_success', cfg.USERPREF_FILE) - + # Connect signals - self.preferences.btn_save.connect ('clicked', savepref) - self.preferences.btn_apply.connect ('clicked', applypref) - - + self.preferences.btn_save.connect('clicked', savepref) + self.preferences.btn_apply.connect('clicked', applypref) + # Called by Clear toolbar btn or menu item def action_clear(self, w): """Reset Statusbar, filemode stuff, TextView buffers.""" @@ -726,91 +721,83 @@ def action_clear(self, w): self.cleanup_filemode() else: self.set_stdstatus() - self.buff.set_text ('') - self.buff2.set_text ('') + self.buff.set_text('') + self.buff2.set_text('') self.x.io = dict(stdin='', stdout='', gstatus=0, infile=0, outfile=0) - - + # Called when user clicks the entry_icon in any of the entry widgets def action_clear_entry(self, entry, *args): """Clear TextEntry widget.""" entry.set_text('') - - + # Called by Open toolbar btn or menu item def action_open(self, w): """Read in a text file and push its contents to our TextView.""" filename = self.chooser_grab_filename('open') if filename: self.open_in_txtview(filename) - - + # Called when direct-file-mode FileChooserButton gets a new file set, # either because of dnd or manual selection def action_chooserbtn_file_set(self, w): - print "[on_file-set] FileChooserButton.get_filename() output:\n{!r}\n".format(w.get_filename()) + print("[on_file-set] FileChooserButton.get_filename() output:\n{!r}\n".format(w.get_filename())) self.initiate_filemode() - - + # Called by Save toolbar btn or menu item def action_save(self, w): """Save contents of msg TextView's TextBuffer to file.""" - + # If Message area is empty, err out if self.test_msgbuff_isempty("No text to save."): return - + # Prompt for filename to save to; cancel if user cancels filename = self.chooser_grab_filename('save') if not filename: return - + # Set saving status self.g_statusbar.push(self.status, "Saving {}".format(filename)) - #while gtk.events_pending(): - gtk.main_iteration() - + # while Gtk.events_pending(): + Gtk.main_iteration() + # Grab text from buffer buffertext = self.buff.get_text(self.buff.get_start_iter(), - self.buff.get_end_iter()) + self.buff.get_end_iter(), + False) try: # If can open file for writing, show success infobar - with open(filename, 'w') as f: f.write(buffertext) + with open(filename, 'w') as f: + f.write(buffertext) self.infobar('txtview_save_success', filename) except: # Otherwise, show error self.infobar('txtview_save_error', filename) - + # Clear saving status self.g_statusbar.pop(self.status) - - + def action_undo(self, w): pass - - + def action_redo(self, w): pass - - + # Called by Cut toolbar btn or menu item def action_cut(self, w): """Cut msg TextBuffer selection.""" - self.buff.cut_clipboard(gtk.clipboard_get(), True) - - + self.buff.cut_clipboard(Gtk.clipboard_get(), True) + # Called by Copy toolbar btn or menu item def action_copy(self, w): """Copy msg TextBuffer selection.""" - self.buff.copy_clipboard(gtk.clipboard_get()) - - + self.buff.copy_clipboard(Gtk.clipboard_get()) + # Called by Paste toolbar btn or menu item def action_paste(self, w): """Paste clipboard into msg TextBuffer at selection.""" - self.buff.paste_clipboard(gtk.clipboard_get(), None, True) - - + self.buff.paste_clipboard(Gtk.clipboard_get(), None, True) + # Called by Copyall toolbar btn def action_copyall(self, w): """Select whole msg TextBuffer contents and copy it to clipboard.""" @@ -818,10 +805,9 @@ def action_copyall(self, w): return self.buff.select_range(self.buff.get_start_iter(), self.buff.get_end_iter()) - self.buff.copy_clipboard(gtk.clipboard_get()) + self.buff.copy_clipboard(Gtk.clipboard_get()) self.infobar('txtview_copyall_success') - - + # Called by Zoom menu items def action_zoom(self, w): """Increase/decrease font size of TextViews.""" @@ -833,11 +819,10 @@ def action_zoom(self, w): self.p['msgfntsize'] -= 1 self.p['errfntsize'] -= 1 self.g_msgtxtview.modify_font( - FontDescription("monospace {}".format(self.p['msgfntsize']))) + Pango.FontDescription("monospace {}".format(self.p['msgfntsize']))) self.g_errtxtview.modify_font( - FontDescription("normal {}".format(self.p['errfntsize']))) - - + Pango.FontDescription("normal {}".format(self.p['errfntsize']))) + # Called when Cipher combobox selection is changed def action_cipher_changed(self, w): """Disallow certain cipher selections in OpenSSL mode.""" @@ -851,16 +836,10 @@ def action_cipher_changed(self, w): self.infobar('cipher_openssl_no_twofish') elif cipher in 'AES': self.infobar('cipher_openssl_aes_note') - - + # Called by Encrypt/Sign toolbar btn def action_encrypt(self, w): """Encrypt or sign input.""" - # DEBUG - #self.g_chooserbtn.select_filename('/etc/passwd') - #self.g_expander.set_expanded(True) - #gtk.main_iteration() - #return if self.g_signverify.get_active(): # If in sign-only mode, figure out which sig-type if self.g_sigmode.get_active() == 0: @@ -873,8 +852,7 @@ def action_encrypt(self, w): else: # Normal enc/dec mode self.launchxface('enc') - - + # Called by Decrypt/Verify toolbar btn def action_decrypt(self, w): """Decrypt or verify input.""" @@ -884,232 +862,210 @@ def action_decrypt(self, w): else: # Normal enc/dec mode self.launchxface('dec') - - + # Called by Symmetric checkbox toggle def action_toggle_symmetric(self, w): """Toggle symmetric encryption (enable/disable certain widgets).""" - + symm_widgets = [self.g_passlabel, self.g_pass] - + if w.get_active(): # If entering toggled state, allow pass entry for widget in symm_widgets: - widget.set_sensitive (True) + widget.set_sensitive(True) if not self.g_advanced.get_active(): # If not in advanced mode, disable Asymmetric - self.g_asymmetric.set_active (False) - + self.g_asymmetric.set_active(False) + else: # If leaving toggled state, hide pass entry for widget in symm_widgets: - widget.set_sensitive (False) + widget.set_sensitive(False) if not self.g_asymmetric.get_active(): # If unchecking Symm & Asymm isn't already on, turn it on - self.g_asymmetric.set_active (True) - - + self.g_asymmetric.set_active(True) + # Called by Asymmetric checkbox toggle def action_toggle_asymmetric(self, w): """Toggle asymmetric encryption (enable/disable certain widgets).""" - + asymm_widgets = [self.g_reciplabel, self.g_recip, self.g_enctoself] - + if w.get_active(): # If entering toggled state, allow recip entry, enctoself for widget in asymm_widgets: - widget.set_sensitive (True) - self.g_signature.set_sensitive (True) + widget.set_sensitive(True) + self.g_signature.set_sensitive(True) if not self.g_advanced.get_active(): # If not in advanced mode, disable Symmetric - self.g_symmetric.set_active (False) - + self.g_symmetric.set_active(False) + self.load_recipients_autocmplete() else: # If leaving toggled state, hide recip entry, enctoself for widget in asymm_widgets: - widget.set_sensitive (False) - self.g_enctoself.set_active (False) + widget.set_sensitive(False) + self.g_enctoself.set_active(False) if not self.g_advanced.get_active(): # If not in advanced mode, ensure add signature is unchecked - self.g_signature.set_sensitive (False) - self.g_signature.set_active (False) + self.g_signature.set_sensitive(False) + self.g_signature.set_active(False) if not self.g_symmetric.get_active(): # If unchecking Asymm & Symm isn't already on, turn it on - self.g_symmetric.set_active (True) - - + self.g_symmetric.set_active(True) + # Called by Advanced checkbox toggle def action_toggle_advanced(self, w): """Enable/disable encryption widgets for advanced mode.""" - + if w.get_active(): # If entering the toggled state, allow adding signature - self.g_signature.set_sensitive (True) - + self.g_signature.set_sensitive(True) + else: # If leaving the toggled state... if self.g_symmetric.get_active(): # We have some things to do if Symmetric is checked... if self.g_asymmetric.get_active(): # If Asymmetric is also checked, disable it - self.g_asymmetric.set_active (False) + self.g_asymmetric.set_active(False) else: # If Asymmetric isn't checked, ensure addsig is disabled - self.g_signature.set_sensitive (False) - self.g_signature.set_active (False) - - + self.g_signature.set_sensitive(False) + self.g_signature.set_active(False) + # Called by Sign/Verify radio toggle def action_toggle_mode_signverify(self, w): """Hide/show, change some widgets when switching modes.""" - + enc_widgets = [self.g_symmetric, self.g_asymmetric, self.g_advanced, self.g_enctoolbar] - + # Change statusbar self.set_stdstatus() - + if w.get_active(): # If entering the toggled state: modify buttons, hide & show widgets # Modify Encrypt/Decrypt button labels - self.g_encrypt.set_label ("Sign") - self.g_decrypt.set_label ("Verify") + self.g_encrypt.set_label("Sign") + self.g_decrypt.set_label("Verify") # Hide encryption toolbar & Symmetric, Asymmetric, Adv toggles for widget in enc_widgets: - widget.set_visible (False) + widget.set_visible(False) # Save state of AddSignature for switching back to Enc/Dec mode self.encdec_sig_state_sensitive = self.g_signature.get_sensitive() - self.encdec_sig_state_active = self.g_signature.get_active() + self.encdec_sig_state_active = self.g_signature.get_active() # Desensitize AddSignature checkbox and turn it on - self.g_signature.set_sensitive (False) - self.g_signature.set_active (True) + self.g_signature.set_sensitive(False) + self.g_signature.set_active(True) # Sensitize sigmode combobox - self.g_sigmode.set_sensitive (True) + self.g_sigmode.set_sensitive(True) # Set sigmode combobox via user prefs if self.x.io['infile']: - self.g_sigmode.set_active (self.p['file_sigmode']) - self.g_chk_outfile.set_visible (True) + self.g_sigmode.set_active(self.p['file_sigmode']) + self.g_chk_outfile.set_visible(True) else: - self.g_sigmode.set_active (self.p['text_sigmode']) - + self.g_sigmode.set_active(self.p['text_sigmode']) + else: # If leaving the toggled state, we have some things to reverse - self.g_encrypt.set_label ("_Encrypt") - self.g_decrypt.set_label ("_Decrypt") - self.g_chk_outfile.set_visible (False) + self.g_encrypt.set_label("_Encrypt") + self.g_decrypt.set_label("_Decrypt") + self.g_chk_outfile.set_visible(False) for widget in enc_widgets: - widget.set_visible (True) - self.g_signature.set_sensitive (self.encdec_sig_state_sensitive) - self.g_signature.set_active (self.encdec_sig_state_active) - self.g_sigmode.set_sensitive (False) - self.g_sigmode.set_active (0) # Reset to 'Embedded' type for Enc/Dec mode - - + widget.set_visible(True) + self.g_signature.set_sensitive(self.encdec_sig_state_sensitive) + self.g_signature.set_active(self.encdec_sig_state_active) + self.g_sigmode.set_sensitive(False) + self.g_sigmode.set_active(0) # Reset to 'Embedded' type for Enc/Dec mode + # Called by 'Change Default Key' checkbox toggle def action_toggle_defaultkey(self, w): """Hide/show Entry widget for setting gpg 'localuser' argument.""" - - if w.get_active(): - # If entering toggled state, show default key TextEntry - self.g_defaultkey.set_visible (True) - else: - # If leaving toggled state, hide default key TextEntry - self.g_defaultkey.set_visible (False) - - + + # If entering toggled state, show default key TextEntry + self.g_defaultkey.set_visible(w.get_active()) + # Called by 'Add Signature' checkbox toggle def action_toggle_signature(self, w): """Hide/show some widgets when toggling adding of a signature to input.""" sig_widgets = [self.g_sigmode, self.g_digest, self.g_digestlabel] - - if w.get_active(): - # If entering toggled state, show sig toolbar widgets - for widget in sig_widgets: - widget.set_visible (True) - else: - # If leaving toggled state, hide sig toolbar widgets - for widget in sig_widgets: - widget.set_visible (False) - - + + active = w.get_active() + # If entering toggled state, show sig toolbar widgets + for widget in sig_widgets: + widget.set_visible(active) + # Called by 'Task Status Side Panel' checkbox toggle def action_toggle_taskstatus(self, w): """Show/hide side pane containing gpg stderr output.""" - if w.get_active(): - # If entering toggled state, show Task Status TextView frame - self.g_frame2.set_visible (True) - else: - # If leaving toggled state, hide Task Status TextView frame - self.g_frame2.set_visible (False) - - + # If entering toggled state, show Task Status TextView frame + self.g_frame2.set_visible(w.get_active()) + # Called by 'Text Wrapping' checkbox toggle def action_toggle_wordwrap(self, w): """Toggle word wrapping for main message TextView.""" if w.get_active(): # If entering toggled state, enable word wrapping - self.g_msgtxtview.set_wrap_mode(gtk.WRAP_WORD) + self.g_msgtxtview.set_wrap_mode(Gtk.WrapMode.WORD) else: # If leaving toggled state, disable word wrapping - self.g_msgtxtview.set_wrap_mode(gtk.WRAP_NONE) - - + self.g_msgtxtview.set_wrap_mode(Gtk.WrapMode.NONE) + # Called by [processing progbar] Cancel button def action_cancel_child_process(self, btn): """Terminate gpg/openssl subprocess.""" - - stderr.write ("Canceling Operation\n") - self.canceled = True + + stderr.write("Canceling Operation\n") + self.canceled = True for w in self.g_cancel, self.g_pause: - w.set_sensitive (False) - self.g_progbar.set_text ("Canceling Operation...") + w.set_sensitive(False) + self.g_progbar.set_text("Canceling Operation...") self.g_activityspin.stop() - gtk.main_iteration() + Gtk.main_iteration() while not self.x.childprocess: - gtk.main_iteration() + Gtk.main_iteration() if self.paused: self.x.childprocess.send_signal(SIGCONT) self.x.childprocess.terminate() self.show_working_progress(False) - - + # Called by [processing progbar] Pause button def action_pause_child_process(self, btn): """Suspend/resume gpg/openssl subprocess with SIGSTOP/SIGCONT.""" - + # We can't pause childprocess until it actually starts while not self.x.childprocess: - gtk.main_iteration() - + Gtk.main_iteration() + if self.paused: # Already paused, so, time to unpause - stderr.write ("\n") - self.paused = False - btn.set_relief (gtk.RELIEF_NONE) - self.g_progbar.set_text ("{} working...".format(self.engine)) + stderr.write("\n") + self.paused = False + btn.set_relief(Gtk.ReliefStyle.NONE) + self.g_progbar.set_text("{} working...".format(self.engine)) self.g_activityspin.start() self.x.childprocess.send_signal(SIGCONT) else: # Time to pause - stderr.write ("\n") - self.paused = True - btn.set_relief (gtk.RELIEF_NORMAL) - self.g_progbar.set_text ("Operation PAUSED") + stderr.write("\n") + self.paused = True + btn.set_relief(Gtk.ReliefStyle.NORMAL) + self.g_progbar.set_text("Operation PAUSED") self.g_activityspin.stop() self.x.childprocess.send_signal(SIGSTOP) - - - #------------------------------------------------------ MAIN XFACE FUNCTION + + # MAIN XFACE FUNCTION def launchxface(self, action): """Manage I/O between Gtk objects and our GpgXface or OpensslXface object.""" - self.canceled = False - self.paused = False + # User Canceled + self.canceled = False + self.paused = False self.x.childprocess = None - - ### PREPARE Xface ARGS - passwd = None - recip = None - localuser = None + + # PREPARE Xface ARGS + passwd = None + recip = None + localuser = None # symmetric & passwd symmetric = self.g_symmetric.get_active() if symmetric: @@ -1119,7 +1075,7 @@ def launchxface(self, action): self.infobar('x_missing_passphrase') return passwd = None # If passwd was '' , set to None, which will trigger gpg-agent if necessary - + # INTERLUDE: If operating in textinput mode, check for input text if not self.x.io['infile']: # Make sure textview has a proper message in it @@ -1127,15 +1083,16 @@ def launchxface(self, action): return False # Make TextView immutable to changes self.g_msgtxtview.set_sensitive(False) - self.fix_msgtxtviewcolor(False) - + self.fix_msgtxtview_color(False) + # enctoself enctoself = self.g_enctoself.get_active() # recip asymmetric = self.g_asymmetric.get_active() if asymmetric: recip = self.g_recip.get_text() - if not recip: recip = None # If recip was '' , set to None + if not recip: + recip = None # If recip was '' , set to None # cipher, base64 cipher = self.grab_activetext_combobox(self.g_cipher) base64 = self.g_plaintext.get_active() @@ -1154,11 +1111,11 @@ def launchxface(self, action): # localuser if self.g_chk_defkey.get_active(): localuser = self.g_defaultkey.get_text() - if not localuser: localuser = None - + if not localuser: + localuser = None + # INITIAL FILE INPUT MODE PREP if self.x.io['infile'] and not self.x.io['outfile']: - if base64 or action in 'clearsign': outfile = self.x.io['infile'] + '.asc' elif self.engine in 'OpenSSL': @@ -1167,10 +1124,10 @@ def launchxface(self, action): outfile = self.x.io['infile'] + '.sig' else: outfile = self.x.io['infile'] + '.gpg' - + if action in 'dec': outfile = self.x.io['infile'][:-4] - + if action not in 'verify': if self.g_signverify.get_active() and not self.g_chk_outfile.get_active(): pass @@ -1182,113 +1139,103 @@ def launchxface(self, action): return working_widgets = self.working_widgets_filemode - for w in working_widgets: w.set_sensitive(False) + for w in working_widgets: + w.set_sensitive(False) self.ib_filemode.hide() - + # FILE INPUT MODE PREP WHEN ALREADY HAVE OUTPUT FILE elif self.x.io['infile'] and self.x.io['outfile']: - working_widgets = self.working_widgets_filemode - for w in working_widgets: w.set_sensitive(False) + for w in working_widgets: + w.set_sensitive(False) self.ib_filemode.hide() - + # TEXT INPUT MODE PREP else: - working_widgets = self.working_widgets_textmode - for w in working_widgets: w.set_sensitive(False) - + for w in working_widgets: + w.set_sensitive(False) # Save textview buffer to Xface stdin self.x.io['stdin'] = self.buff.get_text(self.buff.get_start_iter(), - self.buff.get_end_iter()) - + self.buff.get_end_iter(), + False) + # Set working status + spinner + progress bar self.show_working_progress(True, action) # Clear Task Status self.buff2.set_text('') - + # Setup stderr file descriptors & update task status while processing self.x.io['stderr'] = pipe() - glib.io_add_watch( + GLib.io_add_watch( self.x.io['stderr'][0], - glib.IO_IN | glib.IO_HUP, + GLib.IOCondition.IN | GLib.IOCondition.HUP, self.update_task_status) - + if self.engine in 'OpenSSL': # ATTEMPT EN-/DECRYPTION w/OPENSSL Thread( target=self.x.openssl, args=(action, passwd, base64, cipher) - ).start() - + ).start() + else: # GPG if verbose: # Setup gpg-status file descriptors & update terminal while processing self.x.io['gstatus'] = pipe() - glib.io_add_watch( + GLib.io_add_watch( self.x.io['gstatus'][0], - glib.IO_IN | glib.IO_HUP, + GLib.IOCondition.IN | GLib.IOCondition.HUP, self.update_task_status, 'term') # ATTEMPT EN-/DECRYPTION w/GPG Thread( target=self.x.gpg, args=(action, encsign, digest, localuser, base64, symmetric, passwd, asymmetric, recip, enctoself, cipher, verbose, alwaystrust) - ).start() - + ).start() + # Wait for subprocess to finish or for Cancel button to be clicked c = 0 - while not self.x.childprocess or self.x.childprocess.returncode == None: - if self.canceled: break + while not self.x.childprocess or self.x.childprocess.returncode is None: + if self.canceled: + break if c % 15 == 0 and not self.paused: self.g_progbar.pulse() - gtk.main_iteration() + Gtk.main_iteration() c += 1 if self.quiting: # If application is shutting down return # Restore widgets to normal states - for w in working_widgets: w.set_sensitive(True) + for w in working_widgets: + w.set_sensitive(True) self.show_working_progress(False) - + # FILE INPUT MODE CLEANUP if self.x.io['infile']: - if self.canceled: # User Canceled! - self.ib_filemode.show() - if action in {'enc', 'dec'}: action = "{}rypt".format(action.title()) elif action in {'embedsign', 'clearsign', 'detachsign'}: action = "Sign" elif action in 'verify': action = action.title() - self.infobar('x_canceled_filemode', customtext=action) - elif self.x.childprocess.returncode == 0: # File Success! - if self.engine in 'OpenSSL' and action in 'enc': self.infobar('x_opensslenc_success_filemode', self.x.io['outfile'], cipher) - elif action in {'enc', 'dec'}: self.infobar('x_crypt_success_filemode', self.x.io['outfile'], action) - elif action in {'embedsign', 'clearsign'}: self.infobar('x_sign_success_filemode', self.x.io['outfile']) - elif action in 'detachsign': self.infobar('x_detachsign_success_filemode', self.x.io['outfile']) - elif action in 'verify': self.infobar('x_verify_success') - self.cleanup_filemode() - else: # File Fail! - self.ib_filemode.show() if action in 'verify': self.infobar('x_verify_failed') @@ -1301,38 +1248,31 @@ def launchxface(self, action): elif action in {'embedsign', 'clearsign', 'detachsign'}: action = 'sign' self.infobar('x_generic_failed_filemode', customtext=action) - + # TEXT INPUT MODE CLEANUP else: - self.set_stdstatus() self.g_msgtxtview.set_sensitive(True) - self.fix_msgtxtviewcolor(True) - + self.fix_msgtxtview_color(True) if self.canceled: # User Canceled! - if action in {'enc', 'dec'}: action = "{}rypt".format(action.title()) elif action in {'embedsign', 'clearsign', 'detachsign'}: action = "Sign" elif action in 'verify': action = action.title() - self.infobar('x_canceled_textmode', customtext=action) - elif self.x.childprocess.returncode == 0: # Text Success! - if action in 'verify': self.infobar('x_verify_success') else: # Set TextBuffer to gpg stdout - self.buff.set_text(self.x.io['stdout']) + b = self.x.io['stdout'].decode('utf-8') + self.buff.set_text(b) self.x.io['stdout'] = 0 if self.engine in 'OpenSSL' and action in 'enc': self.infobar('x_opensslenc_success_textmode', customtext=cipher) - else: # Text Fail! - if action in 'verify': self.infobar('x_verify_failed') return @@ -1344,43 +1284,41 @@ def launchxface(self, action): elif action in {'embedsign', 'clearsign', 'detachsign'}: action = 'sign' self.infobar('x_generic_failed_textmode', customtext=action) - - - #------------------------------------------ HELPERS FOR MAIN XFACE FUNCTION - - # CB for glib.io_add_watch() + + # HELPERS FOR MAIN XFACE FUNCTION + + # CB for GLib.io_add_watch() def update_task_status(self, fd, condition, output='task'): """Read data waiting in file descriptor; close fd if other end hangs up.""" - + # If there's data to be read, let's read it - if condition == glib.IO_IN: + if condition == GLib.IOCondition.IN: + b = read(fd, 1024).decode('utf-8') if output in 'task': # Output to Task Status - self.buff2.insert(self.buff2.get_end_iter(), read(fd, 1024)) + self.buff2.insert(self.buff2.get_end_iter(), b) else: # Output to stderr (will show if run from terminal) - stderr.write(read(fd, 1024)) + stderr.write(b) return True - # If other end of pipe hangs up, close our fd and destroy the watcher - elif condition == glib.IO_HUP: + elif condition == GLib.IOCondition.HUP: if output in 'term': stderr.write("\n") close(fd) return False - - + # Called when gpg/openssl begins and ends processing def show_working_progress(self, show=True, action=None): """Hide/show progress widgets; set/unset working status + activity spinner.""" - + # Show/hide progress bar & its buttons for w in self.g_progbar, self.g_cancel, self.g_pause: w.set_visible(show) - + if show: # If beginning processing: set progbar text + working status, start spinner - self.g_progbar.set_text ("{} working...".format(self.engine)) + self.g_progbar.set_text("{} working...".format(self.engine)) if action in {'embedsign', 'clearsign', 'detachsign'}: status = "Signing input ..." elif action in 'verify': @@ -1390,26 +1328,53 @@ def show_working_progress(self, show=True, action=None): self.g_statusbar.push(self.status, status) self.g_activityspin.set_visible(True) self.g_activityspin.start() - gtk.main_iteration() - + Gtk.main_iteration() else: # If finished processing: ensure progbar buttons are normal, reset status, stop spinner for w in self.g_cancel, self.g_pause: w.set_sensitive(True) - w.set_relief(gtk.RELIEF_NONE) + w.set_relief(Gtk.ReliefStyle.NONE) self.g_activityspin.stop() self.g_activityspin.set_visible(False) self.g_statusbar.pop(self.status) - - - #---------------------------------------------- RUN MAIN APPLICATION WINDOW - def main(self): - """Show main window, tweak some GTK+ settings and start GTK+ main loop.""" - self.g_window.show() - settings = gtk.settings_get_default() - settings.props.gtk_button_images = True - with gtk.gdk.lock: - gtk.main() + def loadmails_string_list(self): + """Return emails from all known keys.""" + mails = list() + if self.engine == 'OpenSSL': + return mails + cmd = split("gpg --list-public-keys --with-colons") + keys_string = check_output(cmd).decode('utf-8') + keys_all = keys_string.split('\n') + for line in keys_all: + line_fields = line.split(':') + if line_fields[0] == 'uid': + name_email = line_fields[9] + mails.append(name_email) + return mails + + # Loading names and emails for the recipient menu completion + def load_recipients_autocmplete(self): + mails = Gtk.ListStore(str) + for mail in self.loadmails_string_list(): + mails.append([mail]) + completion = Gtk.EntryCompletion() + completion.set_model(mails) + completion.set_text_column(0) + completion.set_match_func(self.recipient_contains, None) + self.g_recip.set_completion(completion) + + def recipient_contains(self, completion, key_string, iter, data): + model = completion.get_model() + # get the completion strings + modelstr = model[iter][0] + return key_string in modelstr + # RUN MAIN APPLICATION WINDOW + def main(self): + """Show main window, and start GTK+ main loop.""" + self.g_window.show() + self.g_window.connect("destroy", Gtk.main_quit) + self.g_window.show_all() + Gtk.main() diff --git a/modules/crypt_interface.py b/pyrite/crypt_interface.py similarity index 63% rename from modules/crypt_interface.py rename to pyrite/crypt_interface.py index b553809..1e25779 100644 --- a/modules/crypt_interface.py +++ b/pyrite/crypt_interface.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at +#!/usr/bin/env python3 # Copyright 2012, 2013 Ryan Sawhill Aroha # # License: @@ -20,30 +15,26 @@ # # You should have received a copy of the GNU General Public License # along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ -from sys import stderr from os import pipe, write, close from shlex import split from subprocess import Popen, PIPE, check_output +from sys import stderr from time import sleep - -def flatten_list_to_stderr(list): +def flatten_list_to_stderr(lines): stderr.write("-" * 79 + "\n") - for item in list: + for item in lines: stderr.write(item + " ") stderr.write("\n\n") - -class Gpg(): - """GPG/GPG2 interface for encryption/decryption/signing/verifying. +class Gpg: + """GPG interface for encryption/decryption/signing/verifying. - First thing: use subprocess module to call a gpg or gpg2 process, ensuring - that one of them is available on the system; if not, of course we have to + First thing: use subprocess module to call a gpg process, ensuring + that it is available on the system; if not, of course we have to quit (raise exception). Either way, that's all for __init__. See the docstring for the main method -- gpg() -- for next steps. @@ -51,79 +42,60 @@ class Gpg(): Security: Xface.gpg() can take a passphrase for symmetric enc/dec as an argument, but it never stores that passphrase on disk; the passphrase is passed to gpg via an os file descriptor. If any access to your secret key is - required, gpg() invokes gpg/gpg2 with gpg-agent enabled. + required, gpg() invokes gpg with gpg-agent enabled. """ - - - def __init__(self, show_version=True, firstchoice='gpg2'): - """Confirm we can run gpg or gpg2.""" - - def gpg1(): + + def __init__(self, show_version=True): + """Confirm we can run gpg.""" + + try: self.vers = Popen(['gpg', '--version'], stdout=PIPE).communicate()[0] - self.GPG_BINARY = 'gpg' - - def gpg2(): - self.vers = Popen(['gpg2', '--version'], stdout=PIPE).communicate()[0] - self.GPG_BINARY = 'gpg2' - - if firstchoice == 'gpg': - try: gpg1() - except: - try: gpg2() - except: - stderr.write("gpg, gpg2 not found on your system.\n\n") - raise - else: - try: gpg2() - except: - try: gpg1() - except: - stderr.write("gpg, gpg2 not found on your system.\n\n") - raise - + except: + stderr.write("gpg not found on your system.\n\n") + raise + # To show or not to show version info if show_version: stderr.write("{}\n".format(self.vers)) - + # I/O dictionary obj self.io = dict( - stdin='', # Stores input text for subprocess + stdin='', # Stores input text for subprocess stdout='', # Stores stdout stream from subprocess - stderr=0, # Stores tuple of r/w file descriptors for stderr stream + stderr=0, # Stores tuple of r/w file descriptors for stderr stream gstatus=0, # Stores tuple of r/w file descriptors for gpg-status stream - infile=0, # Input filename for subprocess + infile=0, # Input filename for subprocess outfile=0) # Output filename for subprocess - + self.childprocess = None - - + # Main gpg interface method def gpg( - self, - action= None, # One of: enc, dec, embedsign, clearsign, detachsign, verify - encsign= False, # Add '--sign' when encrypting? - digest= None, # One of: sha256, sha1, etc; None == use gpg defaults - localuser= None, # Value passed to --local-user to set default key for signing, etc - base64= True, # Add '--armor' when encrypting/signing? - symmetric= False, # Add '--symmetric'? - passwd= None, # Passphrase for symmetric - asymmetric= False, # Add '--encrypt'? - recip= None, # Recipients for asymmetric (semicolon-delimited) - enctoself= False, # Add first id from secret keyring as recipient? - cipher= None, # One of: aes256, 3des, etc; None == use gpg defaults - verbose= False, # Add '--verbose'? - alwaystrust=False, # Add '--trust-model always'? - yes= True # Add '--yes'? (will overwrite files) - ): - """Build a gpg cmdline and then launch gpg/gpg2, saving output appropriately. + self, + action=None, # One of: enc, dec, embedsign, clearsign, detachsign, verify + encsign=False, # Add '--sign' when encrypting? + digest=None, # One of: sha256, sha1, etc; None == use gpg defaults + localuser=None, # Value passed to --local-user to set default key for signing, etc + base64=True, # Add '--armor' when encrypting/signing? + symmetric=False, # Add '--symmetric'? + passwd=None, # Passphrase for symmetric + asymmetric=False, # Add '--encrypt'? + recip=None, # Recipients for asymmetric (semicolon-delimited) + enctoself=False, # Add first id from secret keyring as recipient? + cipher=None, # One of: aes256, 3des, etc; None == use gpg defaults + verbose=False, # Add '--verbose'? + alwaystrust=False, # Add '--trust-model always'? + yes=True # Add '--yes'? (will overwrite files) + ): + """Build a gpg cmdline and then launch gpg, saving output appropriately. This method inspects the contents of class attr 'io' -- a dict object that should - contain all of the following keys, at least initialized to 0 or '': + contain all the following keys, at least initialized to 0 or '': stdin # Input text for subprocess infile # Input filename for subprocess, in place of stdin outfile # Output filename if infile was given - io['infile'] should contain a filename OR be set to 0, in which case io'[stdin'] + io['infile'] should contain a filename OR be set to 0, in which case io['stdin'] must contain the input data. If using infile, outfile is not necessarily required, but it's probably a good idea unless you're doing sign-only. @@ -147,32 +119,32 @@ def gpg( the caller (i.e., by examining the Popen instance's returncode attribute). """ - + if self.io['infile'] and self.io['infile'] == self.io['outfile']: stderr.write("Same file for both input and output, eh? Is it going " "to work? ... NOPE. Chuck Testa.\n") raise Exception("infile, outfile must be different") - - fd_pwd_R = None - fd_pwd_W = None - useagent = True - cmd = [self.GPG_BINARY] - + + fd_pwd_R = None + fd_pwd_W = None + useagent = True + cmd = ['gpg'] + if self.io['gstatus']: # Status to file descriptor option cmd.append('--status-fd') cmd.append(str(self.io['gstatus'][1])) - + # Setup passphrase file descriptor for symmetric enc/dec if (action in 'enc' and symmetric and passwd and not encsign) or ( - action in 'dec' and symmetric and passwd): - useagent=False - fd_pwd_R, fd_pwd_W = pipe() - write(fd_pwd_W, passwd) - close(fd_pwd_W) - cmd.append('--passphrase-fd') - cmd.append(str(fd_pwd_R)) - + action in 'dec' and symmetric and passwd): + useagent = False + fd_pwd_R, fd_pwd_W = pipe() + write(fd_pwd_W, passwd) + close(fd_pwd_W) + cmd.append('--passphrase-fd') + cmd.append(str(fd_pwd_R)) + # Encrypt opts if action in 'enc': if encsign: @@ -191,48 +163,47 @@ def gpg( if enctoself: cmd.append('--recipient') if localuser: - cmd.append(localuser) + cmd.append("'" + localuser + "'") else: - cmd.append(self.get_gpgdefaultkey()) + cmd.append(self.get_gpg_default_key()) if recip: while recip[-1] == ' ' or recip[-1] == ';': recip = recip.strip() recip = recip.strip(';') for r in recip.split(';'): cmd.append('--recipient') - cmd.append(r) - + cmd.append("'" + r + "'") + # Decrypt opts elif action in 'dec': cmd.append('--decrypt') - + # Sign opts elif action in {'embedsign', 'clearsign', 'detachsign'}: - if action in 'embedsign': cmd.append('--sign') - elif action in 'clearsign': cmd.append('--clearsign') - elif action in 'detachsign': cmd.append('--detach-sign') + if action in 'embedsign': + cmd.append('--sign') + elif action in 'clearsign': + cmd.append('--clearsign') + elif action in 'detachsign': + cmd.append('--detach-sign') if digest: cmd.append('--digest-algo') cmd.append(digest) - + # Verify opts elif action in 'verify': cmd.append('--verify') - + # Wouldn't hurt to use armor for all, but it only works with these 3 if action in {'enc', 'embedsign', 'detachsign'}: if base64: cmd.append('--armor') - + # Action-independent opts if useagent: - if self.GPG_BINARY in 'gpg': - cmd.append('--use-agent') + cmd.append('--use-agent') else: - if self.GPG_BINARY in 'gpg': - cmd.append('--no-use-agent') - else: - cmd.append('--batch') + cmd.append('--no-use-agent') if localuser: cmd.append('--local-user') cmd.append(localuser) @@ -249,40 +220,41 @@ def gpg( cmd.append(self.io['outfile']) if self.io['infile']: cmd.append(self.io['infile']) - + # Print a separator + the command-arguments to stderr flatten_list_to_stderr(cmd) - - # If working direct with files, setup our Popen instance with no stdin + + # If working direct with files, set up our Popen instance with no stdin if self.io['infile']: self.childprocess = Popen(cmd, stdout=PIPE, stderr=self.io['stderr'][1]) # Otherwise, only difference for Popen is we need the stdin pipe else: - self.childprocess = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=self.io['stderr'][1]) - + b = self.io['stderr'] + self.childprocess = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=b[1]) + # Time to communicate! Save output for later - self.io['stdout'] = self.childprocess.communicate(input=self.io['stdin'])[0] - + b = self.io['stdin'].encode('utf-8') + self.io['stdout'] = self.childprocess.communicate(input=b)[0] + # Clear stdin from our dictionary asap, in case it's huge self.io['stdin'] = '' - + # Close os file descriptors - if fd_pwd_R: close(fd_pwd_R) + if fd_pwd_R: + close(fd_pwd_R) sleep(0.1) # Sleep a bit to ensure everything gets read close(self.io['stderr'][1]) if self.io['gstatus']: close(self.io['gstatus'][1]) - - - def get_gpgdefaultkey(self): - """Return key id of first secret key in gpg keyring.""" - return check_output(split( - "{} --list-secret-keys --with-colons --fast-list-mode" - .format(self.GPG_BINARY))).split(':', 5)[4] + def get_gpg_default_key(self): + """Return key id of first secret key in gpg keyring.""" + cmd = split("gpg --list-secret-keys --with-colons --fast-list-mode") + output = str(check_output(cmd)) + return output.split(':', 5)[4] -class Openssl(): +class Openssl: """OpenSSL interface for encryption/decryption. First thing: use subprocess module to call an openssl process, ensuring it @@ -296,47 +268,46 @@ class Openssl(): passed to openssl via an os file descriptor. """ - + def __init__(self, show_version=True): """Confirm we can run openssl.""" - + try: vers = Popen(['openssl', 'version'], stdout=PIPE).communicate()[0] except: stderr.write("OpenSSL not found on your system.\n\n") raise - + # To show or not to show version info if show_version: stderr.write("{}\n".format(vers)) - + # I/O dictionary obj self.io = dict( - stdin='', # Stores input text for subprocess + stdin='', # Stores input text for subprocess stdout='', # Stores stdout stream from subprocess - stderr=0, # Stores tuple of r/w file descriptors for stderr stream - infile=0, # Input filename for subprocess + stderr=0, # Stores tuple of r/w file descriptors for stderr stream + infile=0, # Input filename for subprocess outfile=0) # Output filename for subprocess - + self.childprocess = None - - + # Main openssl interface method def openssl( - self, - action, # One of: enc, dec - passwd, # Passphrase for symmetric - base64=True, # Add '-a' when encrypting/decrypting? - cipher=None, # Cipher in gpg-format; None = use aes256 - ): + self, + action, # One of: enc, dec + passwd, # Passphrase for symmetric + base64=True, # Add '-a' when encrypting/decrypting? + cipher=None, # Cipher in gpg-format; None = use aes256 + ): """Build an openssl cmdline and then launch it, saving output appropriately. This method inspects the contents of class attr 'io' -- a dict object that should - contain all of the following keys, at least initialized to 0 or '': + contain all the following keys, at least initialized to 0 or '': stdin # Input text for subprocess infile # Input filename for subprocess, in place of stdin outfile # Output filename -- required if infile was given - io['infile'] should contain a filename OR be set to 0, in which case io'[stdin'] + io['infile'] should contain a filename OR be set to 0, in which case io['stdin'] must contain the input data. Whether reading input from infile or stdin, each openssl command's stdout & @@ -347,35 +318,46 @@ def openssl( the caller (i.e., by examining the Popen instance's returncode attribute). """ - + if self.io['infile'] and self.io['infile'] == self.io['outfile']: stderr.write("Same file for both input and output, eh? Is it going " "to work? ... NOPE. Chuck Testa.\n") raise Exception("infile, outfile must be different") - - if cipher: cipher = cipher.lower() - if cipher == None: cipher = 'aes-256-cbc' - elif cipher == '3des': cipher = 'des-ede3-cbc' - elif cipher == 'cast5': cipher = 'cast5-cbc' - elif cipher == 'blowfish': cipher = 'bf-cbc' - elif cipher == 'aes': cipher = 'aes-128-cbc' - elif cipher == 'aes192': cipher = 'aes-192-cbc' - elif cipher == 'aes256': cipher = 'aes-256-cbc' - elif cipher == 'camellia128': cipher = 'camellia-128-cbc' - elif cipher == 'camellia192': cipher = 'camellia-192-cbc' - elif cipher == 'camellia256': cipher = 'camellia-256-cbc' - #else: cipher = 'aes-256-cbc' - - fd_pwd_R = None - fd_pwd_W = None - cmd = ['openssl', cipher, '-md', 'sha256', '-pass'] - + + if cipher: + cipher = cipher.lower() + if cipher is None: + cipher = 'aes-256-cbc' + elif cipher == '3des': + cipher = 'des-ede3-cbc' + elif cipher == 'cast5': + cipher = 'cast5-cbc' + elif cipher == 'blowfish': + cipher = 'bf-cbc' + elif cipher == 'aes': + cipher = 'aes-128-cbc' + elif cipher == 'aes192': + cipher = 'aes-192-cbc' + elif cipher == 'aes256': + cipher = 'aes-256-cbc' + elif cipher == 'camellia128': + cipher = 'camellia-128-cbc' + elif cipher == 'camellia192': + cipher = 'camellia-192-cbc' + elif cipher == 'camellia256': + cipher = 'camellia-256-cbc' + # else: cipher = 'aes-256-cbc' + + fd_pwd_R = None + fd_pwd_W = None + cmd = ['openssl', cipher, '-md', 'sha256', '-pass'] + # Setup passphrase file descriptors fd_pwd_R, fd_pwd_W = pipe() write(fd_pwd_W, passwd) close(fd_pwd_W) cmd.append('fd:{}'.format(fd_pwd_R)) - + if base64: cmd.append('-a') if action in 'enc': @@ -387,26 +369,25 @@ def openssl( cmd.append(self.io['infile']) cmd.append('-out') cmd.append(self.io['outfile']) - + # Print a separator + the command-arguments to stderr flatten_list_to_stderr(cmd) - - # If working direct with files, setup our Popen instance with no stdin + + # If working direct with files, set up our Popen instance with no stdin if self.io['infile']: self.childprocess = Popen(cmd, stdout=PIPE, stderr=self.io['stderr'][1]) # Otherwise, only difference for Popen is we need the stdin pipe else: self.childprocess = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=self.io['stderr'][1]) - + # Time to communicate! Save output for later - self.io['stdout'] = self.childprocess.communicate(input=self.io['stdin'])[0] - + b = self.io['stdin'].encode('utf-8') + self.io['stdout'] = self.childprocess.communicate(input=b)[0] + # Clear stdin from our dictionary asap, in case it's huge self.io['stdin'] = '' - + # Close os file descriptors close(fd_pwd_R) sleep(0.1) # Sleep a bit to ensure everything gets read close(self.io['stderr'][1]) - - diff --git a/pyrite/messages.py b/pyrite/messages.py new file mode 100644 index 0000000..c385378 --- /dev/null +++ b/pyrite/messages.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python3 +# Copyright 2012, 2013 Ryan Sawhill Aroha +# +# License: +# +# Pyrite is free software: you can 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. +# +# Pyrite is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Pyrite. If not, see . + +SUCCESS = 0 +INFO = 1 +QUESTION = 2 +WARNING = 3 +ERROR = 4 + + +def msg(text, type, icon, timeout=5): + """Dictionar-ify input arguments.""" + return {'text': text, 'type': type, 'icon': icon, 'timeout': timeout} + + +# INFOBAR MESSAGES FOR MAIN WINDOW +MESSAGE_DICT = dict( + + # Backend Engine + engine_openssl_missing=msg( + ("Your system does not appear to have OpenSSL."), + INFO, WARNING), + + engine_gpg_missing=msg( + ("GnuPG not found. Operating in OpenSSL fallback-mode.\n" + "To make full use of this program you need gpg installed.\n" + "Without it, you won't have access key-based functions like\n" + "asymmetric encryption or singing."), + INFO, WARNING, 20), + + engine_all_missing=msg( + ("This program requires one of: gpg or openssl\n" + "None of these were found on your system. You can look around\n" + "the interface, but to have real fun you'll need to install gpg\n" + "from your linux distribution's software repository."), + ERROR, WARNING, 0), + + engine_openssl_notice=msg( + ("OpenSSL only supports symmetric {{en,de}}cryption.\n" + "All key-based functions are disabled."), + INFO, INFO, 7), + + # Textview Message Area Operations + txtview_empty=msg( + ("{customtext}"), + INFO, WARNING, 2), + + txtview_fileopen_error=msg( + ("Error. Could not open file:\n" + "{filename}"), + WARNING, ERROR), + + txtview_fileopen_binary_error=msg( + ("To operate on binary files, use the\n" + "Input File For Direct Operation chooser button."), + INFO, WARNING, 8), + + txtview_save_success=msg( + ("Saved contents of Message area to file:\n" + "{filename}"), + INFO, SUCCESS), + + txtview_save_error=msg( + ("Error. Could not save to file:\n" + "{filename}"), + WARNING, ERROR), + + txtview_copyall_success=msg( + ("Copied contents of Message area to clipboard."), + INFO, SUCCESS, 3), + + # Filemode Operations + filemode_fileopen_error=msg( + ("Error. Could not open file:\n" + "{filename}\n" + "Choose a new file."), + WARNING, ERROR), + + filemode_blue_banner=msg( + ("Encrypt, Decrypt, Sign, or Verify?\n" + "Choose an action to perform on file:\n" + "{filename}\n" + "You will be prompted for an output filename if necessary."), + QUESTION, QUESTION, 0), + + # Main xface (Enc/Dec/Sign/Verify) Operations + x_missing_passphrase=msg( + ("Passphrase?"), + INFO, QUESTION, 3), + + x_canceled_filemode=msg( + ("{customtext} operation canceled.\n" + "To choose different input or output filenames, select Cancel\n" + "from the blue bar below."), + INFO, WARNING, 6), + + x_canceled_textmode=msg( + ("{customtext} operation canceled."), + INFO, WARNING, 4), + + x_opensslenc_success_filemode=msg( + ("OpenSSL encrypted input file with {customtext} cipher;\n" + "saved output to file:\n" + "{filename}\n" + "In order to decrypt that file in the future, you will need to \n" + "remember which cipher you used .. or guess until you figure it out."), + INFO, SUCCESS, 10), + + x_opensslenc_success_textmode=msg( + ("OpenSSL encrypted input using {customtext} cipher.\n" + "In order to decrypt the output in the future, you will need to \n" + "remember which cipher you used .. or guess until you figure it out."), + INFO, SUCCESS, 9), + + x_crypt_success_filemode=msg( + ("Saved {customtext}rypted copy of input to file:\n" + "{filename}"), + INFO, SUCCESS), + + x_sign_success_filemode=msg( + ("Saved signed copy of input to file:\n" + "{filename}"), + INFO, SUCCESS), + + x_detachsign_success_filemode=msg( + ("Saved detached signature of input to file:\n" + "{filename}"), + INFO, SUCCESS), + + x_verify_success=msg( + ("Signature verified. Data integrity intact."), + INFO, SUCCESS, 4), + + x_verify_failed=msg( + ("Signature or data integrity could not be verified.\n" + "See Task Status for details."), + WARNING, ERROR, 7), + + x_missing_recip=msg( + ("For whom do you want to encrypt your message?\n" + "If you don't want to enter recipients and you don't want to select\n" + " Enc. To Self, you must add one of the directives\n" + "\tdefault-recipient-self\n" + "\tdefault-recipient name\n" + "to your gpg.conf file."), + WARNING, QUESTION, 0), + + x_generic_failed_filemode=msg( + ("Problem {customtext}ing file.\n" + "See Task Status for details. Try a different passphrase or Cancel."), + WARNING, ERROR, 8), + + x_generic_failed_textmode=msg( + ("Problem {customtext}ing input.\n" + "See Task Status for details."), + WARNING, ERROR), + + # OpenSSL Cipher Warnings + cipher_openssl_no_default=msg( + ("OpenSSL has no default cipher.\n" + "AES256 is a good choice."), + INFO, INFO, 7), + + cipher_openssl_no_twofish=msg( + ("OpenSSL has no support for the Twofish cipher."), + INFO, INFO), + + cipher_openssl_aes_note=msg( + ("Note for the command-line geeks:\n" + "AES translates to OpenSSL's aes-128-cbc."), + INFO, INFO), + + # Preferences Actions + preferences_save_success=msg( + ("Saved preferences to {filename}\n" + "but no changes made to current session."), + INFO, SUCCESS), + + preferences_apply_success=msg( + ("Saved preferences to {filename}\n" + "and applied them to current session."), + INFO, SUCCESS), + +) + +# INFOBAR MESSAGES FOR PREFERENCES DIALOG +PREFS_MESSAGE_DICT = dict( + + prefs_save_failed=msg( + ("Saving preferences failed.\n" + "Unable to open config file {filename} for writing."), + ERROR, WARNING, 10), + + prefs_reverted=msg( + ("Reverted to user-saved preferences."), + INFO, SUCCESS, 3), + + prefs_reset_to_defaults=msg( + ("Preferences reset to defaults. You still need to Save or Apply."), + INFO, SUCCESS, 3), + + prefs_notice_enctoself=msg( + ("If you want Encrypt to Self on in Symmetric mode, you must set\n" + "Encryption Type to 'Both'."), + INFO, INFO), + + prefs_notice_addsig=msg( + ("If you want Add Signature on in Symmetric mode, you must also enable\n" + "Advanced."), + INFO, INFO), + + prefs_notice_enc_both=msg( + ("In order for both encryption types to be on by default, Advanced will also be\n" + "turned on, whether or not you select it now."), + INFO, INFO), + +) diff --git a/modules/prefs.py b/pyrite/prefs.py similarity index 51% rename from modules/prefs.py rename to pyrite/prefs.py index 4074209..8664dca 100644 --- a/modules/prefs.py +++ b/pyrite/prefs.py @@ -1,9 +1,4 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# This file is part of Pyrite. -# Last file mod: 2013/09/15 -# Latest version at +#!/usr/bin/env python3 # Copyright 2012, 2013 Ryan Sawhill Aroha # # License: @@ -20,19 +15,23 @@ # # You should have received a copy of the GNU General Public License # along with Pyrite. If not, see . -# -#------------------------------------------------------------------------------ # StdLib: -import gtk -import glib -import cPickle as pickle +import gi + +gi.require_version('GLib', '2.0') +gi.require_version('Gdk', '3.0') +gi.require_version('Gtk', '3.0') +from gi.repository import GLib +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GObject +import pickle as pickle from sys import stderr from os import access, R_OK # Custom Modules: -import cfg -from messages import PREFS_MESSAGE_DICT as MESSAGE_DICT - +from . import cfg +from .messages import PREFS_MESSAGE_DICT as MESSAGE_DICT class Preferences: @@ -41,10 +40,9 @@ class Preferences: Try to read preferences from user preferences file; failing that, initialize good defaults. This class also includes the Preferences-setting window. """ - - + def __init__(self, reset_defaults=False): - + try: if reset_defaults: raise Exception @@ -54,7 +52,7 @@ def __init__(self, reset_defaults=False): raise Exception self.p = dict(pickle.load(f)) stderr.write("Pyrite loaded preferences from file {!r}\n".format(cfg.USERPREF_FILE)) - + except: stderr.write("Pyrite loaded default preferences\n") # Default preferences @@ -83,177 +81,171 @@ def __init__(self, reset_defaults=False): taskstatus=True, verbose=False, wrap=True, - opc_slider=False, - opacity=100, msgfntsize=9, errfntsize=7, color_fg='#000000000000', color_bg='#ffffffffffff') - - + def infobar(self, id, filename=None, customtext=None): """Popup a new auto-hiding InfoBar.""" - + # CB for destroy timeout def destroy_ibar(): self.ibar_timeout = 0 self.ibar.destroy() - self.window.resize(1,1) - + self.window.resize(1, 1) + # If infobar already active: delete old timeout, destroy old ibar if self.ibar_timeout > 0: - glib.source_remove(self.ibar_timeout) + GObject.source_remove(self.ibar_timeout) destroy_ibar() - + # Find the needed dictionary inside our message dict, by id MSG = MESSAGE_DICT[id] - # Use value from MSG type & icon to lookup Gtk constant, e.g. gtk.MESSAGE_INFO - msgtype = cfg.MSGTYPES[ MSG['type'] ] - imgtype = cfg.IMGTYPES[ MSG['icon'] ] + # Use value from MSG type & icon to lookup Gtk constant, e.g. Gtk.MessageType.INFO + msgtype = cfg.MSGTYPES[MSG['type']] + imgtype = cfg.IMGTYPES[MSG['icon']] # Replace variables in message text & change text color message = ("" + MSG['text'].format(filename=filename, customtext=customtext) + "") - + # Now that we have all the data we need, START creating! - self.ibar = gtk.InfoBar() + self.ibar = Gtk.InfoBar() self.ibar.set_message_type(msgtype) - self.vbox_ib.pack_end (self.ibar, False, False) - img = gtk.Image() - img.set_from_stock (imgtype, gtk.ICON_SIZE_LARGE_TOOLBAR) - label = gtk.Label() - label.set_markup (message) - content = self.ibar.get_content_area() - content.pack_start (img, False, False) - content.pack_start (label, False, False) - img.show () - label.show () - self.ibar.show () - self.ibar_timeout = glib.timeout_add_seconds(MSG['timeout'], destroy_ibar) - - + self.vbox_ib.pack_end(self.ibar, False, False, 0) + img = Gtk.Image() + img.set_from_stock(imgtype, Gtk.IconSize.LARGE_TOOLBAR) + label = Gtk.Label() + label.set_markup(message) + content = self.ibar.get_content_area() + content.pack_start(img, False, False, 0) + content.pack_start(label, False, False, 0) + img.show() + label.show() + self.ibar.show() + self.ibar_timeout = GLib.timeout_add_seconds(MSG['timeout'], destroy_ibar) + def open_preferences_window(self, parentwindow): """Show the preferences window. Duh.""" self.ibar_timeout = 0 - builder = gtk.Builder() + builder = Gtk.Builder() builder.add_from_file(cfg.ASSETDIR + 'ui/preferences.glade') # Main window - self.window = builder.get_object('window1') - self.btn_save = builder.get_object('btn_save') - self.btn_apply = builder.get_object('btn_apply') - self.vbox_ib = builder.get_object('vbox_ib') + self.window = builder.get_object('window1') + self.btn_save = builder.get_object('btn_save') + self.btn_apply = builder.get_object('btn_apply') + self.vbox_ib = builder.get_object('vbox_ib') # Main Operation Mode - self.cb_opmode = builder.get_object('cb_opmode') + self.cb_opmode = builder.get_object('cb_opmode') # Engine - self.cb_backend = builder.get_object('cb_backend') + self.cb_backend = builder.get_object('cb_backend') # Enc/Dec Mode - self.cb_enctype = builder.get_object('cb_enctype') - self.tg_advanced = builder.get_object('tg_advanced') - self.tg_enctoself = builder.get_object('tg_enctoself') - self.cb_cipher = builder.get_object('cb_cipher') - self.tg_addsig = builder.get_object('tg_addsig') + self.cb_enctype = builder.get_object('cb_enctype') + self.tg_advanced = builder.get_object('tg_advanced') + self.tg_enctoself = builder.get_object('tg_enctoself') + self.cb_cipher = builder.get_object('cb_cipher') + self.tg_addsig = builder.get_object('tg_addsig') # Mode-Independent - self.cb_digest = builder.get_object('cb_digest') - self.tg_defkey = builder.get_object('tg_defkey') - self.ent_defkey = builder.get_object('ent_defkey') - self.cb_txtoutput = builder.get_object('cb_txtoutput') - self.tg_expander = builder.get_object('tg_expander') + self.cb_digest = builder.get_object('cb_digest') + self.tg_defkey = builder.get_object('tg_defkey') + self.ent_defkey = builder.get_object('ent_defkey') + self.cb_txtoutput = builder.get_object('cb_txtoutput') + self.tg_expander = builder.get_object('tg_expander') # Sign/Verify Mode - self.tg_svoutfiles = builder.get_object('tg_svoutfiles') - self.cb_text_sigmode= builder.get_object('cb_text_sigmode') - self.cb_file_sigmode= builder.get_object('cb_file_sigmode') + self.tg_svoutfiles = builder.get_object('tg_svoutfiles') + self.cb_text_sigmode = builder.get_object('cb_text_sigmode') + self.cb_file_sigmode = builder.get_object('cb_file_sigmode') # Display - self.tg_taskstatus = builder.get_object('tg_taskstatus') - self.tg_verbose = builder.get_object('tg_verbose') - self.tg_wrap = builder.get_object('tg_wrap') - self.tg_opc_slider = builder.get_object('tg_opc_slider') - self.sp_opacity = builder.get_object('sp_opacity') - self.sp_msgfntsize = builder.get_object('sp_msgfntsize') - self.sp_errfntsize = builder.get_object('sp_errfntsize') - self.btn_color_fg = builder.get_object('btn_color_fg') - self.btn_color_bg = builder.get_object('btn_color_bg') + self.tg_taskstatus = builder.get_object('tg_taskstatus') + self.tg_verbose = builder.get_object('tg_verbose') + self.tg_wrap = builder.get_object('tg_wrap') + self.sp_msgfntsize = builder.get_object('sp_msgfntsize') + self.sp_errfntsize = builder.get_object('sp_errfntsize') + self.btn_color_fg = builder.get_object('btn_color_fg') + self.btn_color_bg = builder.get_object('btn_color_bg') # TODO: Advanced tab - #self.tg_args_gpg_e = builder.get_object('tg_args_gpg_e') - #self.en_args_gpg_e = builder.get_object('en_args_gpg_e') - self.window.set_transient_for(parentwindow) + # self.tg_args_gpg_e = builder.get_object('tg_args_gpg_e') + # self.en_args_gpg_e = builder.get_object('en_args_gpg_e') + # self.set_transient_for(parentwindow) if access(cfg.USERPREF_FILE, R_OK): btn_revert = builder.get_object('btn_revert') btn_revert.set_sensitive(True) self.populate_pref_window_prefs() builder.connect_signals(self) self.window.show() - - + def populate_pref_window_prefs(self): """Set state of widgets in prefs window via preferences.""" # Main Operation Mode - self.cb_opmode.set_active (self.p['opmode']) + self.cb_opmode.set_active(self.p['opmode']) # Engine - self.cb_backend.set_active (self.p['backend']) + self.cb_backend.set_active(self.p['backend']) # Enc/Dec Mode - self.cb_enctype.set_active (self.p['enctype']) - self.tg_advanced.set_active (self.p['advanced']) - self.tg_enctoself.set_active (self.p['enctoself']) - self.cb_cipher.set_active (self.p['cipher']) - self.tg_addsig.set_active (self.p['addsig']) + self.cb_enctype.set_active(self.p['enctype']) + self.tg_advanced.set_active(self.p['advanced']) + self.tg_enctoself.set_active(self.p['enctoself']) + self.cb_cipher.set_active(self.p['cipher']) + self.tg_addsig.set_active(self.p['addsig']) # Mode-Independent - self.cb_digest.set_active (self.p['digest']) - self.tg_defkey.set_active (self.p['defkey']) - self.ent_defkey.set_text (self.p['defkeytxt']) - self.cb_txtoutput.set_active (self.p['txtoutput']) - self.tg_expander.set_active (self.p['expander']) + self.cb_digest.set_active(self.p['digest']) + self.tg_defkey.set_active(self.p['defkey']) + self.ent_defkey.set_text(self.p['defkeytxt']) + self.cb_txtoutput.set_active(self.p['txtoutput']) + self.tg_expander.set_active(self.p['expander']) # Sign/Verify Mode - self.tg_svoutfiles.set_active (self.p['svoutfiles']) - self.cb_text_sigmode.set_active (self.p['text_sigmode']) - self.cb_file_sigmode.set_active (self.p['file_sigmode']) + self.tg_svoutfiles.set_active(self.p['svoutfiles']) + self.cb_text_sigmode.set_active(self.p['text_sigmode']) + self.cb_file_sigmode.set_active(self.p['file_sigmode']) # Display - self.tg_taskstatus.set_active (self.p['taskstatus']) - self.tg_verbose.set_active (self.p['verbose']) - self.tg_wrap.set_active (self.p['wrap']) - self.tg_opc_slider.set_active (self.p['opc_slider']) - self.sp_opacity.set_value (self.p['opacity']) - self.sp_msgfntsize.set_value (self.p['msgfntsize']) - self.sp_errfntsize.set_value (self.p['errfntsize']) - self.btn_color_fg.set_color (gtk.gdk.color_parse(self.p['color_fg'])) - self.btn_color_bg.set_color (gtk.gdk.color_parse(self.p['color_bg'])) - - + self.tg_taskstatus.set_active(self.p['taskstatus']) + self.tg_verbose.set_active(self.p['verbose']) + self.tg_wrap.set_active(self.p['wrap']) + self.sp_msgfntsize.set_value(self.p['msgfntsize']) + self.sp_errfntsize.set_value(self.p['errfntsize']) + + fg_color = Gdk.Color(0, 0, 0) + fg_color.parse(self.p['color_fg']) + + bg_color = Gdk.Color(0, 0, 0) + bg_color.parse(self.p['color_bg']) + + self.btn_color_fg.set_color(fg_color) + self.btn_color_bg.set_color(bg_color) + def capture_current_prefs(self): """Capture current state of widgets in prefs window & save as preferences.""" self.p = { # Main Operation Mode - 'opmode' : self.cb_opmode.get_active(), + 'opmode': self.cb_opmode.get_active(), # Engine - 'backend' : self.cb_backend.get_active(), + 'backend': self.cb_backend.get_active(), # Enc/Dec Mode - 'enctype' : self.cb_enctype.get_active(), - 'advanced' : self.tg_advanced.get_active(), - 'enctoself' : self.tg_enctoself.get_active(), - 'cipher' : self.cb_cipher.get_active(), - 'addsig' : self.tg_addsig.get_active(), + 'enctype': self.cb_enctype.get_active(), + 'advanced': self.tg_advanced.get_active(), + 'enctoself': self.tg_enctoself.get_active(), + 'cipher': self.cb_cipher.get_active(), + 'addsig': self.tg_addsig.get_active(), # Mode-Independent - 'digest' : self.cb_digest.get_active(), - 'defkey' : self.tg_defkey.get_active(), - 'defkeytxt' : self.ent_defkey.get_text(), - 'txtoutput' : self.cb_txtoutput.get_active(), - 'expander' : self.tg_expander.get_active(), + 'digest': self.cb_digest.get_active(), + 'defkey': self.tg_defkey.get_active(), + 'defkeytxt': self.ent_defkey.get_text(), + 'txtoutput': self.cb_txtoutput.get_active(), + 'expander': self.tg_expander.get_active(), # Sign/Verify Mode - 'svoutfiles' : self.tg_svoutfiles.get_active(), + 'svoutfiles': self.tg_svoutfiles.get_active(), 'text_sigmode': self.cb_text_sigmode.get_active(), 'file_sigmode': self.cb_file_sigmode.get_active(), # Display - 'taskstatus' : self.tg_taskstatus.get_active(), - 'verbose' : self.tg_verbose.get_active(), - 'wrap' : self.tg_wrap.get_active(), - 'opc_slider' : self.tg_opc_slider.get_active(), - 'opacity' : self.sp_opacity.get_value(), - 'msgfntsize' : self.sp_msgfntsize.get_value(), - 'errfntsize' : self.sp_errfntsize.get_value(), - 'color_fg' : self.btn_color_fg.get_color().to_string(), - 'color_bg' : self.btn_color_bg.get_color().to_string()} + 'taskstatus': self.tg_taskstatus.get_active(), + 'verbose': self.tg_verbose.get_active(), + 'wrap': self.tg_wrap.get_active(), + 'msgfntsize': self.sp_msgfntsize.get_value(), + 'errfntsize': self.sp_errfntsize.get_value(), + 'color_fg': self.btn_color_fg.get_color().to_string(), + 'color_bg': self.btn_color_bg.get_color().to_string()} return self.p - - + # Called by Save button def save_prefs(self): """Attempt to save user prefs to homedir prefs file.""" @@ -266,44 +258,37 @@ def save_prefs(self): self.infobar('prefs_save_failed', cfg.USERPREF_FILE) return False return True - - + # Called by Cancel button def action_cancel_prefs(self, w): """Close prefs window without doing anything.""" self.window.destroy() - - + # Called by Revert button def action_revert_prefs(self, w): """Reset state of widgets in prefs window via external preferences file, if avail.""" self.__init__() self.populate_pref_window_prefs() self.infobar('prefs_reverted') - - + # Called by Defaults button def action_default_prefs(self, w): """Reset state of widgets in prefs window to predefined defaults.""" self.__init__(reset_defaults=True) self.populate_pref_window_prefs() self.infobar('prefs_reset_to_defaults') - - + def action_tg_enctoself(self, w): """Show some info when user enables enctoself toggle.""" if w.get_active(): self.infobar('prefs_notice_enctoself') - - + def action_tg_addsig(self, w): """Show some info when user enables addsig toggle.""" if w.get_active(): self.infobar('prefs_notice_addsig') - - + def action_cb_enctype(self, w): """Show some info when user chooses 'Both' in enctype combobox.""" if w.get_active() == 2: self.infobar('prefs_notice_enc_both') - diff --git a/ui/about.glade b/ui/about.glade index e62dae1..f240220 100644 --- a/ui/about.glade +++ b/ui/about.glade @@ -1,17 +1,17 @@ - - + - False - 5 - True - dialog - True - Pyrite - Copyright © 2012, 2013 Ryan Sawhill Aroha - GnuPG (gpg/gpg2) encrypting, decrypting, signing, and verifying - http://github.com/ryran/pyrite + False + 5 + True + dialog + True + Pyrite + Copyright © 2012, 2013 Ryan Sawhill Aroha; + Maintainer: Sergey Ponomarev <stokito@gmail.com> + GnuPG (gpg) encrypting, decrypting, signing, and verifying + https://github.com/stokito/pyrite This program is free software: you can 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 @@ -25,23 +25,24 @@ GNU 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://gnu.org/licenses/gpl.html>. Ryan Sawhill Aroha <rsaw@redhat.com> - We need translators! + We need translators! We need someone to design some good icons! + image-missing - + True - False + False 2 - + True - False - end + False + end False True - end + end 0 diff --git a/ui/main.glade b/ui/main.glade index ea88f4c..af7cc4d 100644 --- a/ui/main.glade +++ b/ui/main.glade @@ -1,55 +1,54 @@ - - + True - False + False gtk-clear True - False + False gtk-zoom-in True - False + False gtk-zoom-out True - False + False gtk-execute True - False + False gtk-clear True - False + False gtk-revert-to-saved True - False + False gtk-apply True - False + False gtk-open True - False + False gtk-save True - False + False gtk-save-as @@ -143,117 +142,117 @@ - False + False Pyrite - center + center True - False + False True - False + False - False + False True - False + False _File - True + True True - False + False C_lear - False + False True - False - True - Clear all text/file buffers - True + False + True + Clear all text/file buffers + True image6 - False - True - + False + True + _Open Text File as Message - False + False True - False - True - Open text file in Message area - True + False + True + Open text file in Message area + True img_open - False - True - + False + True + _Save Copy of Message - False + False True - False - Save Message to text file - True + False + Save Message to text file + True img_saveas - False - True - + False + True + - False + False True - False + False Use OpenSSL as Engine - False + False True - False - True - Switch between using OpenSSL or GnuPG as the backend - True + False + True + Switch between using OpenSSL or GnuPG as the backend + True image9 - False - True - + False + True + - False + False True - False + False gtk-quit - False + False True - False - True - True - True - + False + True + True + True + @@ -262,103 +261,77 @@ - False + False True - False + False Edit - True + True True - False - - - gtk-undo - False - True - False - False - True - True - True - - - - - - gtk-redo - False - True - False - False - True - True - True - - - + False - False + False True - False + False gtk-cut - False + False True - False - True - True - True + False + True + True + True gtk-copy - False + False True - False - True - True - True + False + True + True + True gtk-paste - False + False True - False - True - True - True + False + True + True + True - False + False True - False + False gtk-preferences - False + False True - False - True - True - True - True - + False + True + True + True + True + @@ -367,86 +340,86 @@ - False + False True - False + False _View - True + True True - False + False - False + False True - False - True - Toggles line-wrapping in Message area + False + True + Toggles line-wrapping in Message area This will not add newline characters to Message Text _Wrapping - True + True True - False + False True - False - True - Show/hide side pane containing gpg/openssl cmd stderr (success/failure messages) + False + True + Show/hide side pane containing gpg/openssl cmd stderr (success/failure messages) _Task Status Side Panel - True + True True - False + False True - False - True - Enable/disable verbose status output from gpg (displayed in side panel) + False + True + Enable/disable verbose status output from gpg (displayed in side panel) _Verbose Output in Task Status - True + True - False + False True - False + False Increase Font Size - False + False True - False - True + False + True image7 - False - True - + False + True + Decrease Font Size - False + False True - False - True + False + True image8 - False - True - + False + True + @@ -455,24 +428,24 @@ This will not add newline characters to Message - False + False True - False + False Help - True + True True - False + False gtk-about - False + False True - False - True - True - True + False + True + True + True @@ -490,12 +463,12 @@ This will not add newline characters to Message True - False + False 3 True - False + False False @@ -507,23 +480,22 @@ This will not add newline characters to Message True - False - edge + False _Encrypt - False + False True - True - True - True - <i>Ctrl+E</i> + True + False + True + True + <i>Ctrl+E</i> img_encrypt none - True - False - + True + False @@ -534,18 +506,18 @@ This will not add newline characters to Message _Decrypt - False + False True - True - True - True - <i>Ctrl+D</i> + True + False + True + True + <i>Ctrl+D</i> img_decrypt none - True - False - + True + False @@ -563,7 +535,7 @@ This will not add newline characters to Message True - False + False @@ -576,16 +548,16 @@ This will not add newline characters to Message C_lear - False + False True - True - True - True - Clear all text/file buffers + True + False + True + True + Clear all text/file buffers img_clear none - True - False + True @@ -594,27 +566,10 @@ This will not add newline characters to Message 3 - - - 70 - True - 0 - False - left - - - - False - True - 6 - end - 4 - - True - False + False @@ -626,8 +581,8 @@ This will not add newline characters to Message - False - 0.02 + False + 0.02 True @@ -638,31 +593,31 @@ This will not add newline characters to Message True - False + False False True 2 - end + end 6 - False - True - True - True - Pause processing + False + True + False + True + True + Pause processing none - False True - False + False gtk-media-pause @@ -670,24 +625,24 @@ This will not add newline characters to Message False True - end + end 7 - False - True - True - True - Cancel processing + False + True + False + True + True + Cancel processing none - False True - False + False gtk-cancel @@ -695,7 +650,7 @@ This will not add newline characters to Message False True - end + end 8 @@ -709,12 +664,12 @@ This will not add newline characters to Message True - False + False 1 True - False + False False @@ -726,17 +681,17 @@ This will not add newline characters to Message Sign/Verif_y Mode - False + False True - True - False - Sign-only / verify-only mode + True + False + False + Sign-only / verify-only mode For adding a signature to a message/file without encrypting it or for verifying a signed message/file that isn't encrypted - True - False + True True - True + True toggle_mode_encdec @@ -750,16 +705,16 @@ For adding a signature to a message/file without encrypting it or for verifying Choose Output Filenames - False - True - False - True - When signing external files, the output filenames are automatically chosen by gpg -- output is saved to the same directory as the input file and an extension is added based on the options used + False + True + False + False + True + When signing external files, the output filenames are automatically chosen by gpg -- output is saved to the same directory as the input file and an extension is added based on the options used Check this if you wish to choose the output filename yourself (e.g., because the input file is in a directory you can't write to) - True - False - True + True + True False @@ -771,7 +726,7 @@ Check this if you wish to choose the output filename yourself (e.g., because the True - False + False False @@ -783,16 +738,16 @@ Check this if you wish to choose the output filename yourself (e.g., because the Enc/Dec _Mode - False + False True - True - False - True - Encrypt / decrypt / encrypt + sign mode - True - False + True + False + False + True + Encrypt / decrypt / encrypt + sign mode + True True - True + True False @@ -804,17 +759,17 @@ Check this if you wish to choose the output filename yourself (e.g., because the _Symmetric - False + False True - True - False - True - Symmetric encryption/decryption + True + False + False + True + Symmetric encryption/decryption Requires specifying a passphrase which is used as a shared key (for both encryption & decryption) - True - False - True + True + True @@ -827,17 +782,17 @@ Requires specifying a passphrase which is used as a shared key (for both encrypt _Asymmetric - False + False True - True - False - True - Asymmetric encryption/decryption + True + False + False + True + Asymmetric encryption/decryption Requires specifying recipients whose public keys will be used for encryption; or for decryption, it requires access to your gpg secret key - True - False - True + True + True @@ -850,17 +805,17 @@ Requires specifying recipients whose public keys will be used for encryption; or Adva_nced - False + False True - True - False - True - Allow mixing simple symmetric encryption with asymmetric encryption and/or signing + True + False + False + True + Allow mixing simple symmetric encryption with asymmetric encryption and/or signing When creating a signed + symmetrically-encrypted message, anything in the passphrase entry box will be ignored -- gpg-agent will need to ask for both the symmetric encryption key (passphrase) and [potentially] the passphrase to your secret key - True - False - True + True + True @@ -880,12 +835,12 @@ When creating a signed + symmetrically-encrypted message, anything in the passph True - False + False 1 True - False + False False @@ -898,11 +853,11 @@ When creating a signed + symmetrically-encrypted message, anything in the passph True False - False + False _Passphrase: - True - True - entry_pass + True + True + entry_pass False @@ -913,9 +868,9 @@ When creating a signed + symmetrically-encrypted message, anything in the passph True - True - True - Symmetric encryption/decryption key + True + True + Symmetric encryption/decryption key Max length limited only by available memory @@ -929,17 +884,13 @@ Example: You encrypt a message with your public key + symmetrically with a passp When you go to decrypt said message, you could leave the passphrase box empty (in which case gpg-agent will ask you for your private key passphrase); you could enter the symmetric passphrase you used, or you could enter your private key passphrase (both these options will bypass gpg-agent) False - - 10 - True - etched-in - True - gtk-dialog-authentication - True - False - True - True - Clear entry field + + 10 + True + etched-in + gtk-dialog-authentication + False + Clear entry field @@ -952,7 +903,7 @@ When you go to decrypt said message, you could leave the passphrase box empty (i True - False + False @@ -966,11 +917,11 @@ When you go to decrypt said message, you could leave the passphrase box empty (i True False - False + False _Recipients: - True - True - entry_recip + True + True + entry_recip False @@ -981,23 +932,19 @@ When you go to decrypt said message, you could leave the passphrase box empty (i True - True - True - Keys to use for asymmetric encryption + True + True + Keys to use for asymmetric encryption Use a semicolon to separate recipients - - 10 - True - etched-in - True - False - gtk-orientation-portrait - True - False - True - True - Clear entry field + + 10 + True + etched-in + False + gtk-orientation-portrait + False + Clear entry field @@ -1010,20 +957,20 @@ Use a semicolon to separate recipients Enc. To Se_lf - False + False True False - True - False - True - Tells gpg to encrypt the message with the public key that corresponds to the first secret key in your keyring + True + False + False + True + Tells gpg to encrypt the message with the public key that corresponds to the first secret key in your keyring This is done in addition to any other recipients, or if in Advanced mode and performing symmetric encryption with a passphrase, then in addition to that Note for power users: if "Change Default Key" in the signature options toolbar is enabled, the contents of its entry box are used as self, instead of the first secret key in your keyring - True - False - True + True + True False @@ -1035,7 +982,7 @@ Note for power users: if "Change Default Key" in the signature options toolbar i True - False + False @@ -1048,10 +995,10 @@ Note for power users: if "Change Default Key" in the signature options toolbar i True - False + False _Cipher: - True - combobox_cipher + True + combobox_cipher False @@ -1062,9 +1009,10 @@ Note for power users: if "Change Default Key" in the signature options toolbar i True - False - True - [Not used when decrypting, verifying in gpg mode] + False + False + True + [Not used when decrypting, verifying in gpg mode] Configures symmetric encryption cipher algorithm @@ -1077,7 +1025,6 @@ This is used for both encryption and decryption in openssl-mode When decrypting, openssl needs to be told what cipher the input was encrypted with (unlike gpg) liststore_ciphers 0 - False @@ -1103,21 +1050,21 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi True - True + True 522 - True + True True - False + False True - False + False True - False + False False @@ -1127,19 +1074,19 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi - False + False True - True - True - True - Open text file in Message area + True + False + True + True + Open text file in Message area none - False True - False + False gtk-open @@ -1152,19 +1099,19 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi - False + False True - True - True - True - Save Message to text file + True + False + True + True + Save Message to text file none - False True - False + False gtk-save-as @@ -1177,19 +1124,19 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi - False + False True - True - True - True - Copy Message to clipboard + True + False + True + True + Copy Message to clipboard none - False True - False + False gtk-select-all @@ -1203,7 +1150,7 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi True - False + False False @@ -1212,60 +1159,6 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi 4 - - - False - True - False - True - True - True - Undo the last action in Message area - none - False - top - - - - True - False - gtk-undo - - - - - False - False - 5 - - - - - False - True - False - True - True - True - Redo the last undone action in Message area - none - False - top - - - - True - False - gtk-redo - - - - - False - False - 6 - - False @@ -1277,33 +1170,33 @@ When decrypting, openssl needs to be told what cipher the input was encrypted wi True - False - 3 - 0 + False + 3 + 0 True - False + False True - True + True True - False + False True - False - True - Choose input file to pass directly to gpg/openssl instead of loading into Message area + False + False + True + Choose input file to pass directly to gpg/openssl instead of loading into Message area This is the way to go when dealing with binary or very large files Drag/drop of files onto this button is supported BUGALERT: The first drag/drop after opening Pyrite will not work! -- do it a 2nd time and all will be fine - False Choose gpg input file... @@ -1317,7 +1210,7 @@ BUGALERT: The first drag/drop after opening Pyrite will not work! -- do it a 2nd True - False + False @@ -1330,13 +1223,14 @@ BUGALERT: The first drag/drop after opening Pyrite will not work! -- do it a 2nd Generate _Text Output - False + False True False - True - False - True - [Not used when decrypting, verifying in gpg-mode] + True + False + False + True + [Not used when decrypting, verifying in gpg-mode] Tells gpg/openssl to output plaintext instead of binary data when encrypting and signing @@ -1347,10 +1241,9 @@ When operating on files directly, this is set based on whether the file is detec OpenSSL Note: This is used for both encryption and decryption in openssl-mode When decrypting, openssl needs to know if the input is base64 or binary (unlike gpg), so when decrypting files in openssl mode, just let Pyrite auto-detect the input file type and auto-set this toggle appropriately - True - False + True True - True + True False @@ -1364,10 +1257,10 @@ When decrypting, openssl needs to know if the input is base64 or binary (unlike True - False + False Inp_ut File For Direct Operation - True - expander_filemode + True + expander_filemode @@ -1377,14 +1270,14 @@ When decrypting, openssl needs to know if the input is base64 or binary (unlike False True - end + end 0 True - False + False @@ -1392,25 +1285,23 @@ When decrypting, openssl needs to know if the input is base64 or binary (unlike False True - end + end 1 True - True - automatic - automatic + True True - True - True - True - Type or paste input text here + True + True + True + Type or paste input text here Drag/drop of text files also supported - word + word @@ -1418,7 +1309,7 @@ Drag/drop of text files also supported True True - end + end 2 @@ -1427,11 +1318,11 @@ Drag/drop of text files also supported True - False + False <i>Message _Input/Output</i> - True - True - textview1 + True + True + textview1 @@ -1450,22 +1341,20 @@ Drag/drop of text files also supported True - False - 3 - 0 + False + 3 + 0 True - True - automatic - automatic + True True False - True - word - False + True + word + False @@ -1473,10 +1362,10 @@ Drag/drop of text files also supported True - False + False <i>Task Status</i> - True - True + True + True @@ -1495,12 +1384,12 @@ Drag/drop of text files also supported True - False + False 1 True - False + False False @@ -1512,20 +1401,20 @@ Drag/drop of text files also supported Add Si_gnature: - False + False True False - True - False - True - [Not used when decrypting, verifying] + True + False + False + True + [Not used when decrypting, verifying] Tells gpg to use your secret key to sign the input This will likely require you to interact with gpg-agent - True - False - True + True + True @@ -1537,9 +1426,10 @@ This will likely require you to interact with gpg-agent False - False - True - [Not used when decrypting, verifying] + False + False + True + [Not used when decrypting, verifying] This allows you to choose the signature type for signing in Sign/Verify mode @@ -1553,7 +1443,6 @@ Detached: Creates a separate signature that does not contain the message -- in order to verify a message/file that has a detached signature, you will need to ensure the message and signature are both in files (with the same name, except for the extra extension of the sig file) in the same directory liststore_sigmodes 0 - False @@ -1571,7 +1460,7 @@ Creates a separate signature that does not contain the message -- in order to ve True - False + False @@ -1583,10 +1472,10 @@ Creates a separate signature that does not contain the message -- in order to ve - False + False D_igest: - True - combobox_digest + True + combobox_digest False @@ -1596,16 +1485,16 @@ Creates a separate signature that does not contain the message -- in order to ve - False - True - [Not used when decrypting, verifying] + False + False + True + [Not used when decrypting, verifying] Configures message digest algorithm (used for hashing message, i.e., creating your signature) With "Default", gpg decides the algorithm based on local system settings, weighing them against the preferences of your secret key liststore_digest 0 - False @@ -1623,7 +1512,7 @@ With "Default", gpg decides the algorithm based on local system settings, weighi True - False + False @@ -1636,17 +1525,17 @@ With "Default", gpg decides the algorithm based on local system settings, weighi Change Default _Key: - False + False True - True - False - True - Tell gpg which secret key to use -- under common circumstances, this will only affect: (1) signing; (2) the calculation of "self" when using the "Enc. To Self" feature + True + False + False + True + Tell gpg which secret key to use -- under common circumstances, this will only affect: (1) signing; (2) the calculation of "self" when using the "Enc. To Self" feature This is only useful if you have multiple secret keys in your keyring - True - False - True + True + True @@ -1657,23 +1546,19 @@ This is only useful if you have multiple secret keys in your keyring - True - True - Key identifier of the non-default key to use for signing + True + True + Key identifier of the non-default key to use for signing Input is passed to gpg "--local-user" option - - 11 - True - etched-in - True - False - gtk-orientation-portrait - True - False - True - True - Clear entry field + + 11 + True + etched-in + False + gtk-orientation-portrait + False + Clear entry field @@ -1693,11 +1578,11 @@ Input is passed to gpg "--local-user" option True - False + False - 16 - False + 16 + False False @@ -1709,7 +1594,7 @@ Input is passed to gpg "--local-user" option True - False + False True diff --git a/ui/preferences.glade b/ui/preferences.glade index e85d77d..10ae929 100644 --- a/ui/preferences.glade +++ b/ui/preferences.glade @@ -1,34 +1,33 @@ - - + 2 50 - 1 - 4 + 1 + 4 2 100 - 1 - 4 + 1 + 4 1 100 100 - 1 - 4 + 1 + 4 True - False + False gtk-justify-fill True - False + False gtk-justify-fill @@ -128,13 +127,10 @@ - gpg2 + gpg - gpg - - - openssl + openssl @@ -187,48 +183,48 @@ - False - 12 + False + 12 Pyrite Preferences - center - True - dialog + center + True + dialog True - False + False 12 True - True + True True - False + False True - False - 8 - 5 - 6 + False + 8 + 5 + 6 True - False + False - 2 - 3 - - 10 + 2 + 3 + + 10 True - False + False liststore_major_opmodes @@ -238,32 +234,32 @@ - 4 - 5 - GTK_FILL - - 10 + 4 + 5 + GTK_FILL + + 10 True - False - 0 + False Operation Mode: - True + True + 0 - 3 - 4 - GTK_FILL - + 3 + 4 + GTK_FILL + True - False + False liststore_engines @@ -273,24 +269,24 @@ - 1 - 2 - GTK_FILL - + 1 + 2 + GTK_FILL + True - False - 0 + False Backend Engine Primary Choice: - True + True + 0 - GTK_FILL - - 10 + GTK_FILL + + 10 @@ -303,7 +299,7 @@ True - False + False False @@ -314,106 +310,106 @@ True - False + False True - False + False True - False - 8 - 5 - 2 - 6 - 6 + False + 8 + 5 + 2 + 6 + 6 Advanced - False + False True - True - False + True + False 0 - True + True - 2 - 2 - 3 - GTK_FILL - - 10 + 2 + 2 + 3 + GTK_FILL + + 10 True - False - 0 + False <b>Encrypt/Decrypt Mode Defaults</b> - True + True + 0 - 2 - GTK_FILL - + 2 + GTK_FILL + Encrypt To Self - False + False True - True - False + True + False 0 - True + True - 4 - 5 - GTK_FILL - - 10 + 4 + 5 + GTK_FILL + + 10 Add Signature - False + False True - True - False + True + False 0 - True + True - 1 - 2 - 4 - 5 - GTK_FILL - + 1 + 2 + 4 + 5 + GTK_FILL + True - False + False True - False + False True - False - 0 + False Symmetric Cipher Algorithm: + 0 False @@ -432,7 +428,7 @@ True - False + False liststore_ciphers @@ -449,26 +445,26 @@ - 2 - 3 - 4 - + 2 + 3 + 4 + True - False + False True - False + False True - False - 0 + False Initial Encryption Type: + 0 False @@ -487,7 +483,7 @@ True - False + False liststore_enctypes @@ -505,10 +501,10 @@ - 2 - 1 - 2 - + 2 + 1 + 2 + @@ -521,7 +517,7 @@ True - False + False False @@ -532,45 +528,45 @@ True - False - 8 - 5 - 2 - 6 - 6 + False + 8 + 5 + 2 + 6 + 6 True - False - 0 + False <b>Mode-Independent Defaults</b> - True + True + 0 - 2 - GTK_FILL - + 2 + GTK_FILL + True - False - 0 + False Digest Hash Algorithm: + 0 - 1 - 2 - GTK_FILL - - 10 + 1 + 2 + GTK_FILL + + 10 True - False + False liststore_digest @@ -580,75 +576,72 @@ - 1 - 2 - 1 - 2 - GTK_FILL - + 1 + 2 + 1 + 2 + GTK_FILL + Change Default Key: - False + False True - True - False + True + False 0 - True + True - 2 - 3 - GTK_FILL - - 10 + 2 + 3 + GTK_FILL + + 10 True - True - - 13 - True - etched-in - True - False - False - False - True - True + True + + 13 + True + etched-in + False + False + False - 1 - 2 - 2 - 3 - GTK_FILL - + 1 + 2 + 2 + 3 + GTK_FILL + True - False - 0 + False Text Output With Files: + 0 - 3 - 4 - GTK_FILL - - 10 + 3 + 4 + GTK_FILL + + 10 True - False + False liststore_txtoutput @@ -658,31 +651,31 @@ - 1 - 2 - 3 - 4 - GTK_FILL - + 1 + 2 + 3 + 4 + GTK_FILL + Expand Input File Expander - False + False True - True - False + True + False 0 - True + True - 2 - 4 - 5 - GTK_FILL - - 10 + 2 + 4 + 5 + GTK_FILL + + 10 @@ -702,7 +695,7 @@ True - False + False False @@ -713,82 +706,82 @@ True - False + False True - False - 8 - 4 - 2 - 6 + False + 8 + 4 + 2 + 6 True - False - 0 + False <b>Sign/Verify Mode Defaults</b> - True + True + 0 - 2 - GTK_FILL - + 2 + GTK_FILL + Choose Output Filenames - False + False True - True - False + True + False 0 - True + True - 2 - 1 - 2 - GTK_FILL - - 10 + 2 + 1 + 2 + GTK_FILL + + 10 True - False - 0 + False Initial Sign Type For Text: + 0 - 2 - 3 - GTK_FILL - - 10 + 2 + 3 + GTK_FILL + + 10 True - False - 0 + False Initial Sign Type For Files: + 0 - 3 - 4 - GTK_FILL - - 10 + 3 + 4 + GTK_FILL + + 10 True - False + False liststore_sigmodes @@ -798,18 +791,18 @@ - 1 - 2 - 2 - 3 - GTK_FILL - + 1 + 2 + 2 + 3 + GTK_FILL + True - False + False liststore_sigmodes @@ -819,12 +812,12 @@ - 1 - 2 - 3 - 4 - GTK_FILL - + 1 + 2 + 3 + 4 + GTK_FILL + @@ -837,7 +830,7 @@ True - False + False False @@ -848,62 +841,62 @@ True - False - 8 - 7 - 2 - 6 - 6 + False + 8 + 7 + 2 + 6 + 6 True - False - 0 + False <b>Display Options</b> - True + True + 0 - 2 - GTK_FILL - + 2 + GTK_FILL + Text Wrapping - False + False True - True - False + True + False 0 - True + True - 2 - 2 - 3 - GTK_FILL - - 10 + 2 + 2 + 3 + GTK_FILL + + 10 True - False + False True - False + False Task Status - False + False True - True - False + True + False 0 - True + True False @@ -922,12 +915,12 @@ Verbose Task Status - False + False True - True - False + True + False 0 - True + True False @@ -938,27 +931,27 @@ - 2 - 1 - 2 - + 2 + 1 + 2 + True - False + False True - False + False 6 True - False - 0 + False Message: + 0 False @@ -969,17 +962,14 @@ True - True - - etched-in - True - False - False - False - True - True + True + + etched-in + False + False + False adj_msgfntsz - True + True True True @@ -1000,14 +990,14 @@ True - False + False 6 True - False - 0 + False Status: + 0 False @@ -1018,17 +1008,14 @@ True - True - - etched-in - True - False - False - False - True - True + True + + etched-in + False + False + False adj_errfntsz - True + True True True @@ -1047,103 +1034,38 @@ - 2 - 5 - 6 - + 2 + 5 + 6 + True - False - 0 + False Font Sizes: - - - 2 - 4 - 5 - GTK_FILL - - 10 - - - - - Show Opacity Slider - False - True - True - False 0 - True - - - 3 - 4 - GTK_FILL - - 10 - - - - - True - False - - - True - False - 0 - Opacity: - - - False - True - 0 - - - - - True - True - - etched-in - True - False - False - False - True - True - adj_opacity - True - True - - - False - True - 1 - - - 1 - 2 - 3 - 4 + 2 + 4 + 5 + GTK_FILL + + 10 True - False + False True - False - 0 + False Message Area Colors: + 0 False @@ -1155,16 +1077,16 @@ True - False + False 4 - False + False True - True - True - True - Foreground (Text) + True + True + True + Foreground (Text) Pick a Foreground (Text) Color #000000000000 @@ -1176,12 +1098,12 @@ - False + False True - True - True - True - Background + True + True + True + Background Pick a Background Color #ffffffffffff @@ -1200,11 +1122,11 @@ - 2 - 6 - 7 - GTK_FILL - GTK_FILL + 2 + 6 + 7 + GTK_FILL + GTK_FILL @@ -1233,279 +1155,261 @@ True - False + False Application Startup Defaults - False + False True False - False - 8 - 8 - 2 - 4 - 6 + False + 8 + 8 + 2 + 4 + 6 True - False - 0 + False <b>Custom GnuPG Arguments</b> - True + True + 0 - 2 - GTK_FILL - + 2 + GTK_FILL + When Encrypting: - False + False True - True - False + True + False 0 - True + True - 1 - 2 - GTK_FILL - - 12 + 1 + 2 + GTK_FILL + + 12 True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 1 - 2 - GTK_FILL - + 1 + 2 + 1 + 2 + GTK_FILL + When Decrypting: - False + False True - True - False + True + False 0 - True + True - 2 - 3 - GTK_FILL - - 12 + 2 + 3 + GTK_FILL + + 12 True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 2 - 3 - GTK_FILL - + 1 + 2 + 2 + 3 + GTK_FILL + When Sign-Only: - False + False True - True - False + True + False 0 - True + True - 3 - 4 - GTK_FILL - - 12 + 3 + 4 + GTK_FILL + + 12 True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 3 - 4 - GTK_FILL - + 1 + 2 + 3 + 4 + GTK_FILL + When Verifying: - False + False True - True - False + True + False 0 - True + True - 4 - 5 - GTK_FILL - - 12 + 4 + 5 + GTK_FILL + + 12 True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 4 - 5 - GTK_FILL - + 1 + 2 + 4 + 5 + GTK_FILL + True - False - 0 + False <b>Custom OpenSSL Arguments</b> - True + True + 0 - 2 - 5 - 6 - GTK_FILL - + 2 + 5 + 6 + GTK_FILL + When Encrypting: - False + False True - True - False + True + False 0 - True + True - 6 - 7 - GTK_FILL - - 12 + 6 + 7 + GTK_FILL + + 12 True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 6 - 7 - GTK_FILL - + 1 + 2 + 6 + 7 + GTK_FILL + True - True - - True - False - False - True - True + True + + False + False - 1 - 2 - 7 - 8 - GTK_FILL - + 1 + 2 + 7 + 8 + GTK_FILL + When Decrypting: - False + False True - True - False + True + False 0 - True + True - 7 - 8 - GTK_FILL - - 12 + 7 + 8 + GTK_FILL + + 12 @@ -1516,12 +1420,12 @@ True - False + False Advanced Options 1 - False + False @@ -1534,21 +1438,21 @@ True - False + False True - False - start + False + start Defaults - False + False True - True - True - True - Reset all preferences to built-in defaults + True + True + True + Reset all preferences to built-in defaults image2 @@ -1561,14 +1465,14 @@ gtk-revert-to-saved - False + False True False - True - True - True - Revert all preferences to values set in user preferences file - True + True + True + True + Revert all preferences to values set in user preferences file + True @@ -1590,18 +1494,18 @@ True - False - end + False + end gtk-cancel - False + False True - True - True - True - Cancel without making any changes - True + True + True + True + Cancel without making any changes + True @@ -1613,13 +1517,13 @@ gtk-save - False + False True - True - True - True - Save all settings out to a pref file in your home, but don't change anything in the current session - True + True + True + True + Save all settings out to a pref file in your home, but don't change anything in the current session + True False @@ -1630,13 +1534,13 @@ gtk-apply - False + False True - True - True - True - Save settings to a user pref file and apply them to current session - True + True + True + True + Save settings to a user pref file and apply them to current session + True False @@ -1648,7 +1552,7 @@ False True - end + end 2 @@ -1662,8 +1566,8 @@ True - False - immediate + False + immediate