diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..19e7218 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Tristan Heaven diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d511905 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..eaa9651 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,4 @@ +Most noticable changes are mentioned in the NEWS file. + +If you're looking for a more complete list, start here: +http://gtkhash.sourceforge.net/ diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..0222f10 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,9 @@ +if ENABLE_NLS +SUBDIRS = data src po +else +SUBDIRS = data src +endif + +ACLOCAL_AMFLAGS = -I m4 --install + +EXTRA_DIST = autogen.sh diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..c8e0efa --- /dev/null +++ b/NEWS @@ -0,0 +1,21 @@ +Summary of changes for each release: + +0.4.0 - + * Added support for hashing remote files using GIO + * General usability improvements + +0.3.0 - 2009-11-22 + * Added optional Nautilus (GNOME file manager) extension + +0.2.1 - 2008-12-31 + * Fixed progress bar display for large files + * Removed dependency on libglade + +0.2.0 - 2007-08-14 + * Added file list mode for hashing multiple files + +0.1.1 - 2007-07-21 + * Added gettext support + +0.1.0 - 2007-06-29 + * Initial release diff --git a/README b/README new file mode 100644 index 0000000..d15c6a9 --- /dev/null +++ b/README @@ -0,0 +1,12 @@ +GtkHash is a GTK+ utility for computing message digests or checksums using +the mhash library. + +http://gtkhash.sourceforge.net/ + +Dependencies: + Required: mhash, GTK+ 2 + Optional (Nautilus extension): Nautilus, GConf + +Translations: + Please submit any new or updated translations here: + https://translations.launchpad.net/gtkhash diff --git a/TODO b/TODO new file mode 100644 index 0000000..bfc3466 --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ +* Uppercase/Lowercase output option +* Digest compare/check/verify (Need UI ideas) +* Drag and drop integration +* Multithreaded hashing diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..d701ec8 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +set -e +set -x + +[ -f autogen.sh ] + +[ ! -d m4 ] && mkdir m4 + +glib-gettextize --copy --force +intltoolize --automake --copy --force +autoreconf --force --install --warnings=all diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..24c21c9 --- /dev/null +++ b/configure.ac @@ -0,0 +1,91 @@ +AC_PREREQ(2.61) +AC_INIT(GtkHash, 0.4.0) +AC_CONFIG_HEADERS(config.h) +AC_CONFIG_SRCDIR(src/main.c) +AC_CONFIG_MACRO_DIR(m4) +AM_INIT_AUTOMAKE + +AC_PROG_CC_C99 +AM_PROG_CC_C_O +LT_INIT + +AX_CFLAGS_GCC_OPTION(-pedantic) +AX_CFLAGS_GCC_OPTION(-Wall) +AX_CFLAGS_GCC_OPTION(-Wextra) + +AX_CFLAGS_GCC_OPTION(-Waggregate-return) +AX_CFLAGS_GCC_OPTION(-Wbad-function-cast) +AX_CFLAGS_GCC_OPTION(-Wcast-align) +AX_CFLAGS_GCC_OPTION(-Wfloat-equal) +AX_CFLAGS_GCC_OPTION(-Wlogical-op) +AX_CFLAGS_GCC_OPTION(-Wmissing-declarations) +AX_CFLAGS_GCC_OPTION(-Wmissing-noreturn) +AX_CFLAGS_GCC_OPTION(-Wredundant-decls) +AX_CFLAGS_GCC_OPTION(-Wshadow) +AX_CFLAGS_GCC_OPTION(-Wswitch-default) +AX_CFLAGS_GCC_OPTION(-Wwrite-strings) + +PKG_PROG_PKG_CONFIG + +AC_CHECK_LIB(mhash, mhash, :, AC_MSG_ERROR(mhash library not found)) +MHASH_LIBS="-lmhash" +AC_SUBST(MHASH_LIBS) + +PKG_CHECK_MODULES(GTHREAD, gthread-2.0) +AC_SUBST(GTHREAD_CFLAGS) +AC_SUBST(GTHREAD_LIBS) + +PKG_CHECK_MODULES(GDK, gdk-2.0) +AC_SUBST(GDK_CFLAGS) +AC_SUBST(GDK_LIBS) + +PKG_CHECK_MODULES(GTK, gtk+-2.0) +AC_SUBST(GTK_CFLAGS) +AC_SUBST(GTK_LIBS) + +AC_ARG_ENABLE(nautilus, AS_HELP_STRING(--disable-nautilus, disable building the nautilus extension)) +AM_CONDITIONAL(ENABLE_NAUTILUS, test "${enable_nautilus}" != "no") +AM_GCONF_SOURCE_2 + +if test "${enable_nautilus}" != "no" ; then + # Check for nautilus + PKG_CHECK_MODULES(NAUTILUS, libnautilus-extension) + AC_SUBST(NAUTILUS_CFLAGS) + AC_SUBST(NAUTILUS_LIBS) + NAUTILUS_EXTENSION_DIR=`${PKG_CONFIG} --variable=extensiondir libnautilus-extension` + AC_SUBST(NAUTILUS_EXTENSION_DIR) + + # Check for gconf + PKG_CHECK_MODULES(GCONF, gconf-2.0) + AC_SUBST(GCONF_CFLAGS) + AC_SUBST(GCONF_LIBS) + AC_PATH_PROG(GCONFTOOL, gconftool-2, no) + if test "${GCONFTOOL}" = "no" ; then + AC_MSG_ERROR(gconftool-2 not found) + fi +fi + +AM_CONDITIONAL(ENABLE_NLS, test "${enable_nls}" != "no") + +if test "${enable_nls}" = "no" ; then + AC_DEFINE_UNQUOTED(ENABLE_NLS, 0) +else + GETTEXT_PACKAGE="${PACKAGE}" + AC_SUBST(GETTEXT_PACKAGE) + AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "${GETTEXT_PACKAGE}", Define the gettext package) + IT_PROG_INTLTOOL(0.40.6) + AM_GLIB_GNU_GETTEXT +fi + +AC_DEFINE_UNQUOTED(FILE_BUFFER_SIZE, 131072, Define file buffer size) +AC_DEFINE_UNQUOTED(G_LOG_DOMAIN, "${PACKAGE_NAME}", Define the Glib log domain) + +AC_CONFIG_FILES(Makefile) +AC_CONFIG_FILES(data/Makefile) +AC_CONFIG_FILES(data/nautilus/Makefile) +AC_CONFIG_FILES(po/Makefile.in) +AC_CONFIG_FILES(src/Makefile) +AC_CONFIG_FILES(src/hash/Makefile) +AC_CONFIG_FILES(src/hash/mutils/Makefile) +AC_CONFIG_FILES(src/nautilus/Makefile) +AC_OUTPUT diff --git a/data/Makefile.am b/data/Makefile.am new file mode 100644 index 0000000..f197670 --- /dev/null +++ b/data/Makefile.am @@ -0,0 +1,6 @@ +if ENABLE_NAUTILUS +SUBDIRS = nautilus +endif + +pkgdata_DATA = gtkhash.xml +EXTRA_DIST = gtkhash.xml diff --git a/data/gtkhash.xml b/data/gtkhash.xml new file mode 100644 index 0000000..9f77957 --- /dev/null +++ b/data/gtkhash.xml @@ -0,0 +1,620 @@ + + + + + + GtkHash + gtkhash + + + True + vertical + + + True + + + True + _File + True + + + True + + + gtk-save-as + True + False + True + True + + + + + True + + + + + gtk-quit + True + True + True + + + + + + + + + True + _Edit + True + + + True + + + gtk-cut + True + True + True + + + + + gtk-copy + True + True + True + + + + + gtk-paste + True + True + True + + + + + gtk-delete + True + True + True + + + + + True + + + + + gtk-select-all + True + True + True + + + + + True + + + + + gtk-preferences + True + True + True + + + + + + + + + True + _View + True + + + True + + + True + _File + True + True + True + + + + + True + _Text + True + True + radiomenuitem_file + + + + + True + File _List + True + True + radiomenuitem_file + + + + + + + + + True + _Help + True + + + True + + + gtk-about + True + True + True + + + + + + + + + False + 0 + + + + + True + both-horiz + + + True + True + gtk-add + + + False + True + + + + + True + True + gtk-remove + + + False + True + + + + + True + True + gtk-clear + + + False + True + + + + + False + 1 + + + + + True + 6 + vertical + + + True + vertical + + + True + 6 + + + True + vertical + 3 + True + + + True + File: + + + 0 + + + + + True + Text: + + + 1 + + + + + False + 0 + + + + + True + vertical + 3 + True + + + True + False + + + False + 0 + + + + + True + True + True + + + 1 + + + + + 1 + + + + + False + 0 + + + + + True + + + False + 6 + 1 + + + + + True + 6 + + + True + vertical + 3 + True + + + + + + False + 0 + + + + + True + vertical + 3 + True + + + + + + 1 + + + + + True + vertical + 3 + True + + + + + + 2 + + + + + False + 2 + + + + + 0 + + + + + True + vertical + + + True + 6 + + + True + True + automatic + automatic + in + + + 450 + 150 + True + True + False + True + False + False + True + + + True + autosize + File + + + + 0 + + + + + + + + + + + 0 + + + + + 1 + + + + + + + + True + vertical + + + True + + + False + 6 + 0 + + + + + True + + + True + 0.5 + 12 + + + + + + 0 + + + + + True + 6 + end + + + True + False + True + True + True + True + + + True + 3 + + + True + 1 + gtk-execute + + + 0 + + + + + True + 0 + Hash + button_hash + + + 1 + + + + + + + False + False + 0 + + + + + gtk-stop + True + True + True + True + + + False + False + 1 + + + + + False + 1 + + + + + False + 1 + + + + + False + end + 2 + + + + + 2 + + + + + + + 6 + Preferences + False + center-on-parent + dialog + True + window + + + True + vertical + 3 + + + True + 0 + Hash functions: + + + False + False + 1 + + + + + True + 6 + + + + + + end + 2 + + + + + True + end + + + gtk-close + True + True + True + True + True + True + + + False + False + 0 + + + + + False + end + 1 + + + + + + dialog_button_close + + + diff --git a/data/nautilus/Makefile.am b/data/nautilus/Makefile.am new file mode 100644 index 0000000..7dd027f --- /dev/null +++ b/data/nautilus/Makefile.am @@ -0,0 +1,15 @@ +nautilusdir = $(pkgdatadir)/nautilus +nautilus_DATA = gtkhash-properties.xml + +schemadir = $(GCONF_SCHEMA_FILE_DIR) +schema_DATA = gtkhash.schemas + +EXTRA_DIST = gtkhash-properties.xml gtkhash.schemas + +if GCONF_SCHEMAS_INSTALL +install-data-local: + GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) \ + --makefile-install-rule $(schema_DATA) +else +install-data-local: +endif diff --git a/data/nautilus/gtkhash-properties.xml b/data/nautilus/gtkhash-properties.xml new file mode 100644 index 0000000..def1f27 --- /dev/null +++ b/data/nautilus/gtkhash-properties.xml @@ -0,0 +1,165 @@ + + + + + + + + + + + + + + + + + + liststore + + + True + vertical + + + True + True + automatic + automatic + in + + + True + True + treemodelfilter + False + False + 0 + False + + + + + + 1 + + + + + + + Hash Function + + + + 2 + + + + + + + Digest + + + + 3 + + + + + + + + + 0 + + + + + True + False + + + False + 1 + + + + + True + 15 + 8 + end + + + gtk-stop + True + False + True + True + True + + + False + False + 0 + + + + + H_ash + True + True + True + image_execute + True + + + False + False + 1 + + + + + False + 2 + + + + + True + gtk-execute + + + True + + + _Copy Digest + True + image_copy + True + False + + + + + True + + + + + True + Show _Disabled Hash Functions + True + True + + + + + True + gtk-copy + 1 + + diff --git a/data/nautilus/gtkhash.schemas b/data/nautilus/gtkhash.schemas new file mode 100644 index 0000000..0127528 --- /dev/null +++ b/data/nautilus/gtkhash.schemas @@ -0,0 +1,26 @@ + + + + + /schemas/apps/gtkhash/hash_functions + /apps/gtkhash/hash_functions + gtkhash + list + string + [MD5,SHA1,SHA256] + + List of enabled hash functions + + + + /schemas/apps/gtkhash/show_disabled_hash_functions + /apps/gtkhash/show_disabled_hash_functions + gtkhash + bool + 1 + + Show disabled hash functions + + + + diff --git a/po/ChangeLog b/po/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..1ba2bd0 --- /dev/null +++ b/po/LINGUAS @@ -0,0 +1,7 @@ +cs +de +eo +es +fr +sv +tr diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..3bcd858 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,14 @@ +[encoding: UTF-8] + +[type: gettext/glade]data/gtkhash.xml +[type: gettext/glade]data/nautilus/gtkhash-properties.xml +src/callbacks.c +src/gui.c +src/hash.c +src/list.c +src/main.c +src/prefs.c +src/nautilus/properties.c +src/nautilus/properties-hash.c +src/nautilus/properties-list.c +src/nautilus/properties-prefs.c diff --git a/po/cs.po b/po/cs.po new file mode 100644 index 0000000..579d05a --- /dev/null +++ b/po/cs.po @@ -0,0 +1,135 @@ +# Czech translation for gtkhash +# Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 +# This file is distributed under the same license as the gtkhash package. +# FIRST AUTHOR , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: gtkhash\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-11-15 23:59+0000\n" +"PO-Revision-Date: 2009-01-18 08:39+0000\n" +"Last-Translator: Jakub Žáček \n" +"Language-Team: Czech \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2009-11-15 22:44+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +#: ../data/gtkhash.xml.h:1 +msgid "File _List" +msgstr "Sezna_m souborů" + +#: ../data/gtkhash.xml.h:2 +msgid "File:" +msgstr "Soubor:" + +#: ../data/gtkhash.xml.h:3 +msgid "Hash" +msgstr "Kontrolní součet" + +#: ../data/gtkhash.xml.h:4 +msgid "Hash functions:" +msgstr "Funkce kontr. součtu:" + +#: ../data/gtkhash.xml.h:5 +msgid "Preferences" +msgstr "Nastavení" + +#: ../data/gtkhash.xml.h:6 +msgid "Text:" +msgstr "Text:" + +#: ../data/gtkhash.xml.h:7 +msgid "_Edit" +msgstr "Ú_pravy" + +#: ../data/gtkhash.xml.h:8 +msgid "_File" +msgstr "_Soubor" + +#: ../data/gtkhash.xml.h:9 +msgid "_Help" +msgstr "_Nápověda" + +#: ../data/gtkhash.xml.h:10 +msgid "_Text" +msgstr "_Text" + +#: ../data/gtkhash.xml.h:11 +msgid "_View" +msgstr "_Zobrazit" + +#: ../data/nautilus/gtkhash-properties.xml.h:1 +#, fuzzy +msgid "H_ash" +msgstr "Kontrolní součet" + +#: ../src/callbacks.c:99 +msgid "Save Digests To File" +msgstr "Uložit součty do souboru" + +#: ../src/callbacks.c:310 +msgid "A GTK+ utility for computing digests using the mhash library." +msgstr "Utilita GTK+ pro počítání součtů pomocí knihovny mhash." + +#: ../src/callbacks.c:314 +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" Jakub Žáček https://launchpad.net/~dawon" + +#: ../src/callbacks.c:339 +msgid "Select Files" +msgstr "Vyberte soubory" + +#: ../src/gui.c:75 +#, c-format +msgid "" +"Failed to read %s:\n" +"%s" +msgstr "" +"Selhalo čtení %s:\n" +"%s" + +#: ../src/list.c:56 +msgid "Path" +msgstr "Umístění" + +#: ../src/list.c:62 +msgid "Filename" +msgstr "Název souboru" + +#: ../src/main.c:56 +msgid "[FILE...]" +msgstr "[SOUBOR...]" + +#: ../src/main.c:67 +#, c-format +msgid "Unknown option, try %s --help\n" +msgstr "Neplatná možnost, zkuste %s --help\n" + +#: ../src/nautilus/properties.c:178 +msgid "Digests" +msgstr "" + +#: ../src/nautilus/properties-hash.c:357 +#, c-format +msgid "Estimated time remaining: %d minute" +msgstr "" + +#: ../src/nautilus/properties-hash.c:360 +#, c-format +msgid "Estimated time remaining: %d minutes" +msgstr "" + +#: ../src/nautilus/properties-hash.c:364 +#, c-format +msgid "Estimated time remaining: %d second" +msgstr "" + +#: ../src/nautilus/properties-hash.c:367 +#, c-format +msgid "Estimated time remaining: %d seconds" +msgstr "" diff --git a/po/de.po b/po/de.po new file mode 100644 index 0000000..175a4ee --- /dev/null +++ b/po/de.po @@ -0,0 +1,137 @@ +# German translation for gtkhash +# Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 +# This file is distributed under the same license as the gtkhash package. +# FIRST AUTHOR , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: gtkhash\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-11-15 23:59+0000\n" +"PO-Revision-Date: 2009-10-04 09:27+0000\n" +"Last-Translator: Trip McKay \n" +"Language-Team: German \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2009-11-15 22:44+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +#: ../data/gtkhash.xml.h:1 +msgid "File _List" +msgstr "Dateiliste" + +#: ../data/gtkhash.xml.h:2 +msgid "File:" +msgstr "Datei:" + +#: ../data/gtkhash.xml.h:3 +msgid "Hash" +msgstr "Hash" + +#: ../data/gtkhash.xml.h:4 +msgid "Hash functions:" +msgstr "Hashfunktionen:" + +#: ../data/gtkhash.xml.h:5 +msgid "Preferences" +msgstr "Einstellungen" + +#: ../data/gtkhash.xml.h:6 +msgid "Text:" +msgstr "Text:" + +#: ../data/gtkhash.xml.h:7 +msgid "_Edit" +msgstr "_Bearbeiten" + +#: ../data/gtkhash.xml.h:8 +msgid "_File" +msgstr "_Datei" + +#: ../data/gtkhash.xml.h:9 +msgid "_Help" +msgstr "_Hilfe" + +#: ../data/gtkhash.xml.h:10 +msgid "_Text" +msgstr "_Text" + +#: ../data/gtkhash.xml.h:11 +msgid "_View" +msgstr "_Ansicht" + +#: ../data/nautilus/gtkhash-properties.xml.h:1 +#, fuzzy +msgid "H_ash" +msgstr "Hash" + +#: ../src/callbacks.c:99 +msgid "Save Digests To File" +msgstr "Hashwerte in Datei speichern" + +#: ../src/callbacks.c:310 +msgid "A GTK+ utility for computing digests using the mhash library." +msgstr "" +"Ein GTK+ Werkzeug, um Hashwerte mithilfe der mhash-Bibliothek zu berechnen." + +#: ../src/callbacks.c:314 +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" Patrick Kolesa https://launchpad.net/~pkol.\n" +" Trip McKay https://launchpad.net/~trip-mckay" + +#: ../src/callbacks.c:339 +msgid "Select Files" +msgstr "Dateien auswählen" + +#: ../src/gui.c:75 +#, c-format +msgid "" +"Failed to read %s:\n" +"%s" +msgstr "" +"Lesen von %s fehlgeschlagen:\n" +"%s" + +#: ../src/list.c:56 +msgid "Path" +msgstr "Pfad" + +#: ../src/list.c:62 +msgid "Filename" +msgstr "Dateiname" + +#: ../src/main.c:56 +msgid "[FILE...]" +msgstr "[DATEI …]" + +#: ../src/main.c:67 +#, c-format +msgid "Unknown option, try %s --help\n" +msgstr "Unbekannte Einstellung, versuche %s --help\n" + +#: ../src/nautilus/properties.c:178 +msgid "Digests" +msgstr "" + +#: ../src/nautilus/properties-hash.c:357 +#, c-format +msgid "Estimated time remaining: %d minute" +msgstr "" + +#: ../src/nautilus/properties-hash.c:360 +#, c-format +msgid "Estimated time remaining: %d minutes" +msgstr "" + +#: ../src/nautilus/properties-hash.c:364 +#, c-format +msgid "Estimated time remaining: %d second" +msgstr "" + +#: ../src/nautilus/properties-hash.c:367 +#, c-format +msgid "Estimated time remaining: %d seconds" +msgstr "" diff --git a/po/eo.po b/po/eo.po new file mode 100644 index 0000000..638e82f --- /dev/null +++ b/po/eo.po @@ -0,0 +1,133 @@ +# Esperanto translation for gtkhash +# Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 +# This file is distributed under the same license as the gtkhash package. +# FIRST AUTHOR , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: gtkhash\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-11-15 23:59+0000\n" +"PO-Revision-Date: 2009-11-06 05:59+0000\n" +"Last-Translator: Lucas \n" +"Language-Team: Esperanto \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2009-11-15 22:44+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +#: ../data/gtkhash.xml.h:1 +msgid "File _List" +msgstr "_Listo de dosieroj" + +#: ../data/gtkhash.xml.h:2 +msgid "File:" +msgstr "Dosiero:" + +#: ../data/gtkhash.xml.h:3 +msgid "Hash" +msgstr "Haketaĵo" + +#: ../data/gtkhash.xml.h:4 +msgid "Hash functions:" +msgstr "Haketfunkcioj:" + +#: ../data/gtkhash.xml.h:5 +msgid "Preferences" +msgstr "Agordoj" + +#: ../data/gtkhash.xml.h:6 +msgid "Text:" +msgstr "Teksto:" + +#: ../data/gtkhash.xml.h:7 +msgid "_Edit" +msgstr "" + +#: ../data/gtkhash.xml.h:8 +msgid "_File" +msgstr "" + +#: ../data/gtkhash.xml.h:9 +msgid "_Help" +msgstr "_Helpo" + +#: ../data/gtkhash.xml.h:10 +msgid "_Text" +msgstr "_Teksto" + +#: ../data/gtkhash.xml.h:11 +msgid "_View" +msgstr "" + +#: ../data/nautilus/gtkhash-properties.xml.h:1 +#, fuzzy +msgid "H_ash" +msgstr "Haketaĵo" + +#: ../src/callbacks.c:99 +msgid "Save Digests To File" +msgstr "" + +#: ../src/callbacks.c:310 +msgid "A GTK+ utility for computing digests using the mhash library." +msgstr "" + +#: ../src/callbacks.c:314 +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" Lucas https://launchpad.net/~lucaslarson" + +#: ../src/callbacks.c:339 +msgid "Select Files" +msgstr "Elektu dosierojn" + +#: ../src/gui.c:75 +#, c-format +msgid "" +"Failed to read %s:\n" +"%s" +msgstr "" + +#: ../src/list.c:56 +msgid "Path" +msgstr "" + +#: ../src/list.c:62 +msgid "Filename" +msgstr "Dosiernomo" + +#: ../src/main.c:56 +msgid "[FILE...]" +msgstr "[DOSIERO...]" + +#: ../src/main.c:67 +#, c-format +msgid "Unknown option, try %s --help\n" +msgstr "" + +#: ../src/nautilus/properties.c:178 +msgid "Digests" +msgstr "" + +#: ../src/nautilus/properties-hash.c:357 +#, c-format +msgid "Estimated time remaining: %d minute" +msgstr "" + +#: ../src/nautilus/properties-hash.c:360 +#, c-format +msgid "Estimated time remaining: %d minutes" +msgstr "" + +#: ../src/nautilus/properties-hash.c:364 +#, c-format +msgid "Estimated time remaining: %d second" +msgstr "" + +#: ../src/nautilus/properties-hash.c:367 +#, c-format +msgid "Estimated time remaining: %d seconds" +msgstr "" diff --git a/po/es.po b/po/es.po new file mode 100644 index 0000000..fb0c3c7 --- /dev/null +++ b/po/es.po @@ -0,0 +1,136 @@ +# Spanish translation for gtkhash +# Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 +# This file is distributed under the same license as the gtkhash package. +# FIRST AUTHOR , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: gtkhash\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-11-15 23:59+0000\n" +"PO-Revision-Date: 2009-03-15 13:22+0000\n" +"Last-Translator: DiegoJ \n" +"Language-Team: Spanish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2009-11-15 22:44+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +#: ../data/gtkhash.xml.h:1 +msgid "File _List" +msgstr "_Lista de archivos" + +#: ../data/gtkhash.xml.h:2 +msgid "File:" +msgstr "Archivo:" + +#: ../data/gtkhash.xml.h:3 +msgid "Hash" +msgstr "Hash" + +#: ../data/gtkhash.xml.h:4 +msgid "Hash functions:" +msgstr "Funciones de hash:" + +#: ../data/gtkhash.xml.h:5 +msgid "Preferences" +msgstr "Preferencias" + +#: ../data/gtkhash.xml.h:6 +msgid "Text:" +msgstr "Texto:" + +#: ../data/gtkhash.xml.h:7 +msgid "_Edit" +msgstr "_Editar" + +#: ../data/gtkhash.xml.h:8 +msgid "_File" +msgstr "_Archivo" + +#: ../data/gtkhash.xml.h:9 +msgid "_Help" +msgstr "_Ayuda" + +#: ../data/gtkhash.xml.h:10 +msgid "_Text" +msgstr "_Texto" + +#: ../data/gtkhash.xml.h:11 +msgid "_View" +msgstr "_Ver" + +#: ../data/nautilus/gtkhash-properties.xml.h:1 +#, fuzzy +msgid "H_ash" +msgstr "Hash" + +#: ../src/callbacks.c:99 +msgid "Save Digests To File" +msgstr "Guardar resúmenes a un archivo" + +#: ../src/callbacks.c:310 +msgid "A GTK+ utility for computing digests using the mhash library." +msgstr "Una utilidad GTK+ para generar resúmenes usando la librería mhash." + +#: ../src/callbacks.c:314 +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" DiegoJ https://launchpad.net/~diegojromerolopez\n" +" juancarlospaco https://launchpad.net/~juancarlospaco" + +#: ../src/callbacks.c:339 +msgid "Select Files" +msgstr "Seleccionar archivos" + +#: ../src/gui.c:75 +#, c-format +msgid "" +"Failed to read %s:\n" +"%s" +msgstr "" +"Falló al leer %s:\n" +"%s" + +#: ../src/list.c:56 +msgid "Path" +msgstr "Ruta" + +#: ../src/list.c:62 +msgid "Filename" +msgstr "Nombre de archivo" + +#: ../src/main.c:56 +msgid "[FILE...]" +msgstr "[ARCHIVO...]" + +#: ../src/main.c:67 +#, c-format +msgid "Unknown option, try %s --help\n" +msgstr "Opcion desconocida, pruebe %s --help\n" + +#: ../src/nautilus/properties.c:178 +msgid "Digests" +msgstr "" + +#: ../src/nautilus/properties-hash.c:357 +#, c-format +msgid "Estimated time remaining: %d minute" +msgstr "" + +#: ../src/nautilus/properties-hash.c:360 +#, c-format +msgid "Estimated time remaining: %d minutes" +msgstr "" + +#: ../src/nautilus/properties-hash.c:364 +#, c-format +msgid "Estimated time remaining: %d second" +msgstr "" + +#: ../src/nautilus/properties-hash.c:367 +#, c-format +msgid "Estimated time remaining: %d seconds" +msgstr "" diff --git a/po/fr.po b/po/fr.po new file mode 100644 index 0000000..b040485 --- /dev/null +++ b/po/fr.po @@ -0,0 +1,136 @@ +# French translation for gtkhash +# Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 +# This file is distributed under the same license as the gtkhash package. +# FIRST AUTHOR , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: gtkhash\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-11-15 23:59+0000\n" +"PO-Revision-Date: 2009-10-12 23:58+0000\n" +"Last-Translator: ERE \n" +"Language-Team: French \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2009-11-15 22:44+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +#: ../data/gtkhash.xml.h:1 +msgid "File _List" +msgstr "_Liste de Fichiers" + +#: ../data/gtkhash.xml.h:2 +msgid "File:" +msgstr "Fichier :" + +#: ../data/gtkhash.xml.h:3 +msgid "Hash" +msgstr "Hashé" + +#: ../data/gtkhash.xml.h:4 +msgid "Hash functions:" +msgstr "Fonctions de Hachage" + +#: ../data/gtkhash.xml.h:5 +msgid "Preferences" +msgstr "Préférences" + +#: ../data/gtkhash.xml.h:6 +msgid "Text:" +msgstr "Texte :" + +#: ../data/gtkhash.xml.h:7 +msgid "_Edit" +msgstr "_Édition" + +#: ../data/gtkhash.xml.h:8 +msgid "_File" +msgstr "_Fichier" + +#: ../data/gtkhash.xml.h:9 +msgid "_Help" +msgstr "_Aide" + +#: ../data/gtkhash.xml.h:10 +msgid "_Text" +msgstr "_Texte" + +#: ../data/gtkhash.xml.h:11 +msgid "_View" +msgstr "_Vue" + +#: ../data/nautilus/gtkhash-properties.xml.h:1 +#, fuzzy +msgid "H_ash" +msgstr "Hashé" + +#: ../src/callbacks.c:99 +msgid "Save Digests To File" +msgstr "Sauvegarder les Condensés dans un Fichier" + +#: ../src/callbacks.c:310 +msgid "A GTK+ utility for computing digests using the mhash library." +msgstr "" +"L'utilitaire GTK+ pour le calcul des condensés utilise la librairie mhash." + +#: ../src/callbacks.c:314 +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" ERE https://launchpad.net/~karfter" + +#: ../src/callbacks.c:339 +msgid "Select Files" +msgstr "Sélectionnez les Fichiers" + +#: ../src/gui.c:75 +#, c-format +msgid "" +"Failed to read %s:\n" +"%s" +msgstr "" +"Impossible de Lire %s:\n" +"%s" + +#: ../src/list.c:56 +msgid "Path" +msgstr "Chemin" + +#: ../src/list.c:62 +msgid "Filename" +msgstr "Nom du fichier" + +#: ../src/main.c:56 +msgid "[FILE...]" +msgstr "[FICHIER...]" + +#: ../src/main.c:67 +#, c-format +msgid "Unknown option, try %s --help\n" +msgstr "Option Inconnu, essayez %s --help\n" + +#: ../src/nautilus/properties.c:178 +msgid "Digests" +msgstr "" + +#: ../src/nautilus/properties-hash.c:357 +#, c-format +msgid "Estimated time remaining: %d minute" +msgstr "" + +#: ../src/nautilus/properties-hash.c:360 +#, c-format +msgid "Estimated time remaining: %d minutes" +msgstr "" + +#: ../src/nautilus/properties-hash.c:364 +#, c-format +msgid "Estimated time remaining: %d second" +msgstr "" + +#: ../src/nautilus/properties-hash.c:367 +#, c-format +msgid "Estimated time remaining: %d seconds" +msgstr "" diff --git a/po/gtkhash.pot b/po/gtkhash.pot new file mode 100644 index 0000000..6d64de8 --- /dev/null +++ b/po/gtkhash.pot @@ -0,0 +1,145 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-11-23 17:17+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../data/gtkhash.xml.h:1 +msgid "File _List" +msgstr "" + +#: ../data/gtkhash.xml.h:2 +msgid "File:" +msgstr "" + +#: ../data/gtkhash.xml.h:3 +msgid "Hash" +msgstr "" + +#: ../data/gtkhash.xml.h:4 +msgid "Hash functions:" +msgstr "" + +#: ../data/gtkhash.xml.h:5 +msgid "Preferences" +msgstr "" + +#: ../data/gtkhash.xml.h:6 +msgid "Text:" +msgstr "" + +#: ../data/gtkhash.xml.h:7 +msgid "_Edit" +msgstr "" + +#: ../data/gtkhash.xml.h:8 +msgid "_File" +msgstr "" + +#: ../data/gtkhash.xml.h:9 +msgid "_Help" +msgstr "" + +#: ../data/gtkhash.xml.h:10 +msgid "_Text" +msgstr "" + +#: ../data/gtkhash.xml.h:11 +msgid "_View" +msgstr "" + +#: ../data/nautilus/gtkhash-properties.xml.h:1 +msgid "Digest" +msgstr "" + +#: ../data/nautilus/gtkhash-properties.xml.h:2 +msgid "H_ash" +msgstr "" + +#: ../data/nautilus/gtkhash-properties.xml.h:3 +msgid "Hash Function" +msgstr "" + +#: ../data/nautilus/gtkhash-properties.xml.h:4 +msgid "Show _Disabled Hash Functions" +msgstr "" + +#: ../data/nautilus/gtkhash-properties.xml.h:5 +msgid "_Copy Digest" +msgstr "" + +#: ../src/callbacks.c:99 +msgid "Save Digests To File" +msgstr "" + +#: ../src/callbacks.c:310 +msgid "A GTK+ utility for computing digests using the mhash library." +msgstr "" + +#: ../src/callbacks.c:314 +msgid "translator-credits" +msgstr "" + +#: ../src/callbacks.c:339 +msgid "Select Files" +msgstr "" + +#: ../src/gui.c:75 +#, c-format +msgid "" +"Failed to read %s:\n" +"%s" +msgstr "" + +#: ../src/list.c:56 +msgid "Path" +msgstr "" + +#: ../src/list.c:62 +msgid "Filename" +msgstr "" + +#: ../src/main.c:56 +msgid "[FILE...]" +msgstr "" + +#: ../src/main.c:67 +#, c-format +msgid "Unknown option, try %s --help\n" +msgstr "" + +#: ../src/nautilus/properties.c:265 +msgid "Digests" +msgstr "" + +#: ../src/nautilus/properties-hash.c:367 +#, c-format +msgid "Estimated time remaining: %d minute" +msgstr "" + +#: ../src/nautilus/properties-hash.c:370 +#, c-format +msgid "Estimated time remaining: %d minutes" +msgstr "" + +#: ../src/nautilus/properties-hash.c:374 +#, c-format +msgid "Estimated time remaining: %d second" +msgstr "" + +#: ../src/nautilus/properties-hash.c:377 +#, c-format +msgid "Estimated time remaining: %d seconds" +msgstr "" diff --git a/po/sv.po b/po/sv.po new file mode 100644 index 0000000..a54e340 --- /dev/null +++ b/po/sv.po @@ -0,0 +1,135 @@ +# Swedish translation for gtkhash +# Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 +# This file is distributed under the same license as the gtkhash package. +# FIRST AUTHOR , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: gtkhash\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-11-15 23:59+0000\n" +"PO-Revision-Date: 2009-01-09 14:23+0000\n" +"Last-Translator: Mattias Ohlsson \n" +"Language-Team: Swedish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2009-11-15 22:44+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +#: ../data/gtkhash.xml.h:1 +msgid "File _List" +msgstr "Fil_lista" + +#: ../data/gtkhash.xml.h:2 +msgid "File:" +msgstr "Fil:" + +#: ../data/gtkhash.xml.h:3 +msgid "Hash" +msgstr "Hash" + +#: ../data/gtkhash.xml.h:4 +msgid "Hash functions:" +msgstr "Hashfunktioner:" + +#: ../data/gtkhash.xml.h:5 +msgid "Preferences" +msgstr "Inställningar" + +#: ../data/gtkhash.xml.h:6 +msgid "Text:" +msgstr "Text:" + +#: ../data/gtkhash.xml.h:7 +msgid "_Edit" +msgstr "_Redigera" + +#: ../data/gtkhash.xml.h:8 +msgid "_File" +msgstr "_Arkiv" + +#: ../data/gtkhash.xml.h:9 +msgid "_Help" +msgstr "_Hjälp" + +#: ../data/gtkhash.xml.h:10 +msgid "_Text" +msgstr "_Text" + +#: ../data/gtkhash.xml.h:11 +msgid "_View" +msgstr "_Visa" + +#: ../data/nautilus/gtkhash-properties.xml.h:1 +#, fuzzy +msgid "H_ash" +msgstr "Hash" + +#: ../src/callbacks.c:99 +msgid "Save Digests To File" +msgstr "" + +#: ../src/callbacks.c:310 +msgid "A GTK+ utility for computing digests using the mhash library." +msgstr "" + +#: ../src/callbacks.c:314 +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" Mattias Ohlsson https://launchpad.net/~mattias-oh" + +#: ../src/callbacks.c:339 +msgid "Select Files" +msgstr "Välj filer" + +#: ../src/gui.c:75 +#, c-format +msgid "" +"Failed to read %s:\n" +"%s" +msgstr "" +"Kunde inte läsa %s:\n" +"%s" + +#: ../src/list.c:56 +msgid "Path" +msgstr "Sökväg" + +#: ../src/list.c:62 +msgid "Filename" +msgstr "Filnamn" + +#: ../src/main.c:56 +msgid "[FILE...]" +msgstr "[FIL...]" + +#: ../src/main.c:67 +#, c-format +msgid "Unknown option, try %s --help\n" +msgstr "" + +#: ../src/nautilus/properties.c:178 +msgid "Digests" +msgstr "" + +#: ../src/nautilus/properties-hash.c:357 +#, c-format +msgid "Estimated time remaining: %d minute" +msgstr "" + +#: ../src/nautilus/properties-hash.c:360 +#, c-format +msgid "Estimated time remaining: %d minutes" +msgstr "" + +#: ../src/nautilus/properties-hash.c:364 +#, c-format +msgid "Estimated time remaining: %d second" +msgstr "" + +#: ../src/nautilus/properties-hash.c:367 +#, c-format +msgid "Estimated time remaining: %d seconds" +msgstr "" diff --git a/po/tr.po b/po/tr.po new file mode 100644 index 0000000..d2f8d28 --- /dev/null +++ b/po/tr.po @@ -0,0 +1,132 @@ +# Turkish translation for gtkhash +# Copyright (c) 2009 Rosetta Contributors and Canonical Ltd 2009 +# This file is distributed under the same license as the gtkhash package. +# FIRST AUTHOR , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: gtkhash\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-11-15 23:59+0000\n" +"PO-Revision-Date: 2009-01-15 18:01+0000\n" +"Last-Translator: zeugma \n" +"Language-Team: Turkish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2009-11-15 22:44+0000\n" +"X-Generator: Launchpad (build Unknown)\n" + +#: ../data/gtkhash.xml.h:1 +msgid "File _List" +msgstr "" + +#: ../data/gtkhash.xml.h:2 +msgid "File:" +msgstr "Dosya:" + +#: ../data/gtkhash.xml.h:3 +msgid "Hash" +msgstr "" + +#: ../data/gtkhash.xml.h:4 +msgid "Hash functions:" +msgstr "" + +#: ../data/gtkhash.xml.h:5 +msgid "Preferences" +msgstr "" + +#: ../data/gtkhash.xml.h:6 +msgid "Text:" +msgstr "Metin:" + +#: ../data/gtkhash.xml.h:7 +msgid "_Edit" +msgstr "_Düzenle" + +#: ../data/gtkhash.xml.h:8 +msgid "_File" +msgstr "_Dosya" + +#: ../data/gtkhash.xml.h:9 +msgid "_Help" +msgstr "_Yardım" + +#: ../data/gtkhash.xml.h:10 +msgid "_Text" +msgstr "_Metin" + +#: ../data/gtkhash.xml.h:11 +msgid "_View" +msgstr "_Görünüm" + +#: ../data/nautilus/gtkhash-properties.xml.h:1 +msgid "H_ash" +msgstr "" + +#: ../src/callbacks.c:99 +msgid "Save Digests To File" +msgstr "" + +#: ../src/callbacks.c:310 +msgid "A GTK+ utility for computing digests using the mhash library." +msgstr "" + +#: ../src/callbacks.c:314 +msgid "translator-credits" +msgstr "" +"Launchpad Contributions:\n" +" zeugma https://launchpad.net/~sunder67" + +#: ../src/callbacks.c:339 +msgid "Select Files" +msgstr "Dosyaları Seç" + +#: ../src/gui.c:75 +#, c-format +msgid "" +"Failed to read %s:\n" +"%s" +msgstr "" + +#: ../src/list.c:56 +msgid "Path" +msgstr "" + +#: ../src/list.c:62 +msgid "Filename" +msgstr "Dosya adı" + +#: ../src/main.c:56 +msgid "[FILE...]" +msgstr "[DOSYA...]" + +#: ../src/main.c:67 +#, c-format +msgid "Unknown option, try %s --help\n" +msgstr "" + +#: ../src/nautilus/properties.c:178 +msgid "Digests" +msgstr "" + +#: ../src/nautilus/properties-hash.c:357 +#, c-format +msgid "Estimated time remaining: %d minute" +msgstr "" + +#: ../src/nautilus/properties-hash.c:360 +#, c-format +msgid "Estimated time remaining: %d minutes" +msgstr "" + +#: ../src/nautilus/properties-hash.c:364 +#, c-format +msgid "Estimated time remaining: %d second" +msgstr "" + +#: ../src/nautilus/properties-hash.c:367 +#, c-format +msgid "Estimated time remaining: %d seconds" +msgstr "" diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..1fd25d5 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,22 @@ +SUBDIRS = hash + +if ENABLE_NAUTILUS +SUBDIRS += nautilus +endif + +bin_PROGRAMS = gtkhash + +gtkhash_SOURCES = \ + callbacks.c callbacks.h \ + gui.c gui.h \ + hash.c hash.h \ + list.c list.h \ + main.c main.h \ + prefs.c prefs.h + +gtkhash_CPPFLAGS = \ + $(GTHREAD_CFLAGS) $(GTK_CFLAGS) \ + -DBUILDER_XML="\"$(pkgdatadir)/gtkhash.xml\"" \ + -DLOCALEDIR="\"$(localedir)\"" + +gtkhash_LDADD = hash/hash.la $(GTHREAD_LIBS) $(GTK_LIBS) diff --git a/src/callbacks.c b/src/callbacks.c new file mode 100644 index 0000000..a5905a6 --- /dev/null +++ b/src/callbacks.c @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include + +#include "callbacks.h" +#include "main.h" +#include "gui.h" +#include "hash.h" +#include "prefs.h" +#include "list.h" +#include "hash/hash-string.h" + +static bool on_window_destroy(void) +{ + gtk_main_quit(); + return true; +} + +static void on_window_size_request(void) +{ + if (gui_is_maximised()) + return; + + int width, height; + gtk_window_get_size(gui.window, &width, &height); + prefs.width = width; + prefs.height = height; +} + +static void on_menuitem_file_activate(void) +{ + if (gui.busy) + return; + + bool sensitive = false; + + switch (gui_get_view()) { + case VIEW_FILE: + for (int i = 0; i < HASH_FUNCS_N; i++) { + if (hash.funcs[i].enabled && + *gtk_entry_get_text(gui.hash_widgets[i].entry_file)) + { + sensitive = true; + break; + } + } + break; + case VIEW_TEXT: + sensitive = true; + break; + case VIEW_FILE_LIST: + for (int i = 0; i < HASH_FUNCS_N; i++) { + if (hash.funcs[i].enabled) { + char *digest = list_get_digest(0, i); + if (digest != NULL && *digest) { + g_free(digest); + sensitive = true; + break; + } + } + } + break; + default: + g_assert_not_reached(); + } + + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_save_as), sensitive); +} + +static void on_menuitem_save_as_activate(void) +{ + GtkFileChooser *chooser = GTK_FILE_CHOOSER( + gtk_file_chooser_dialog_new(_("Save Digests"), NULL, + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL)); + gtk_file_chooser_set_do_overwrite_confirmation(chooser, true); + + if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) { + char *filename = gtk_file_chooser_get_filename(chooser); + GString *string = g_string_sized_new(1024); + + for (int i = 0; i < HASH_FUNCS_N; i++) { + if (!hash.funcs[i].enabled) + continue; + + switch (gui_get_view()) { + case VIEW_FILE: { + const char *digest = gtk_entry_get_text( + gui.hash_widgets[i].entry_file); + if (digest && *digest) + g_string_append_printf(string, "# %s\n", + hash.funcs[i].name); + else + continue; + char *path = gtk_file_chooser_get_filename( + GTK_FILE_CHOOSER(gui.filechooserbutton)); + char *basename = g_path_get_basename(path); + g_free(path); + g_string_append_printf(string, "%s %s\n", + gtk_entry_get_text(gui.hash_widgets[i].entry_file), + basename); + g_free(basename); + break; + } + case VIEW_TEXT: + g_string_append_printf(string, "# %s\n", hash.funcs[i].name); + g_string_append_printf(string, "%s \"%s\"\n", + gtk_entry_get_text(gui.hash_widgets[i].entry_text), + gtk_entry_get_text(gui.entry)); + break; + case VIEW_FILE_LIST: { + int prev = -1; + for (unsigned int row = 0; row < list_count_rows(); row++) + { + char *digest = list_get_digest(row, i); + if (digest && *digest) { + if (i != prev) + g_string_append_printf(string, "# %s\n", + hash.funcs[i].name); + prev = i; + } else { + if (digest) + g_free(digest); + prev = i; + continue; + } + char *uri = list_get_uri(row); + char *basename = g_filename_display_basename(uri); + g_string_append_printf(string, "%s %s\n", + digest, basename); + g_free(basename); + g_free(uri); + g_free(digest); + } + break; + } + default: + g_assert_not_reached(); + } + } + + char *data = g_string_free(string, false); + g_file_set_contents(filename, data, -1, NULL); + + g_free(data); + g_free(filename); + } + + gtk_widget_destroy(GTK_WIDGET(chooser)); +} + +static void on_menuitem_quit_activate(void) +{ + gtk_main_quit(); +} + +static void on_menuitem_edit_activate(void) +{ + GtkWidget *widget = gtk_window_get_focus(gui.window); + bool selection, editable, clipboard; + + if (GTK_IS_ENTRY(widget)) { + selection = gtk_editable_get_selection_bounds( + GTK_EDITABLE(widget), NULL, NULL); + editable = gtk_editable_get_editable(GTK_EDITABLE(widget)); + clipboard = gtk_clipboard_wait_is_text_available( + gtk_clipboard_get(GDK_NONE)); + + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_cut), selection && editable); + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_copy), selection); + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_paste), editable && clipboard); + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_delete), selection && editable); + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_select_all), true); + } else { + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_cut), false); + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_copy), false); + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_paste), false); + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_delete), false); + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_select_all), false); + } +} + +static void on_menuitem_cut_activate(void) +{ + GtkEditable *widget = GTK_EDITABLE(gtk_window_get_focus(gui.window)); + + gtk_editable_cut_clipboard(widget); +} + +static void on_menuitem_copy_activate(void) +{ + GtkEditable *widget = GTK_EDITABLE(gtk_window_get_focus(gui.window)); + + gtk_editable_copy_clipboard(widget); +} + +static void on_menuitem_paste_activate(void) +{ + GtkEditable *widget = GTK_EDITABLE(gtk_window_get_focus(gui.window)); + + gtk_editable_paste_clipboard(widget); +} + +static void on_menuitem_delete_activate(void) +{ + GtkEditable *widget = GTK_EDITABLE(gtk_window_get_focus(gui.window)); + + gtk_editable_delete_selection(widget); +} + +static void on_menuitem_select_all_activate(void) +{ + GtkEditable *widget = GTK_EDITABLE(gtk_window_get_focus(gui.window)); + + gtk_editable_set_position(widget, -1); + gtk_editable_select_region(widget, 0, -1); +} + +static void on_menuitem_prefs_activate(void) +{ + gtk_widget_show(GTK_WIDGET(gui.dialog)); +} + +static void on_radiomenuitem_toggled(void) +{ + gui_update(); +} + +static void on_menuitem_about_activate(void) +{ + const char *license = { + "This program is free software: you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation, either version 2 of the License, or\n" + "(at your option) any later version.\n\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n\n" + "You should have received a copy of the GNU General Public License along\n" + "with this program; if not, see .\n" + }; + + const char *authors[] = { + "Tristan Heaven ", + NULL + }; + + gtk_show_about_dialog( + gui.window, + "authors", authors, + "comments", _("A GTK+ utility for computing digests using the mhash library."), + "license", license, + "program-name", PACKAGE_NAME, +#if ENABLE_NLS + "translator-credits", _("translator-credits"), +#endif + "version", VERSION, + "website", "http://gtkhash.sourceforge.net/", + NULL); +} + +static void on_filechooserbutton_selection_changed(void) +{ + char *uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(gui.filechooserbutton)); + + gtk_widget_set_sensitive(GTK_WIDGET(gui.button_hash), uri ? true : false); + + gui_clear_digests(); +} + +static void on_entry_changed(void) +{ + g_signal_emit_by_name(gui.button_hash, "clicked"); +} + +static void on_toolbutton_add_clicked(void) +{ + GtkFileChooser *chooser = GTK_FILE_CHOOSER( + gtk_file_chooser_dialog_new(_("Select Files"), NULL, + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL)); + gtk_file_chooser_set_select_multiple(chooser, true); + gtk_file_chooser_set_local_only(chooser, false); + + if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) { + GSList *uris = gtk_file_chooser_get_uris(chooser); +// bool has_selected = false; + + for (unsigned int i = 0; i < g_slist_length(uris); i++) { + char *uri = g_slist_nth(uris, i)->data; + list_append_row(uri); + g_free(uri); +// has_selected = true; + } + +// gtk_widget_set_sensitive(GTK_WIDGET(gui.button_hash), has_selected); + g_slist_free(uris); + } + + gtk_widget_destroy(GTK_WIDGET(chooser)); +} + +static void on_toolbutton_remove_clicked(void) +{ + list_remove_selection(); +} + +static void on_toolbutton_clear_clicked(void) +{ + list_clear(); +} + +static void on_button_hash_clicked(void) +{ + if (gui_get_view() == VIEW_FILE) { + // XXX: Workaround for when user clicks Cancel in FileChooserDialog and + // XXX: uri is changed without emitting the "selection-changed" signal + on_filechooserbutton_selection_changed(); + if (!gtk_widget_get_sensitive(GTK_WIDGET(gui.button_hash))) + return; + } + + gui_set_busy(true); + gui_clear_digests(); + + switch (gui_get_view()) { + case VIEW_FILE: { + char *uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER( + gui.filechooserbutton)); + hash_file_start(uri); + break; + } + case VIEW_TEXT: { + const char *str = gtk_entry_get_text(gui.entry); + gtkhash_hash_string(hash.funcs, str); + gui_set_busy(false); + break; + } + case VIEW_FILE_LIST: + hash_file_list_start(); + break; + default: + g_assert_not_reached(); + } +} + +static void on_button_stop_clicked(void) +{ + hash_file_stop(); +} + +static bool on_dialog_delete_event(void) +{ + gtk_widget_hide(GTK_WIDGET(gui.dialog)); + return true; +} + +void callbacks_init(void) +{ + const struct { + GObject *obj; + const char *sig; + GCallback cb; + } callbacks[] = { + { G_OBJECT(gui.window), "destroy", G_CALLBACK(on_window_destroy) }, + { G_OBJECT(gui.window), "destroy-event", G_CALLBACK(on_window_destroy) }, + { G_OBJECT(gui.window), "delete-event", G_CALLBACK(on_window_destroy) }, + { G_OBJECT(gui.window), "size-request", on_window_size_request }, + { G_OBJECT(gui.menuitem_file), "activate", on_menuitem_file_activate }, + { G_OBJECT(gui.menuitem_save_as), "activate", on_menuitem_save_as_activate }, + { G_OBJECT(gui.menuitem_quit), "activate", on_menuitem_quit_activate }, + { G_OBJECT(gui.menuitem_edit), "activate", on_menuitem_edit_activate }, + { G_OBJECT(gui.menuitem_cut), "activate", on_menuitem_cut_activate }, + { G_OBJECT(gui.menuitem_copy), "activate", on_menuitem_copy_activate }, + { G_OBJECT(gui.menuitem_paste), "activate", on_menuitem_paste_activate }, + { G_OBJECT(gui.menuitem_delete), "activate", on_menuitem_delete_activate }, + { G_OBJECT(gui.menuitem_select_all), "activate", on_menuitem_select_all_activate }, + { G_OBJECT(gui.menuitem_prefs), "activate", on_menuitem_prefs_activate }, + { G_OBJECT(gui.radiomenuitem_file), "toggled", on_radiomenuitem_toggled }, + { G_OBJECT(gui.radiomenuitem_text), "toggled", on_radiomenuitem_toggled }, + { G_OBJECT(gui.radiomenuitem_file_list), "toggled", on_radiomenuitem_toggled }, + { G_OBJECT(gui.menuitem_about), "activate", on_menuitem_about_activate }, +// file-set isn't emitted when file is deleted +// { G_OBJECT(gui.filechooserbutton), "file-set", on_filechooserbutton_file_set }, + { G_OBJECT(gui.filechooserbutton), "selection-changed", on_filechooserbutton_selection_changed }, + { G_OBJECT(gui.entry), "changed", on_entry_changed }, + { G_OBJECT(gui.toolbutton_add), "clicked", on_toolbutton_add_clicked }, + { G_OBJECT(gui.toolbutton_remove), "clicked", on_toolbutton_remove_clicked }, + { G_OBJECT(gui.toolbutton_clear), "clicked", on_toolbutton_clear_clicked }, + { G_OBJECT(gui.button_hash), "clicked", on_button_hash_clicked }, + { G_OBJECT(gui.button_stop), "clicked", on_button_stop_clicked }, + { G_OBJECT(gui.dialog), "delete-event", G_CALLBACK(on_dialog_delete_event) }, + { G_OBJECT(gui.dialog_button_close), "clicked", G_CALLBACK(on_dialog_delete_event) } + }; + + for (unsigned int i = 0; i < G_N_ELEMENTS(callbacks); i++) + g_signal_connect(callbacks[i].obj, callbacks[i].sig, callbacks[i].cb, + NULL); +} diff --git a/src/callbacks.h b/src/callbacks.h new file mode 100644 index 0000000..624ec0a --- /dev/null +++ b/src/callbacks.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_CALLBACKS_H +#define GTKHASH_CALLBACKS_H + +void callbacks_init(void); + +#endif diff --git a/src/gui.c b/src/gui.c new file mode 100644 index 0000000..c1ecda3 --- /dev/null +++ b/src/gui.c @@ -0,0 +1,385 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "gui.h" +#include "main.h" +#include "callbacks.h" +#include "hash.h" +#include "list.h" +#include "prefs.h" + +static GObject *gui_get_object(GtkBuilder *builder, const char *name) +{ + g_assert(name); + + GObject *obj = gtk_builder_get_object(builder, name); + if (!obj) + g_error("unknown object: \"%s\"\n", name); + + return obj; +} + +static void gui_get_objects(GtkBuilder *builder) +{ + // Window + gui.window = GTK_WINDOW(gui_get_object(builder, "window")); + + // Menus + gui.menuitem_file = GTK_MENU_ITEM(gui_get_object(builder, + "menuitem_file")); + gui.menuitem_save_as = GTK_MENU_ITEM(gui_get_object(builder, + "menuitem_save_as")); + gui.menuitem_quit = GTK_MENU_ITEM(gui_get_object(builder, + "menuitem_quit")); + gui.menuitem_edit = GTK_MENU_ITEM(gui_get_object(builder, + "menuitem_edit")); + gui.menuitem_cut = GTK_MENU_ITEM(gui_get_object(builder, + "menuitem_cut")); + gui.menuitem_copy = GTK_MENU_ITEM(gui_get_object(builder, + "menuitem_copy")); + gui.menuitem_paste = GTK_MENU_ITEM(gui_get_object(builder, + "menuitem_paste")); + gui.menuitem_delete = GTK_MENU_ITEM(gui_get_object(builder, + "menuitem_delete")); + gui.menuitem_select_all = GTK_MENU_ITEM(gui_get_object(builder, + "menuitem_select_all")); + gui.menuitem_prefs = GTK_MENU_ITEM(gui_get_object(builder, + "menuitem_prefs")); + gui.menuitem_about = GTK_MENU_ITEM(gui_get_object(builder, + "menuitem_about")); + gui.radiomenuitem_file = GTK_RADIO_MENU_ITEM(gui_get_object(builder, + "radiomenuitem_file")); + gui.radiomenuitem_text = GTK_RADIO_MENU_ITEM(gui_get_object(builder, + "radiomenuitem_text")); + gui.radiomenuitem_file_list = GTK_RADIO_MENU_ITEM(gui_get_object(builder, + "radiomenuitem_file_list")); + + // Toolbar + gui.toolbar = GTK_TOOLBAR(gui_get_object(builder, + "toolbar")); + gui.toolbutton_add = GTK_TOOL_BUTTON(gui_get_object(builder, + "toolbutton_add")); + gui.toolbutton_remove = GTK_TOOL_BUTTON(gui_get_object(builder, + "toolbutton_remove")); + gui.toolbutton_clear = GTK_TOOL_BUTTON(gui_get_object(builder, + "toolbutton_clear")); + + // Containers + gui.vbox_single = GTK_VBOX(gui_get_object(builder, + "vbox_single")); + gui.vbox_list = GTK_VBOX(gui_get_object(builder, + "vbox_list")); + gui.hbox_input = GTK_HBOX(gui_get_object(builder, + "hbox_input")); + gui.hbox_output = GTK_HBOX(gui_get_object(builder, + "hbox_output")); + gui.vbox_outputlabels = GTK_VBOX(gui_get_object(builder, + "vbox_outputlabels")); + gui.vbox_digests_file = GTK_VBOX(gui_get_object(builder, + "vbox_digests_file")); + gui.vbox_digests_text = GTK_VBOX(gui_get_object(builder, + "vbox_digests_text")); + + // Inputs + gui.entry = GTK_ENTRY(gui_get_object(builder, + "entry")); + gui.filechooserbutton = GTK_FILE_CHOOSER_BUTTON(gui_get_object(builder, + "filechooserbutton")); + + // Labels + gui.label_text = GTK_LABEL(gui_get_object(builder, "label_text")); + gui.label_file = GTK_LABEL(gui_get_object(builder, "label_file")); + + // Tree View + gui.treeview = GTK_TREE_VIEW(gui_get_object(builder, "treeview")); + + // Buttons + gui.hseparator_buttons = GTK_HSEPARATOR(gui_get_object(builder, + "hseparator_buttons")); + gui.button_hash = GTK_BUTTON(gui_get_object(builder, "button_hash")); + gui.button_stop = GTK_BUTTON(gui_get_object(builder, "button_stop")); + + // Progress Bar + gui.progressbar = GTK_PROGRESS_BAR(gui_get_object(builder, "progressbar")); + + // Dialog + gui.dialog = GTK_DIALOG(gui_get_object(builder, + "dialog")); + gui.dialog_table = GTK_TABLE(gui_get_object(builder, + "dialog_table")); + gui.dialog_button_close = GTK_BUTTON(gui_get_object(builder, + "dialog_button_close")); +} + +static void init_hash_funcs(void) +{ + for (int i = 0; i < HASH_FUNCS_N; i++) { + gui.hash_widgets[i].button = GTK_TOGGLE_BUTTON( + gtk_check_button_new_with_label(hash.funcs[i].name)); + g_signal_connect(G_OBJECT(gui.hash_widgets[i].button), "toggled", + gui_update, NULL); + + // Label the digest outputs + char *label = g_strdup_printf("%s:", hash.funcs[i].name); + gui.hash_widgets[i].label = GTK_LABEL(gtk_label_new(label)); + g_free(label); + + gui.hash_widgets[i].entry_file = GTK_ENTRY(gtk_entry_new()); + gui.hash_widgets[i].entry_text = GTK_ENTRY(gtk_entry_new()); + + gtk_table_attach_defaults(gui.dialog_table, + GTK_WIDGET(gui.hash_widgets[i].button), + // Sort checkbuttons into 2 columns + i % 2 ? 1 : 0, + i % 2 ? 2 : 1, + i / 2, + i / 2 + 1); + + gtk_container_add(GTK_CONTAINER(gui.vbox_outputlabels), + GTK_WIDGET(gui.hash_widgets[i].label)); + // Left align + gtk_misc_set_alignment(GTK_MISC(gui.hash_widgets[i].label), 0.0, 0.5); + + gtk_container_add(GTK_CONTAINER(gui.vbox_digests_file), + GTK_WIDGET(gui.hash_widgets[i].entry_file)); + gtk_editable_set_editable(GTK_EDITABLE(gui.hash_widgets[i].entry_file), false); + + gtk_container_add(GTK_CONTAINER(gui.vbox_digests_text), + GTK_WIDGET(gui.hash_widgets[i].entry_text)); + gtk_editable_set_editable(GTK_EDITABLE(gui.hash_widgets[i].entry_text), false); + + gtk_widget_show(GTK_WIDGET(gui.hash_widgets[i].button)); + } +} + +void gui_init(void) +{ + GtkBuilder *builder = gtk_builder_new(); + +#if ENABLE_NLS + gtk_builder_set_translation_domain(builder, PACKAGE); +#endif + + if (!gtk_builder_add_from_file(builder, BUILDER_XML, NULL)) { + GtkWidget *dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to read %s:\n%s"), + BUILDER_XML, g_strerror(errno)); + gtk_dialog_run(GTK_DIALOG(dialog)); + exit(EXIT_FAILURE); + } + + gui_get_objects(builder); + callbacks_init(); + init_hash_funcs(); + + g_object_unref(builder); +} + +void gui_run(void) +{ + // Show window here so it doesn't resize just after it's opened + gtk_widget_show(GTK_WIDGET(gui.window)); + + gtk_main(); +} + +enum gui_view_e gui_get_view(void) +{ + if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM( + gui.radiomenuitem_file))) + { + return VIEW_FILE; + } else if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM( + gui.radiomenuitem_text))) + { + return VIEW_TEXT; + } else if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM( + gui.radiomenuitem_file_list))) + { + return VIEW_FILE_LIST; + } else + g_assert_not_reached(); +} + +void gui_update(void) +{ + bool has_enabled = false; + + for (int i = 0; i < HASH_FUNCS_N; i++) { + hash.funcs[i].enabled = gtk_toggle_button_get_active(gui.hash_widgets[i].button); + if (hash.funcs[i].enabled) { + gtk_widget_show(GTK_WIDGET(gui.hash_widgets[i].label)); + gtk_widget_show(GTK_WIDGET(gui.hash_widgets[i].entry_file)); + gtk_widget_show(GTK_WIDGET(gui.hash_widgets[i].entry_text)); + has_enabled = true; + } else { + gtk_widget_hide(GTK_WIDGET(gui.hash_widgets[i].label)); + gtk_widget_hide(GTK_WIDGET(gui.hash_widgets[i].entry_file)); + gtk_widget_hide(GTK_WIDGET(gui.hash_widgets[i].entry_text)); + } + } + + if (!has_enabled) { + for (int i = 0; i < HASH_FUNCS_N; i++) + if (HASH_FUNC_IS_DEFAULT(i)) + gtk_toggle_button_set_active(gui.hash_widgets[i].button, true); + return; + } + + list_update(); + + switch (gui_get_view()) { + case VIEW_FILE: + gtk_widget_hide(GTK_WIDGET(gui.toolbar)); + gtk_widget_hide(GTK_WIDGET(gui.label_text)); + gtk_widget_hide(GTK_WIDGET(gui.entry)); + gtk_widget_hide(GTK_WIDGET(gui.vbox_list)); + gtk_widget_hide(GTK_WIDGET(gui.vbox_digests_text)); + gtk_widget_show(GTK_WIDGET(gui.label_file)); + gtk_widget_show(GTK_WIDGET(gui.filechooserbutton)); + gtk_widget_show(GTK_WIDGET(gui.vbox_single)); + gtk_widget_show(GTK_WIDGET(gui.vbox_digests_file)); + gtk_widget_show(GTK_WIDGET(gui.hseparator_buttons)); + gtk_widget_show(GTK_WIDGET(gui.button_hash)); + + char *uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER( + gui.filechooserbutton)); + if (uri) { + gtk_widget_set_sensitive(GTK_WIDGET(gui.button_hash), true); + g_free(uri); + } else + gtk_widget_set_sensitive(GTK_WIDGET(gui.button_hash), false); + + break; + case VIEW_TEXT: + gtk_widget_hide(GTK_WIDGET(gui.toolbar)); + gtk_widget_hide(GTK_WIDGET(gui.label_file)); + gtk_widget_hide(GTK_WIDGET(gui.filechooserbutton)); + gtk_widget_hide(GTK_WIDGET(gui.vbox_list)); + gtk_widget_hide(GTK_WIDGET(gui.vbox_digests_file)); + gtk_widget_hide(GTK_WIDGET(gui.hseparator_buttons)); + gtk_widget_hide(GTK_WIDGET(gui.button_hash)); + gtk_widget_show(GTK_WIDGET(gui.label_text)); + gtk_widget_show(GTK_WIDGET(gui.entry)); + gtk_widget_show(GTK_WIDGET(gui.vbox_single)); + gtk_widget_show(GTK_WIDGET(gui.vbox_digests_text)); + + g_signal_emit_by_name(gui.button_hash, "clicked"); + + break; + case VIEW_FILE_LIST: + gtk_widget_hide(GTK_WIDGET(gui.vbox_single)); + gtk_widget_hide(GTK_WIDGET(gui.hseparator_buttons)); + gtk_widget_show(GTK_WIDGET(gui.toolbar)); + gtk_widget_show(GTK_WIDGET(gui.vbox_list)); + gtk_widget_show(GTK_WIDGET(gui.button_hash)); + + gtk_widget_set_sensitive(GTK_WIDGET(gui.button_hash), list_count_rows()); + + break; + default: + g_assert_not_reached(); + } + + gtk_window_resize(gui.window, + CLAMP(prefs.width, 1, prefs.width), + CLAMP(prefs.height, 1, prefs.height)); +} + +void gui_clear_digests(void) +{ + switch (gui_get_view()) { + case VIEW_FILE: + for (int i = 0; i < HASH_FUNCS_N; i++) + gtk_entry_set_text(gui.hash_widgets[i].entry_file, ""); + break; + case VIEW_TEXT: + for (int i = 0; i < HASH_FUNCS_N; i++) + gtk_entry_set_text(gui.hash_widgets[i].entry_text, ""); + break; + case VIEW_FILE_LIST: + list_clear_digests(); + break; + default: + g_assert_not_reached(); + } +} + +void gui_set_busy(const bool busy) +{ + gui.busy = busy; + + if (gui_get_view() == VIEW_TEXT) + return; + + gtk_widget_set_visible(GTK_WIDGET(gui.button_hash), !busy); + gtk_widget_set_visible(GTK_WIDGET(gui.button_stop), busy); + + gtk_progress_bar_set_fraction(gui.progressbar, 0.0); + gtk_widget_set_visible(GTK_WIDGET(gui.progressbar), busy); + + gtk_widget_set_sensitive(GTK_WIDGET(gui.hbox_input), !busy); + gtk_widget_set_sensitive(GTK_WIDGET(gui.hbox_output), !busy); + gtk_widget_set_sensitive(GTK_WIDGET(gui.toolbar), !busy); + + gtk_widget_set_sensitive(GTK_WIDGET(gui.radiomenuitem_text), !busy); + gtk_widget_set_sensitive(GTK_WIDGET(gui.radiomenuitem_file), !busy); + gtk_widget_set_sensitive(GTK_WIDGET(gui.radiomenuitem_file_list), !busy); + + gtk_widget_set_sensitive(GTK_WIDGET(gui.dialog_table), !busy); + + if (busy) { + gtk_window_set_default(gui.window, GTK_WIDGET(gui.button_stop)); + gtk_widget_set_sensitive(GTK_WIDGET(gui.menuitem_save_as), false); + } else { + gtk_window_set_default(gui.window, GTK_WIDGET(gui.button_hash)); + // User may already have menu open, so make sure save_as gets updated + g_signal_emit_by_name(gui.menuitem_file, "activate"); + } +} + +bool gui_is_maximised(void) +{ + GdkWindow *window = GTK_WIDGET(gui.window)->window; + + if (!window) + return false; + + GdkWindowState state = gdk_window_get_state(window); + + return (state & GDK_WINDOW_STATE_MAXIMIZED); +} + +void gui_chooser_set_uri(const char *uri) +{ + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gui.radiomenuitem_file), + true); + + gtk_file_chooser_set_uri(GTK_FILE_CHOOSER(gui.filechooserbutton), uri); +} diff --git a/src/gui.h b/src/gui.h new file mode 100644 index 0000000..bcf16a7 --- /dev/null +++ b/src/gui.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_GUI_H +#define GTKHASH_GUI_H + +#include +#include + +#include "hash.h" + +enum gui_view_e { + VIEW_FILE, + VIEW_TEXT, + VIEW_FILE_LIST +}; + +struct { + bool busy; + GtkWindow *window; + GtkMenuItem *menuitem_file, *menuitem_save_as, *menuitem_quit; + GtkMenuItem *menuitem_edit; + GtkMenuItem *menuitem_cut, *menuitem_copy, *menuitem_paste; + GtkMenuItem *menuitem_delete, *menuitem_select_all, *menuitem_prefs; + GtkMenuItem *menuitem_about; + GtkRadioMenuItem *radiomenuitem_file, *radiomenuitem_text, *radiomenuitem_file_list; + GtkToolbar *toolbar; + GtkToolButton *toolbutton_add, *toolbutton_remove, *toolbutton_clear; + GtkVBox *vbox_single, *vbox_list; + GtkHBox *hbox_input, *hbox_output; + GtkVBox *vbox_outputlabels, *vbox_digests_file, *vbox_digests_text; + GtkEntry *entry; + GtkFileChooserButton *filechooserbutton; + GtkLabel *label_text, *label_file; + GtkTreeView *treeview; + GtkTreeModel *treemodel; + GtkListStore *liststore; + GtkHSeparator *hseparator_buttons; + GtkProgressBar *progressbar; + GtkButton *button_hash, *button_stop; + GtkDialog *dialog; + GtkTable *dialog_table; + GtkButton *dialog_button_close; + struct { + GtkToggleButton *button; + GtkLabel *label; + GtkEntry *entry_file, *entry_text; + } hash_widgets[HASH_FUNCS_N]; +} gui; + +void gui_init(void); +void gui_run(void); +enum gui_view_e gui_get_view(void); +void gui_update(void); +void gui_clear_digests(void); +void gui_set_busy(const bool set); +bool gui_is_maximised(void); +void gui_chooser_set_uri(const char *path); + +#endif diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..93e4a66 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "hash.h" +#include "main.h" +#include "gui.h" +#include "list.h" +#include "hash/hash-func.h" +#include "hash/hash-string.h" +#include "hash/hash-file.h" + +void gtkhash_hash_string_finish_cb(const enum hash_func_e id, + const char *digest) +{ + gtk_entry_set_text(gui.hash_widgets[id].entry_text, digest); +} + +void gtkhash_hash_file_report_cb(G_GNUC_UNUSED void *data, goffset file_size, + goffset total_read, G_GNUC_UNUSED GTimer *timer) +{ + gtk_progress_bar_set_fraction(gui.progressbar, + (double)total_read / + (double)file_size); +} + +void gtkhash_hash_file_finish_cb(G_GNUC_UNUSED void *data) +{ + const bool stop = gtkhash_hash_file_get_stop(&hash.file_data); + + switch (gui_get_view()) { + case VIEW_FILE: { + if (stop) + break; + + for (int i = 0; i < HASH_FUNCS_N; i++) { + const char *digest = gtkhash_hash_func_get_digest(&hash.funcs[i]); + gtk_entry_set_text(gui.hash_widgets[i].entry_file, digest); + } + + break; + } + case VIEW_FILE_LIST: { + g_assert(hash.uris); + g_assert(hash.uris->data); + + if (stop) + break; + + for (int i = 0; i < HASH_FUNCS_N; i++) { + const char *digest = gtkhash_hash_func_get_digest(&hash.funcs[i]); + list_set_digest(hash.uris->data, i, digest); + } + + g_free(hash.uris->data); + if ((hash.uris = g_slist_delete_link(hash.uris, hash.uris))) { + hash_file_start(hash.uris->data); + return; + } + + break; + } + default: + g_assert_not_reached(); + } + + gui_set_busy(false); +} + +void hash_file_start(const char *uri) +{ + if (gui_get_view() != VIEW_FILE_LIST) + gtkhash_hash_file_clear_digests(&hash.file_data); + + gtkhash_hash_file_set_uri(&hash.file_data, uri); + gtkhash_hash_file_set_stop(&hash.file_data, false); + gtkhash_hash_file_set_state(&hash.file_data, HASH_FILE_STATE_START); + gtkhash_hash_file_add_source(&hash.file_data); +} + +void hash_file_list_start(void) +{ + gtkhash_hash_file_clear_digests(&hash.file_data); + + if (hash.uris) + g_slist_free_full(hash.uris, g_free); + + hash.uris = list_get_all_uris(); + g_assert(hash.uris); + + hash_file_start(hash.uris->data); +} + +void hash_file_stop(void) +{ + gtkhash_hash_file_set_stop(&hash.file_data, true); + + while (gtkhash_hash_file_get_state(&hash.file_data) != HASH_FILE_STATE_IDLE) + gtk_main_iteration_do(false); +} + +void hash_init(void) +{ + gtkhash_hash_func_init_all(hash.funcs); + gtkhash_hash_file_init(&hash.file_data, hash.funcs, NULL); + hash.uris = NULL; +} diff --git a/src/hash.h b/src/hash.h new file mode 100644 index 0000000..ed03ff6 --- /dev/null +++ b/src/hash.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_HASH_H +#define GTKHASH_HASH_H + +#include "hash/hash-func.h" +#include "hash/hash-file.h" + +struct { + struct hash_func_s funcs[HASH_FUNCS_N]; + struct hash_file_s file_data; + GSList *uris; +} hash; + +void hash_file_start(const char *uri); +void hash_file_list_start(void); +void hash_file_stop(void); +void hash_init(void); + +#endif diff --git a/src/hash/Makefile.am b/src/hash/Makefile.am new file mode 100644 index 0000000..f4571f1 --- /dev/null +++ b/src/hash/Makefile.am @@ -0,0 +1,17 @@ +SUBDIRS = mutils + +noinst_LTLIBRARIES = hash.la + +hash_la_SOURCES = \ + hash-file.c hash-file.h \ + hash-func.c hash-func.h \ + hash-lib.c hash-lib.h \ + hash-lib-glib.c hash-lib-glib.h \ + hash-lib-mhash.c hash-lib-mhash.h \ + hash-string.c hash-string.h + +hash_la_CPPFLAGS = -DIN_HASH_LIB $(GDK_CFLAGS) + +hash_la_LDFLAGS = -avoid-version -module + +hash_la_LIBADD = $(GDK_LIBS) $(MHASH_LIBS) diff --git a/src/hash/hash-file.c b/src/hash/hash-file.c new file mode 100644 index 0000000..2e5c31d --- /dev/null +++ b/src/hash/hash-file.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "hash-file.h" +#include "hash-func.h" +#include "hash-lib.h" + +static bool gtkhash_hash_file(struct hash_file_s *data); + +unsigned int gtkhash_hash_file_get_source(struct hash_file_s *data) +{ + g_mutex_lock(data->priv.mutex); + unsigned int source = data->priv.source; + g_mutex_unlock(data->priv.mutex); + + return source; +} + +static void gtkhash_hash_file_set_source(struct hash_file_s *data, + const unsigned int source) +{ + g_mutex_lock(data->priv.mutex); + data->priv.source = source; + g_mutex_unlock(data->priv.mutex); +} + +void gtkhash_hash_file_add_source(struct hash_file_s *data) +{ + g_mutex_lock(data->priv.mutex); + if (G_UNLIKELY(data->priv.source != 0)) + g_critical("source was already added"); + data->priv.source = gdk_threads_add_idle( + (GSourceFunc)gtkhash_hash_file, data); + g_mutex_unlock(data->priv.mutex); +} + +static void gtkhash_hash_file_remove_source(struct hash_file_s *data) +{ + g_mutex_lock(data->priv.mutex); + if (G_UNLIKELY(!g_source_remove(data->priv.source))) + g_critical("failed to remove source"); + data->priv.source = 0; + g_mutex_unlock(data->priv.mutex); +} + +bool gtkhash_hash_file_get_stop(struct hash_file_s *data) +{ + g_mutex_lock(data->priv.mutex); + bool stop = data->priv.stop; + g_mutex_unlock(data->priv.mutex); + + return stop; +} + +void gtkhash_hash_file_set_stop(struct hash_file_s *data, const bool stop) +{ + g_mutex_lock(data->priv.mutex); + data->priv.stop = stop; + g_mutex_unlock(data->priv.mutex); +} + +enum hash_file_state_e gtkhash_hash_file_get_state(struct hash_file_s *data) +{ + g_mutex_lock(data->priv.mutex); + enum hash_file_state_e state = data->priv.state; + g_mutex_unlock(data->priv.mutex); + + return state; +} + +void gtkhash_hash_file_set_state(struct hash_file_s *data, + const enum hash_file_state_e state) +{ + g_mutex_lock(data->priv.mutex); + data->priv.state = state; + g_mutex_unlock(data->priv.mutex); +} + +void gtkhash_hash_file_set_uri(struct hash_file_s *data, const char *uri) +{ + data->uri = uri; +} + +static void gtkhash_hash_file_start(struct hash_file_s *data) +{ + g_assert(data->uri); + + for (int i = 0; i < HASH_FUNCS_N; i++) + if (data->funcs[i].enabled) + gtkhash_hash_lib_start(&data->funcs[i]); + + data->buffer = g_malloc(FILE_BUFFER_SIZE); + data->file = g_file_new_for_uri(data->uri); + data->current_func = 0; + data->just_read = 0; + data->total_read = 0; + data->timer = g_timer_new(); + + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_OPEN); +} + +static void gtkhash_hash_file_open_finish( + G_GNUC_UNUSED GObject *source, GAsyncResult *res, struct hash_file_s *data) +{ + data->stream = g_file_read_finish(data->file, res, NULL); + if (!data->stream) { + g_warning("file_open_finish: failed to open file"); + gtkhash_hash_file_set_stop(data, true); + } + + if (gtkhash_hash_file_get_stop(data)) + if (data->stream) + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_CLOSE); + else + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_FINISH); + else + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_GET_SIZE); + + gtkhash_hash_file_add_source(data); +} + +static void gtkhash_hash_file_open(struct hash_file_s *data) +{ + if (gtkhash_hash_file_get_stop(data)) { + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_FINISH); + return; + } + + gtkhash_hash_file_remove_source(data); + g_file_read_async(data->file, G_PRIORITY_DEFAULT, NULL, + (GAsyncReadyCallback)gtkhash_hash_file_open_finish, data); +} + +static void gtkhash_hash_file_get_size_finish( + G_GNUC_UNUSED GObject *source, GAsyncResult *res, struct hash_file_s *data) +{ + GFileInfo *info = g_file_input_stream_query_info_finish( + data->stream, res, NULL); + data->file_size = g_file_info_get_size(info); + g_object_unref(info); + + if (gtkhash_hash_file_get_stop(data)) + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_CLOSE); + else if (data->file_size == 0) + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_HASH); + else + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_READ); + + gtkhash_hash_file_add_source(data); +} + +static void gtkhash_hash_file_get_size(struct hash_file_s *data) +{ + if (gtkhash_hash_file_get_stop(data)) { + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_CLOSE); + return; + } + + gtkhash_hash_file_remove_source(data); + g_file_input_stream_query_info_async(data->stream, + G_FILE_ATTRIBUTE_STANDARD_SIZE, G_PRIORITY_DEFAULT, NULL, + (GAsyncReadyCallback)gtkhash_hash_file_get_size_finish, data); +} + +static void gtkhash_hash_file_read_finish( + G_GNUC_UNUSED GObject *source, GAsyncResult *res, struct hash_file_s *data) +{ + data->just_read = g_input_stream_read_finish( + G_INPUT_STREAM(data->stream), res, NULL); + + if (G_UNLIKELY(data->just_read == -1)) { + g_warning("file_read_finish: failed to read file"); + gtkhash_hash_file_set_stop(data, true); + } else if (G_UNLIKELY(data->just_read == 0)) { + g_warning("file_read_finish: unexpected EOF"); + gtkhash_hash_file_set_stop(data, true); + } else { + data->total_read += data->just_read; + if (G_UNLIKELY(data->total_read > data->file_size)) { + g_warning("file_read_finish: read %" G_GOFFSET_FORMAT + " bytes more than expected", + data->total_read - data->file_size); + gtkhash_hash_file_set_stop(data, true); + } else + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_HASH); + } + + if (G_UNLIKELY(gtkhash_hash_file_get_stop(data))) + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_CLOSE); + + gtkhash_hash_file_add_source(data); +} + +static void gtkhash_hash_file_read(struct hash_file_s *data) +{ + if (G_UNLIKELY(gtkhash_hash_file_get_stop(data))) { + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_CLOSE); + return; + } + + gtkhash_hash_file_remove_source(data); + g_input_stream_read_async(G_INPUT_STREAM(data->stream), + data->buffer, FILE_BUFFER_SIZE, G_PRIORITY_DEFAULT, NULL, + (GAsyncReadyCallback)gtkhash_hash_file_read_finish, data); +} + +static void gtkhash_hash_file_hash(struct hash_file_s *data) +{ + if (G_UNLIKELY(gtkhash_hash_file_get_stop(data))) { + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_CLOSE); + return; + } else if (data->current_func < HASH_FUNCS_N) { + if (data->funcs[data->current_func].enabled) { + gtkhash_hash_lib_update(&data->funcs[data->current_func], + data->buffer, data->just_read); + } + data->current_func++; + return; + } + + data->current_func = 0; + + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_REPORT); +} + +static void gtkhash_hash_file_report(struct hash_file_s *data) +{ + if (data->total_read >= data->file_size) + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_CLOSE); + else + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_READ); + + if (data->file_size == 0) + return; + + gtkhash_hash_file_report_cb(data->cb_data, data->file_size, + data->total_read, data->timer); +} + +static void gtkhash_hash_file_close_finish( + G_GNUC_UNUSED GObject *source, GAsyncResult *res, struct hash_file_s *data) +{ + if (!g_input_stream_close_finish(G_INPUT_STREAM(data->stream), + res, NULL)) + { + g_warning("file_close_finish: failed to close file"); + } + + g_object_unref(data->stream); + + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_FINISH); + gtkhash_hash_file_add_source(data); +} + +static void gtkhash_hash_file_close(struct hash_file_s *data) +{ + gtkhash_hash_file_remove_source(data); + g_input_stream_close_async(G_INPUT_STREAM(data->stream), + G_PRIORITY_DEFAULT, NULL, + (GAsyncReadyCallback)gtkhash_hash_file_close_finish, data); +} + +static void gtkhash_hash_file_finish(struct hash_file_s *data) +{ + if (gtkhash_hash_file_get_stop(data)) { + for (int i = 0; i < HASH_FUNCS_N; i++) + if (data->funcs[i].enabled) + gtkhash_hash_lib_stop(&data->funcs[i]); + } else { + for (int i = 0; i < HASH_FUNCS_N; i++) + if (data->funcs[i].enabled) + gtkhash_hash_lib_finish(&data->funcs[i]); + } + + g_timer_destroy(data->timer); + g_free(data->buffer); + g_object_unref(data->file); + + gtkhash_hash_file_set_source(data, 0); + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_TERM); +} + +static bool gtkhash_hash_file(struct hash_file_s *data) +{ + static void (* const state_funcs[])(struct hash_file_s *) = { + gtkhash_hash_file_start, + gtkhash_hash_file_open, + gtkhash_hash_file_get_size, + gtkhash_hash_file_read, + gtkhash_hash_file_hash, + gtkhash_hash_file_report, + gtkhash_hash_file_close, + gtkhash_hash_file_finish + }; + + const enum hash_file_state_e state = gtkhash_hash_file_get_state(data); + + if (state == HASH_FILE_STATE_TERM) { + gtkhash_hash_file_set_state(data, HASH_FILE_STATE_IDLE); + gtkhash_hash_file_finish_cb(data->cb_data); + return false; + } + + // Call func + state_funcs[state](data); + + return true; +} + +void gtkhash_hash_file_init(struct hash_file_s *data, struct hash_func_s *funcs, + void *cb_data) +{ + data->priv.mutex = g_mutex_new(); + data->priv.source = 0; + data->priv.state = HASH_FILE_STATE_IDLE; + data->priv.stop = false; + data->funcs = funcs; + data->cb_data = cb_data; + data->uri = NULL; +} + +void gtkhash_hash_file_deinit(struct hash_file_s *data) +{ + g_assert(data->priv.source == 0); + + g_mutex_free(data->priv.mutex); +} + +void gtkhash_hash_file_clear_digests(struct hash_file_s *data) +{ + for (int i = 0; i < HASH_FUNCS_N; i++) + gtkhash_hash_func_set_digest(&data->funcs[i], NULL); +} diff --git a/src/hash/hash-file.h b/src/hash/hash-file.h new file mode 100644 index 0000000..50c15d6 --- /dev/null +++ b/src/hash/hash-file.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_HASH_FILE_H +#define GTKHASH_HASH_FILE_H + +#include +#include +#include +#include + +#include "hash-func.h" + +enum hash_file_state_e { + HASH_FILE_STATE_START, + HASH_FILE_STATE_OPEN, + HASH_FILE_STATE_GET_SIZE, + HASH_FILE_STATE_READ, + HASH_FILE_STATE_HASH, + HASH_FILE_STATE_REPORT, + HASH_FILE_STATE_CLOSE, + HASH_FILE_STATE_FINISH, + HASH_FILE_STATE_TERM, + HASH_FILE_STATE_IDLE +}; + +struct hash_file_s { + void *cb_data; + const char *uri; + GFile *file; + GFileInputStream *stream; + goffset file_size; + goffset total_read; + gssize just_read; + uint8_t *buffer; + GTimer *timer; + enum hash_func_e current_func; + struct hash_func_s *funcs; + struct { + GMutex *mutex; + unsigned int source; + bool stop; + enum hash_file_state_e state; + } priv; +}; + +unsigned int gtkhash_hash_file_get_source(struct hash_file_s *data); +void gtkhash_hash_file_add_source(struct hash_file_s *data); +bool gtkhash_hash_file_get_stop(struct hash_file_s *data); +void gtkhash_hash_file_set_stop(struct hash_file_s *data, const bool stop); +enum hash_file_state_e gtkhash_hash_file_get_state(struct hash_file_s *data); +void gtkhash_hash_file_set_state(struct hash_file_s *data, + const enum hash_file_state_e state); +void gtkhash_hash_file_set_uri(struct hash_file_s *data, const char *uri); +void gtkhash_hash_file_init(struct hash_file_s *data, struct hash_func_s *funcs, + void *cb_data); +void gtkhash_hash_file_deinit(struct hash_file_s *data); +void gtkhash_hash_file_clear_digests(struct hash_file_s *data); + +void gtkhash_hash_file_report_cb(void *data, goffset file_size, + goffset total_read, GTimer *timer); +void gtkhash_hash_file_finish_cb(void *data); + +#endif diff --git a/src/hash/hash-func.c b/src/hash/hash-func.c new file mode 100644 index 0000000..a2f23f0 --- /dev/null +++ b/src/hash/hash-func.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include + +#include "hash-func.h" +#include "hash-lib.h" + +static const char * const hash_func_names[HASH_FUNCS_N] = { + [HASH_FUNC_MD2] = "MD2", + [HASH_FUNC_MD4] = "MD4", + [HASH_FUNC_MD5] = "MD5", + [HASH_FUNC_SHA1] = "SHA1", + [HASH_FUNC_SHA224] = "SHA224", + [HASH_FUNC_SHA256] = "SHA256", + [HASH_FUNC_SHA384] = "SHA384", + [HASH_FUNC_SHA512] = "SHA512", + [HASH_FUNC_RIPEMD128] = "RIPEMD128", + [HASH_FUNC_RIPEMD160] = "RIPEMD160", + [HASH_FUNC_RIPEMD256] = "RIPEMD256", + [HASH_FUNC_RIPEMD320] = "RIPEMD320", + [HASH_FUNC_HAVAL128] = "HAVAL128", + [HASH_FUNC_HAVAL160] = "HAVAL160", + [HASH_FUNC_HAVAL192] = "HAVAL192", + [HASH_FUNC_HAVAL224] = "HAVAL224", + [HASH_FUNC_HAVAL256] = "HAVAL256", + [HASH_FUNC_TIGER128] = "TIGER128", + [HASH_FUNC_TIGER160] = "TIGER160", + [HASH_FUNC_TIGER192] = "TIGER192", + [HASH_FUNC_GOST] = "GOST", + [HASH_FUNC_WHIRLPOOL] = "WHIRLPOOL", + [HASH_FUNC_SNEFRU128] = "SNEFRU128", + [HASH_FUNC_SNEFRU256] = "SNEFRU256", + [HASH_FUNC_CRC32] = "CRC32", + [HASH_FUNC_CRC32B] = "CRC32B", + [HASH_FUNC_ADLER32] = "ADLER32" +}; + +enum hash_func_e gtkhash_hash_func_get_id_from_name(const char *name) +{ + g_assert(name); + + for (int i = 0; i < HASH_FUNCS_N; i++) + if (g_strcmp0(name, hash_func_names[i]) == 0) + return i; + + g_warning("unknown hash func name '%s'", name); + + return HASH_FUNC_INVALID; +} + +void gtkhash_hash_func_set_digest(struct hash_func_s *func, char *digest) +{ + g_assert(func); + + if (func->priv.digest) + g_free(func->priv.digest); + + func->priv.digest = digest; +} + +const char *gtkhash_hash_func_get_digest(struct hash_func_s *func) +{ + g_assert(func); + + if (func->priv.digest) + return func->priv.digest; + else + return ""; +} + +static void gtkhash_hash_func_init(struct hash_func_s *func, + const enum hash_func_e id) +{ + func->id = id; + func->enabled = false; + func->name = hash_func_names[id]; + func->priv.digest = NULL; + func->priv.lib_data = NULL; +} + +void gtkhash_hash_func_init_all(struct hash_func_s *funcs) +{ + g_assert(funcs); + + for (int i = 0; i < HASH_FUNCS_N; i++) + gtkhash_hash_func_init(&funcs[i], i); +} + +void gtkhash_hash_func_deinit_all(struct hash_func_s *funcs) +{ + g_assert(funcs); + + for (int i = 0; i < HASH_FUNCS_N; i++) { + gtkhash_hash_func_set_digest(&funcs[i], NULL); + funcs[i].name = NULL; + funcs[i].id = HASH_FUNC_INVALID; + } +} diff --git a/src/hash/hash-func.h b/src/hash/hash-func.h new file mode 100644 index 0000000..3f6afe9 --- /dev/null +++ b/src/hash/hash-func.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_HASH_FUNC_H +#define GTKHASH_HASH_FUNC_H + +#include + +#define HASH_FUNCS_N 27 +#define HASH_FUNC_IS_DEFAULT(X) \ + ((X) == HASH_FUNC_MD5 || (X) == HASH_FUNC_SHA1 || (X) == HASH_FUNC_SHA256) + +// All supported hash functions +enum hash_func_e { + HASH_FUNC_INVALID = -1, + HASH_FUNC_MD2 = 0, + HASH_FUNC_MD4 = 1, + HASH_FUNC_MD5 = 2, + HASH_FUNC_SHA1 = 3, + HASH_FUNC_SHA224 = 4, + HASH_FUNC_SHA256 = 5, + HASH_FUNC_SHA384 = 6, + HASH_FUNC_SHA512 = 7, + HASH_FUNC_RIPEMD128 = 8, + HASH_FUNC_RIPEMD160 = 9, + HASH_FUNC_RIPEMD256 = 10, + HASH_FUNC_RIPEMD320 = 11, + HASH_FUNC_HAVAL128 = 12, + HASH_FUNC_HAVAL160 = 13, + HASH_FUNC_HAVAL192 = 14, + HASH_FUNC_HAVAL224 = 15, + HASH_FUNC_HAVAL256 = 16, + HASH_FUNC_TIGER128 = 17, + HASH_FUNC_TIGER160 = 18, + HASH_FUNC_TIGER192 = 19, + HASH_FUNC_GOST = 20, + HASH_FUNC_WHIRLPOOL = 21, + HASH_FUNC_SNEFRU128 = 22, + HASH_FUNC_SNEFRU256 = 23, + HASH_FUNC_CRC32 = 24, + HASH_FUNC_CRC32B = 25, + HASH_FUNC_ADLER32 = 26 +}; + +struct hash_func_s { + enum hash_func_e id; + bool enabled; + const char *name; + struct { + char *digest; + void *lib_data; + } priv; +}; + +enum hash_func_e gtkhash_hash_func_get_id_from_name(const char *name); +void gtkhash_hash_func_set_digest(struct hash_func_s *func, char *digest); +const char *gtkhash_hash_func_get_digest(struct hash_func_s *func); +void gtkhash_hash_func_init_all(struct hash_func_s *funcs); +void gtkhash_hash_func_deinit_all(struct hash_func_s *funcs); + +#endif diff --git a/src/hash/hash-lib-glib.c b/src/hash/hash-lib-glib.c new file mode 100644 index 0000000..bcb2e71 --- /dev/null +++ b/src/hash/hash-lib-glib.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include +#include + +#include "hash-lib-glib.h" +#include "hash-lib.h" +#include "hash-func.h" + +#define LIB_DATA ((struct hash_lib_s *)func->priv.lib_data) + +struct hash_lib_s { + GChecksumType type; + GChecksum *checksum; +}; + +void gtkhash_hash_lib_glib_start(struct hash_func_s *func) +{ + func->priv.lib_data = g_new(struct hash_lib_s, 1); + + switch (func->id) { + case HASH_FUNC_MD5: + LIB_DATA->type = G_CHECKSUM_MD5; + break; + case HASH_FUNC_SHA1: + LIB_DATA->type = G_CHECKSUM_SHA1; + break; + case HASH_FUNC_SHA256: + LIB_DATA->type = G_CHECKSUM_SHA256; + break; + default: + g_assert_not_reached(); + } + + LIB_DATA->checksum = g_checksum_new(LIB_DATA->type); + g_assert(LIB_DATA->checksum); +} + +void gtkhash_hash_lib_glib_update(struct hash_func_s *func, + const uint8_t *buffer, const size_t size) +{ + g_checksum_update(LIB_DATA->checksum, buffer, size); +} + +void gtkhash_hash_lib_glib_stop(struct hash_func_s *func) +{ + g_checksum_free(LIB_DATA->checksum); + g_free(LIB_DATA); +} + +char *gtkhash_hash_lib_glib_finish(struct hash_func_s *func) +{ + char *digest = g_strdup(g_checksum_get_string(LIB_DATA->checksum)); + + g_checksum_free(LIB_DATA->checksum); + g_free(LIB_DATA); + + return digest; +} diff --git a/src/hash/hash-lib-glib.h b/src/hash/hash-lib-glib.h new file mode 100644 index 0000000..882c151 --- /dev/null +++ b/src/hash/hash-lib-glib.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_HASH_LIB_GLIB_H +#define GTKHASH_HASH_LIB_GLIB_H + +#ifndef IN_HASH_LIB + #error "don't use directly" +#endif + +#include +#include + +#include "hash-func.h" + +void gtkhash_hash_lib_glib_start(struct hash_func_s *func); +void gtkhash_hash_lib_glib_update(struct hash_func_s *func, + const uint8_t *buffer, const size_t size); +void gtkhash_hash_lib_glib_stop(struct hash_func_s *func); +char *gtkhash_hash_lib_glib_finish(struct hash_func_s *func); + +#endif diff --git a/src/hash/hash-lib-mhash.c b/src/hash/hash-lib-mhash.c new file mode 100644 index 0000000..9ab0358 --- /dev/null +++ b/src/hash/hash-lib-mhash.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "hash-lib-mhash.h" +#include "hash-lib.h" +#include "hash-func.h" + +#define LIB_DATA ((struct hash_lib_s *)func->priv.lib_data) + +struct hash_lib_s { + hashid type; + MHASH thread; +}; + +void gtkhash_hash_lib_mhash_start(struct hash_func_s *func) +{ + func->priv.lib_data = g_new(struct hash_lib_s, 1); + + switch (func->id) { + case HASH_FUNC_MD2: + LIB_DATA->type = MHASH_MD2; + break; + case HASH_FUNC_MD4: + LIB_DATA->type = MHASH_MD4; + break; + case HASH_FUNC_MD5: + LIB_DATA->type = MHASH_MD5; + break; + case HASH_FUNC_SHA1: + LIB_DATA->type = MHASH_SHA1; + break; + case HASH_FUNC_SHA224: + LIB_DATA->type = MHASH_SHA224; + break; + case HASH_FUNC_SHA256: + LIB_DATA->type = MHASH_SHA256; + break; + case HASH_FUNC_SHA384: + LIB_DATA->type = MHASH_SHA384; + break; + case HASH_FUNC_SHA512: + LIB_DATA->type = MHASH_SHA512; + break; + case HASH_FUNC_RIPEMD128: + LIB_DATA->type = MHASH_RIPEMD128; + break; + case HASH_FUNC_RIPEMD160: + LIB_DATA->type = MHASH_RIPEMD160; + break; + case HASH_FUNC_RIPEMD256: + LIB_DATA->type = MHASH_RIPEMD256; + break; + case HASH_FUNC_RIPEMD320: + LIB_DATA->type = MHASH_RIPEMD320; + break; + case HASH_FUNC_HAVAL128: + LIB_DATA->type = MHASH_HAVAL128; + break; + case HASH_FUNC_HAVAL160: + LIB_DATA->type = MHASH_HAVAL160; + break; + case HASH_FUNC_HAVAL192: + LIB_DATA->type = MHASH_HAVAL192; + break; + case HASH_FUNC_HAVAL224: + LIB_DATA->type = MHASH_HAVAL224; + break; + case HASH_FUNC_HAVAL256: + LIB_DATA->type = MHASH_HAVAL256; + break; + case HASH_FUNC_TIGER128: + LIB_DATA->type = MHASH_TIGER128; + break; + case HASH_FUNC_TIGER160: + LIB_DATA->type = MHASH_TIGER160; + break; + case HASH_FUNC_TIGER192: + LIB_DATA->type = MHASH_TIGER192; + break; + case HASH_FUNC_GOST: + LIB_DATA->type = MHASH_GOST; + break; + case HASH_FUNC_WHIRLPOOL: + LIB_DATA->type = MHASH_WHIRLPOOL; + break; + case HASH_FUNC_SNEFRU128: + LIB_DATA->type = MHASH_SNEFRU128; + break; + case HASH_FUNC_SNEFRU256: + LIB_DATA->type = MHASH_SNEFRU256; + break; + case HASH_FUNC_CRC32: + LIB_DATA->type = MHASH_CRC32; + break; + case HASH_FUNC_CRC32B: + LIB_DATA->type = MHASH_CRC32B; + break; + case HASH_FUNC_ADLER32: + LIB_DATA->type = MHASH_ADLER32; + break; + default: + g_assert_not_reached(); + } + + LIB_DATA->thread = mhash_init(LIB_DATA->type); + g_assert(LIB_DATA->thread != MHASH_FAILED); +} + +void gtkhash_hash_lib_mhash_update(struct hash_func_s *func, + const uint8_t *buffer, const size_t size) +{ + mhash(LIB_DATA->thread, buffer, size); +} + +void gtkhash_hash_lib_mhash_stop(struct hash_func_s *func) +{ + mhash_deinit(LIB_DATA->thread, NULL); + g_free(LIB_DATA); +} + +char *gtkhash_hash_lib_mhash_finish(struct hash_func_s *func) +{ + uint8_t *bin = mhash_end_m(LIB_DATA->thread, g_malloc); + GString *digest = g_string_sized_new(128); + + for (unsigned int i = 0; i < mhash_get_block_size(LIB_DATA->type); i++) + g_string_append_printf(digest, "%.2x", bin[i]); + + g_free(bin); + g_free(LIB_DATA); + + return g_string_free(digest, false); +} diff --git a/src/hash/hash-lib-mhash.h b/src/hash/hash-lib-mhash.h new file mode 100644 index 0000000..996c1a5 --- /dev/null +++ b/src/hash/hash-lib-mhash.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_HASH_LIB_MHASH_H +#define GTKHASH_HASH_LIB_MHASH_H + +#ifndef IN_HASH_LIB + #error "don't use directly" +#endif + +#include +#include + +#include "hash-func.h" + +void gtkhash_hash_lib_mhash_start(struct hash_func_s *func); +void gtkhash_hash_lib_mhash_update(struct hash_func_s *func, + const uint8_t *buffer, const size_t size); +void gtkhash_hash_lib_mhash_stop(struct hash_func_s *func); +char *gtkhash_hash_lib_mhash_finish(struct hash_func_s *func); + +#endif diff --git a/src/hash/hash-lib.c b/src/hash/hash-lib.c new file mode 100644 index 0000000..fb1a5df --- /dev/null +++ b/src/hash/hash-lib.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include + +#include "hash-lib.h" +#include "hash-func.h" +#include "hash-lib-mhash.h" +#include "hash-lib-glib.h" + +enum hash_lib_e { + HASH_LIB_GLIB = 0, + HASH_LIB_MHASH = 1 +}; + +static const enum hash_lib_e hash_libs[HASH_FUNCS_N] = { + [HASH_FUNC_MD2] = HASH_LIB_MHASH, + [HASH_FUNC_MD4] = HASH_LIB_MHASH, + [HASH_FUNC_MD5] = HASH_LIB_GLIB, + [HASH_FUNC_SHA1] = HASH_LIB_GLIB, + [HASH_FUNC_SHA224] = HASH_LIB_MHASH, + [HASH_FUNC_SHA256] = HASH_LIB_GLIB, + [HASH_FUNC_SHA384] = HASH_LIB_MHASH, + [HASH_FUNC_SHA512] = HASH_LIB_MHASH, + [HASH_FUNC_RIPEMD128] = HASH_LIB_MHASH, + [HASH_FUNC_RIPEMD160] = HASH_LIB_MHASH, + [HASH_FUNC_RIPEMD256] = HASH_LIB_MHASH, + [HASH_FUNC_RIPEMD320] = HASH_LIB_MHASH, + [HASH_FUNC_HAVAL128] = HASH_LIB_MHASH, + [HASH_FUNC_HAVAL160] = HASH_LIB_MHASH, + [HASH_FUNC_HAVAL192] = HASH_LIB_MHASH, + [HASH_FUNC_HAVAL224] = HASH_LIB_MHASH, + [HASH_FUNC_HAVAL256] = HASH_LIB_MHASH, + [HASH_FUNC_TIGER128] = HASH_LIB_MHASH, + [HASH_FUNC_TIGER160] = HASH_LIB_MHASH, + [HASH_FUNC_TIGER192] = HASH_LIB_MHASH, + [HASH_FUNC_GOST] = HASH_LIB_MHASH, + [HASH_FUNC_WHIRLPOOL] = HASH_LIB_MHASH, + [HASH_FUNC_SNEFRU128] = HASH_LIB_MHASH, + [HASH_FUNC_SNEFRU256] = HASH_LIB_MHASH, + [HASH_FUNC_CRC32] = HASH_LIB_MHASH, + [HASH_FUNC_CRC32B] = HASH_LIB_MHASH, + [HASH_FUNC_ADLER32] = HASH_LIB_MHASH +}; + +void gtkhash_hash_lib_start(struct hash_func_s *func) +{ + g_assert(func); + g_assert(func->enabled); + g_assert(!func->priv.lib_data); + + static void (* const start_funcs[])(struct hash_func_s *) = { + [HASH_LIB_GLIB] = gtkhash_hash_lib_glib_start, + [HASH_LIB_MHASH] = gtkhash_hash_lib_mhash_start + }; + + start_funcs[hash_libs[func->id]](func); +} + +void gtkhash_hash_lib_update(struct hash_func_s *func, const uint8_t *buffer, + const size_t size) +{ + g_assert(func); + g_assert(func->enabled); + g_assert(func->priv.lib_data); + g_assert(buffer); + + static void (* const update_funcs[])(struct hash_func_s *, + const uint8_t *, const size_t) = + { + [HASH_LIB_GLIB] = gtkhash_hash_lib_glib_update, + [HASH_LIB_MHASH] = gtkhash_hash_lib_mhash_update + }; + + update_funcs[hash_libs[func->id]](func, buffer, size); +} + +void gtkhash_hash_lib_stop(struct hash_func_s *func) +{ + g_assert(func); + g_assert(func->enabled); + g_assert(func->priv.lib_data); + + static void (* const stop_funcs[])(struct hash_func_s *) = { + [HASH_LIB_GLIB] = gtkhash_hash_lib_glib_stop, + [HASH_LIB_MHASH] = gtkhash_hash_lib_mhash_stop + }; + + stop_funcs[hash_libs[func->id]](func); + func->priv.lib_data = NULL; +} + +void gtkhash_hash_lib_finish(struct hash_func_s *func) +{ + g_assert(func); + g_assert(func->enabled); + g_assert(func->priv.lib_data); + + static char * (* const finish_libs[])(struct hash_func_s *) = { + [HASH_LIB_GLIB] = gtkhash_hash_lib_glib_finish, + [HASH_LIB_MHASH] = gtkhash_hash_lib_mhash_finish + }; + + char *digest = finish_libs[hash_libs[func->id]](func); + func->priv.lib_data = NULL; + + gtkhash_hash_func_set_digest(func, digest); +} diff --git a/src/hash/hash-lib.h b/src/hash/hash-lib.h new file mode 100644 index 0000000..7b371b1 --- /dev/null +++ b/src/hash/hash-lib.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_HASH_LIB_H +#define GTKHASH_HASH_LIB_H + +#ifndef IN_HASH_LIB + #error "don't use directly" +#endif + +#include +#include + +#include "hash-func.h" + +void gtkhash_hash_lib_start(struct hash_func_s *func); +void gtkhash_hash_lib_update(struct hash_func_s *func, const uint8_t *buffer, + const size_t size); +void gtkhash_hash_lib_stop(struct hash_func_s *func); +void gtkhash_hash_lib_finish(struct hash_func_s *func); + +#endif diff --git a/src/hash/hash-string.c b/src/hash/hash-string.c new file mode 100644 index 0000000..f4d2b0e --- /dev/null +++ b/src/hash/hash-string.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include +#include + +#include "hash-string.h" +#include "hash-func.h" +#include "hash-lib.h" + +void gtkhash_hash_string(struct hash_func_s *funcs, const char *str) +{ + g_assert(str); + + for (int i = 0; i < HASH_FUNCS_N; i++) { + if (!funcs[i].enabled) + continue; + gtkhash_hash_lib_start(&funcs[i]); + // Assuming this won't take too long + gtkhash_hash_lib_update(&funcs[i], (const uint8_t *)str, strlen(str)); + gtkhash_hash_lib_finish(&funcs[i]); + + const char *digest = gtkhash_hash_func_get_digest(&funcs[i]); + gtkhash_hash_string_finish_cb(funcs[i].id, digest); + } +} diff --git a/src/hash/hash-string.h b/src/hash/hash-string.h new file mode 100644 index 0000000..f48e430 --- /dev/null +++ b/src/hash/hash-string.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_HASH_STRING_H +#define GTKHASH_HASH_STRING_H + +#include "hash-func.h" + +void gtkhash_hash_string(struct hash_func_s *funcs, const char *str); + +void gtkhash_hash_string_finish_cb(const enum hash_func_e id, + const char *digest); + +#endif diff --git a/src/hash/mutils/Makefile.am b/src/hash/mutils/Makefile.am new file mode 100644 index 0000000..3cf69d3 --- /dev/null +++ b/src/hash/mutils/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = mhash_config.h diff --git a/src/hash/mutils/mhash_config.h b/src/hash/mutils/mhash_config.h new file mode 100644 index 0000000..fe1696e --- /dev/null +++ b/src/hash/mutils/mhash_config.h @@ -0,0 +1 @@ +// Try to prevent #include diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000..ef708b0 --- /dev/null +++ b/src/list.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "list.h" +#include "main.h" +#include "hash.h" +#include "gui.h" + +#define COL_N (COL_HASH + HASH_FUNCS_N) + +enum { + COL_FILE, + COL_HASH +}; + +void list_init(void) +{ + GType types[COL_N]; + + for (int i = 0; i < HASH_FUNCS_N; i++) { + gtk_tree_view_insert_column_with_attributes(gui.treeview, -1, + hash.funcs[i].name, gtk_cell_renderer_text_new(), + "text", COL_HASH + i, NULL); + } + + for (int i = 0; i < COL_N; i++) { + types[i] = G_TYPE_STRING; + GtkTreeViewColumn *col = gtk_tree_view_get_column(gui.treeview, i); + gtk_tree_view_column_set_resizable(col, true); + } + + gui.liststore = gtk_list_store_newv(COL_N, types); + gui.treemodel = GTK_TREE_MODEL(gui.liststore); + + gtk_tree_view_set_model(gui.treeview, gui.treemodel); +} + +void list_update(void) +{ + for (int i = 0; i < HASH_FUNCS_N; i++) { + GtkTreeViewColumn *col = gtk_tree_view_get_column(gui.treeview, + COL_HASH + i); + bool active = hash.funcs[i].enabled; + gtk_tree_view_column_set_visible(col, active); + } +} + +void list_append_row(const char *uri) +{ + g_assert(uri); + + GFile *file = g_file_new_for_uri(uri); + char *pname = g_file_get_parse_name(file); + g_object_unref(file); + + if (list_find_row(pname) >= 0) + return; + + gtk_list_store_insert_with_values(gui.liststore, NULL, G_MAXINT, + COL_FILE, pname, -1); + g_free(pname); + + gtk_widget_set_sensitive(GTK_WIDGET(gui.button_hash), true); + + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM( + gui.radiomenuitem_file_list), true); +} + +void list_remove_selection(void) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(gui.treeview); + GList *rows = gtk_tree_selection_get_selected_rows(selection, + &gui.treemodel); + + for (GList *i = rows; i != NULL; i = i->next) { + GtkTreePath *path = i->data; + GtkTreeRowReference *ref = gtk_tree_row_reference_new(gui.treemodel, + i->data); + i->data = ref; + gtk_tree_path_free(path); + } + + for (GList *i = rows; i != NULL; i = i->next) { + GtkTreeRowReference *ref = i->data; + GtkTreePath *path = gtk_tree_row_reference_get_path(ref); + GtkTreeIter iter; + + if (gtk_tree_model_get_iter(gui.treemodel, &iter, path)) + gtk_list_store_remove(gui.liststore, &iter); + + gtk_tree_path_free(path); + gtk_tree_row_reference_free(ref); + } + + g_list_free(rows); +} + +char *list_get_uri(const unsigned int row) +{ + g_assert(row <= list_count_rows()); + + GtkTreeIter iter; + GValue value; + value.g_type = 0; + + if (!gtk_tree_model_get_iter_first(gui.treemodel, &iter)) + return NULL; + + for (unsigned int i = 0; i < row; i++) + gtk_tree_model_iter_next(gui.treemodel, &iter); + + gtk_tree_model_get_value(gui.treemodel, &iter, COL_FILE, &value); + GFile *file = g_file_parse_name(g_value_get_string(&value)); + g_value_unset(&value); + + char *uri = g_file_get_uri(file); + g_object_unref(file); + + return uri; +} + +GSList *list_get_all_uris(void) +{ + GSList *uris = NULL; + + for (unsigned int i = 0; i < list_count_rows(); i++) { + char *uri = list_get_uri(i); + uris = g_slist_append(uris, uri); + } + + return uris; +} + +// Returns the row number with matching uri or -1 if not found +int list_find_row(const char *uri) +{ + g_assert(uri); + + GtkTreeIter iter; + + GFile *file = g_file_new_for_uri(uri); + char *pname = g_file_get_parse_name(file); + g_object_unref(file); + + if (gtk_tree_model_get_iter_first(gui.treemodel, &iter)) { + int row = 0; + do { + GValue value; + value.g_type = 0; + gtk_tree_model_get_value(gui.treemodel, &iter, COL_FILE, &value); + const char *string = g_value_get_string(&value); + + if (strcmp(string, pname) == 0) { + g_free(pname); + g_value_unset(&value); + return row; + } else { + g_value_unset(&value); + row++; + } + } while (gtk_tree_model_iter_next(gui.treemodel, &iter)); + } + + g_free(pname); + + return -1; +} + +unsigned int list_count_rows(void) +{ + GtkTreeIter iter; + unsigned int count = 0; + + if (gtk_tree_model_get_iter_first(gui.treemodel, &iter)) { + count++; + while(gtk_tree_model_iter_next(gui.treemodel, &iter)) + count++; + } + + return count; +} + +void list_set_digest(const char *uri, const int hash_func_id, + const char *digest) +{ + g_assert(uri); + g_assert(hash_func_id >= 0); + g_assert(hash_func_id < HASH_FUNCS_N); + + GtkTreeIter iter; + int row = list_find_row(uri); + g_assert (row >= 0); + + if (!gtk_tree_model_get_iter_first(gui.treemodel, &iter)) + return; + + for (int i = 0; i < row; i++) + gtk_tree_model_iter_next(gui.treemodel, &iter); + + gtk_list_store_set(gui.liststore, &iter, COL_HASH + hash_func_id, digest, + -1); +} + +char *list_get_digest(const unsigned int row, const int hash_func_id) +{ + g_assert(row <= list_count_rows()); + g_assert(hash_func_id >= 0); + g_assert(hash_func_id < HASH_FUNCS_N); + + GtkTreeIter iter; + char *digest; + GValue value; + value.g_type = 0; + + if (!gtk_tree_model_get_iter_first(gui.treemodel, &iter)) + return NULL; + + for (unsigned int i = 0; i < row; i++) + gtk_tree_model_iter_next(gui.treemodel, &iter); + + gtk_tree_model_get_value(gui.treemodel, &iter, COL_HASH + hash_func_id, + &value); + digest = g_strdup(g_value_get_string(&value)); + g_value_unset(&value); + + return digest; +} + +void list_clear_digests(void) +{ + GtkTreeIter iter; + + if (!gtk_tree_model_get_iter_first(gui.treemodel, &iter)) + return; + + do { + for (int i = 0; i < HASH_FUNCS_N; i++) + gtk_list_store_set(gui.liststore, &iter, COL_HASH + i, "", -1); + } while (gtk_tree_model_iter_next(gui.treemodel, &iter)); +} + +void list_clear(void) +{ + gtk_list_store_clear(gui.liststore); + gtk_widget_set_sensitive(GTK_WIDGET(gui.button_hash), false); +} diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000..585dbce --- /dev/null +++ b/src/list.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_LIST_H +#define GTKHASH_LIST_H + +void list_init(void); +void list_update(void); +void list_append_row(const char *uri); +void list_remove_selection(void); +char *list_get_uri(const unsigned int row); +GSList *list_get_all_uris(void); +int list_find_row(const char *path); +unsigned int list_count_rows(void); +void list_set_digest(const char *uri, const int hash_func_id, + const char *digest); +char *list_get_digest(const unsigned int row, const int hash_func_id); +void list_clear_digests(void); +void list_clear(void); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..3b4588c --- /dev/null +++ b/src/main.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include + +#include "main.h" +#include "hash.h" +#include "gui.h" +#include "list.h" +#include "prefs.h" + +static struct { + bool version; + char **files; +} opts = { + .version = false, + .files = NULL +}; + +static GOptionEntry entries[] = { + { + "version", 'v', 0, G_OPTION_ARG_NONE, &opts.version, + "Display version information", NULL + }, + { + G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opts.files, + NULL, NULL + }, + { NULL, 0, 0, 0, NULL, NULL, NULL } +}; + +static char *filename_arg_to_uri(const char *arg) +{ + GFile *file = g_file_new_for_commandline_arg(arg); + char *uri = g_file_get_uri(file); + g_object_unref(file); + + return uri; +} + +static void parse_opts(int *argc, char ***argv) +{ + GOptionContext *context = g_option_context_new(_("[FILE|URI...]")); + +#if ENABLE_NLS + g_option_context_add_main_entries(context, entries, PACKAGE); +#else + g_option_context_add_main_entries(context, entries, NULL); +#endif + + g_option_context_add_group(context, gtk_get_option_group(false)); + + if (!g_option_context_parse(context, argc, argv, NULL)) { + printf(_("Unknown option, try %s --help\n"), g_get_prgname()); + exit(EXIT_FAILURE); + } + + if (opts.version) { + printf("%s\n", PACKAGE_STRING); + exit(EXIT_SUCCESS); + } + + if (opts.files) { + if (!opts.files[1]) { + char *uri = filename_arg_to_uri(opts.files[0]); + gui_chooser_set_uri(uri); + g_free(uri); + } else { + for (int i = 0; opts.files[i]; i++) { + char *uri = filename_arg_to_uri(opts.files[i]); + list_append_row(uri); + g_free(uri); + } + } + } + + g_option_context_free(context); +} + +int main(int argc, char *argv[]) +{ +#if ENABLE_NLS + bindtextdomain(PACKAGE, LOCALEDIR); + bind_textdomain_codeset(PACKAGE, "UTF-8"); + textdomain(PACKAGE); +#endif + + g_thread_init(NULL); + gdk_threads_init(); + gdk_threads_enter(); + + gtk_init(&argc, &argv); + hash_init(); + gui_init(); + list_init(); + + prefs_load(); + + parse_opts(&argc, &argv); + + gui_run(); + + prefs_save(); + + gdk_threads_leave(); + + return EXIT_SUCCESS; +} diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..fa7dda0 --- /dev/null +++ b/src/main.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_MAIN_H +#define GTKHASH_MAIN_H + +#if ENABLE_NLS + #include +#else + #define _(X) (X) +#endif + +#endif diff --git a/src/nautilus/Makefile.am b/src/nautilus/Makefile.am new file mode 100644 index 0000000..2276303 --- /dev/null +++ b/src/nautilus/Makefile.am @@ -0,0 +1,22 @@ +nautilusdir = $(NAUTILUS_EXTENSION_DIR) +nautilus_LTLIBRARIES = libgtkhash-properties.la + +libgtkhash_properties_la_SOURCES = \ + properties.c properties.h \ + properties-hash.c properties-hash.h \ + properties-list.c properties-list.h \ + properties-prefs.c properties-prefs.h + +libgtkhash_properties_la_CPPFLAGS = \ + $(NAUTILUS_CFLAGS) $(GTK_CFLAGS) $(GCONF_CFLAGS) \ + -DBUILDER_XML="\"$(pkgdatadir)/nautilus/gtkhash-properties.xml\"" \ + -DLOCALEDIR="\"$(localedir)\"" + +libgtkhash_properties_la_LDFLAGS = \ + -avoid-version \ + -export-symbols-regex ^nautilus_module_ \ + -module \ + -shared + +libgtkhash_properties_la_LIBADD = \ + ../hash/hash.la $(NAUTILUS_LIBS) $(GTK_LIBS) $(GCONF_LIBS) diff --git a/src/nautilus/properties-hash.c b/src/nautilus/properties-hash.c new file mode 100644 index 0000000..8a215c9 --- /dev/null +++ b/src/nautilus/properties-hash.c @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include + +#include "properties.h" +#include "properties-hash.h" +#include "properties-list.h" +#include "../hash/hash-string.h" +#include "../hash/hash-file.h" + +void gtkhash_hash_string_finish_cb(G_GNUC_UNUSED const enum hash_func_e id, + G_GNUC_UNUSED const char *digest) +{ +} + +void gtkhash_hash_file_report_cb(void *data, goffset file_size, + goffset total_read, GTimer *timer) +{ + struct page_s *page = data; + + gtk_progress_bar_set_fraction(page->progressbar, + (double)total_read / + (double)file_size); + + if (total_read < FILE_BUFFER_SIZE * 3) + return; + + // Update progres bar text... + int remaining = g_timer_elapsed(timer, NULL) / + total_read * (file_size - total_read); + char *text; + if (remaining > 60) { + int minutes = remaining / 60; + if (minutes == 1) + text = g_strdup_printf(_("Estimated time remaining: 1 minute")); + else + text = g_strdup_printf(_("Estimated time remaining: %d minutes"), + minutes); + } else { + if (remaining == 1) + text = g_strdup_printf(_("Estimated time remaining: 1 second")); + else + text = g_strdup_printf(_("Estimated time remaining: %d seconds"), + remaining); + } + gtk_progress_bar_set_text(page->progressbar, text); + g_free(text); +} + +void gtkhash_hash_file_finish_cb(void *data) +{ + struct page_s *page = data; + + if (!gtkhash_hash_file_get_stop(&page->hash_file)) + gtkhash_properties_list_update_digests(page); + + gtkhash_properties_idle(page); +} + +void gtkhash_properties_hash_start(struct page_s *page) +{ + gtkhash_hash_file_set_stop(&page->hash_file, false); + gtkhash_hash_file_set_state(&page->hash_file, HASH_FILE_STATE_START); + gtkhash_hash_file_add_source(&page->hash_file); +} + +void gtkhash_properties_hash_stop(struct page_s *page) +{ + gtkhash_hash_file_set_stop(&page->hash_file, true); + + while (gtkhash_hash_file_get_state(&page->hash_file) != HASH_FILE_STATE_IDLE) + gtk_main_iteration_do(false); +} + +void gtkhash_properties_hash_init(struct page_s *page, const char *uri) +{ + gtkhash_hash_func_init_all(page->funcs); + gtkhash_hash_file_init(&page->hash_file, page->funcs, page); + gtkhash_hash_file_set_uri(&page->hash_file, uri); +} + +void gtkhash_properties_hash_deinit(struct page_s *page) +{ + gtkhash_hash_file_deinit(&page->hash_file); + gtkhash_hash_func_deinit_all(page->funcs); +} diff --git a/src/nautilus/properties-hash.h b/src/nautilus/properties-hash.h new file mode 100644 index 0000000..d288e59 --- /dev/null +++ b/src/nautilus/properties-hash.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_NAUTILUS_RROPERTIES_HASH_H +#define GTKHASH_NAUTILUS_PROPERTIES_HASH_H + +#include "properties.h" + +void gtkhash_properties_hash_start(struct page_s *page); +void gtkhash_properties_hash_stop(struct page_s *page); +void gtkhash_properties_hash_init(struct page_s *page, const char *uri); +void gtkhash_properties_hash_deinit(struct page_s *page); + +#endif diff --git a/src/nautilus/properties-list.c b/src/nautilus/properties-list.c new file mode 100644 index 0000000..9bd4c76 --- /dev/null +++ b/src/nautilus/properties-list.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include + +#include "properties.h" +#include "properties-list.h" +#include "properties-hash.h" +#include "../hash/hash-func.h" + +enum { + COL_ID, + COL_ENABLED, + COL_HASH_FUNC, + COL_DIGEST +}; + +static GtkTreeModelFilter *gtkhash_properties_list_get_filter( + struct page_s *page) +{ + return GTK_TREE_MODEL_FILTER(gtk_tree_view_get_model(page->treeview)); +} + +static GtkTreeModel *gtkhash_properties_list_get_model(struct page_s *page) +{ + GtkTreeModelFilter *filter = gtkhash_properties_list_get_filter(page); + return gtk_tree_model_filter_get_model(filter); +} + +static GtkListStore *gtkhash_properties_list_get_store(struct page_s *page) +{ + return GTK_LIST_STORE(gtkhash_properties_list_get_model(page)); +} + +int gtkhash_properties_list_get_row_id(struct page_s *page, const char *path) +{ + GtkTreeModel *model = gtkhash_properties_list_get_model(page); + GtkTreeIter iter; + int id; + + gtk_tree_model_get_iter_from_string(model, &iter, path); + gtk_tree_model_get(model, &iter, COL_ID, &id, -1); + + return id; +} + +void gtkhash_properties_list_update_enabled(struct page_s *page, const int id) +{ + GtkTreeModel *model = gtkhash_properties_list_get_model(page); + GtkListStore *store = gtkhash_properties_list_get_store(page); + GtkTreeIter iter; + + gtk_tree_model_iter_nth_child(model, &iter, NULL, id); + gtk_list_store_set(store, &iter, COL_ENABLED, + page->hash_file.funcs[id].enabled, -1); +} + +void gtkhash_properties_list_update_digests(struct page_s *page) +{ + GtkTreeModel *model = gtkhash_properties_list_get_model(page); + GtkListStore *store = gtkhash_properties_list_get_store(page); + GtkTreeIter iter; + + if (!gtk_tree_model_get_iter_first(model, &iter)) + return; + + do { + int i; + gtk_tree_model_get(model, &iter, COL_ID, &i, -1); + gtk_list_store_set(store, &iter, COL_DIGEST, + gtkhash_hash_func_get_digest(&page->hash_file.funcs[i]), -1); + } while (gtk_tree_model_iter_next(model, &iter)); + + gtk_tree_view_columns_autosize(page->treeview); +} + +char *gtkhash_properties_list_get_selected_digest(struct page_s *page) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(page->treeview); + + GtkTreeIter iter; + GtkTreeModel *model; + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return NULL; + + char *digest = NULL;; + gtk_tree_model_get(model, &iter, COL_DIGEST, &digest, -1); + + if (digest && *digest) + return digest; + else { + g_free(digest); + return NULL; + } +} + +void gtkhash_properties_list_refilter(struct page_s *page) +{ + GtkTreeModelFilter *filter = gtkhash_properties_list_get_filter(page); + gtk_tree_model_filter_refilter(filter); + + bool active = gtk_check_menu_item_get_active(page->menuitem_show_funcs); + GtkTreeViewColumn *col = gtk_tree_view_get_column(page->treeview, 0); + gtk_tree_view_column_set_visible(col, active); + + gtk_tree_view_columns_autosize(page->treeview); +} + +static bool gtkhash_properties_list_filter(GtkTreeModel *model, + GtkTreeIter *iter, struct page_s *page) +{ + gboolean enabled; + gtk_tree_model_get(model, iter, COL_ENABLED, &enabled, -1); + + if (!enabled && !gtk_check_menu_item_get_active(page->menuitem_show_funcs)) + return false; + + return true; +} + +void gtkhash_properties_list_init(struct page_s *page) +{ + GtkListStore *store = gtkhash_properties_list_get_store(page); + + for (int i = 0; i < HASH_FUNCS_N; i++) { + gtk_list_store_insert_with_values(store, NULL, i, + COL_ID, i, + COL_ENABLED, page->hash_file.funcs[i].enabled, + COL_HASH_FUNC, page->hash_file.funcs[i].name, + COL_DIGEST, gtkhash_hash_func_get_digest(&page->hash_file.funcs[i]), + -1); + } + + GtkTreeModelFilter *filter = gtkhash_properties_list_get_filter(page); + gtk_tree_model_filter_set_visible_func(filter, + (GtkTreeModelFilterVisibleFunc)gtkhash_properties_list_filter, page, + NULL); + + gtkhash_properties_list_refilter(page); +} diff --git a/src/nautilus/properties-list.h b/src/nautilus/properties-list.h new file mode 100644 index 0000000..a8d4cfc --- /dev/null +++ b/src/nautilus/properties-list.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_NAUTILUS_PROPERTIES_LIST_H +#define GTKHASH_NAUTILUS_PROPERTIES_LIST_H + +#include "properties.h" + +int gtkhash_properties_list_get_row_id(struct page_s *page, const char *path); +void gtkhash_properties_list_update_enabled(struct page_s *page, const int id); +void gtkhash_properties_list_update_digests(struct page_s *page); +char *gtkhash_properties_list_get_selected_digest(struct page_s *page); +void gtkhash_properties_list_refilter(struct page_s *page); +void gtkhash_properties_list_init(struct page_s *page); + +#endif diff --git a/src/nautilus/properties-prefs.c b/src/nautilus/properties-prefs.c new file mode 100644 index 0000000..adfe153 --- /dev/null +++ b/src/nautilus/properties-prefs.c @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "properties.h" +#include "properties-prefs.h" +#include "properties-hash.h" +#include "../hash/hash-func.h" + +#define KEY_HASH_FUNCTIONS "/apps/gtkhash/hash_functions" +#define KEY_SHOW_DISABLED_HASH_FUNCTIONS "/apps/gtkhash/show_disabled_hash_functions" + +static void gtkhash_properties_prefs_load_hash_functions(struct page_s *page, + GConfClient *client) +{ + GSList *list = gconf_client_get_list(client, KEY_HASH_FUNCTIONS, + GCONF_VALUE_STRING, NULL); + if (!list) + return; + + GSList *element = list; + do { + enum hash_func_e id = gtkhash_hash_func_get_id_from_name(element->data); + if (id != HASH_FUNC_INVALID) + page->hash_file.funcs[id].enabled = true; + g_free(element->data); + } while ((element = element->next)); + + g_slist_free(list); +} + +static void gtkhash_properties_prefs_load_show_disabled_hash_functions(struct page_s *page, + GConfClient *client) +{ + // Default to enabled + bool active = true; + + GError *error = NULL; + if (!gconf_client_get_bool(client, KEY_SHOW_DISABLED_HASH_FUNCTIONS, &error)) { + if (error) + g_error_free(error); + else + active = false; + } + + gtk_check_menu_item_set_active(page->menuitem_show_funcs, active); +} + +void gtkhash_properties_prefs_load(struct page_s *page) +{ + GConfClient *client = gconf_client_get_default(); + + gtkhash_properties_prefs_load_hash_functions(page, client); + gtkhash_properties_prefs_load_show_disabled_hash_functions(page, client); + + g_object_unref(client); +} + +static void gtkhash_properties_prefs_save_hash_functions(struct page_s *page, + GConfClient *client) +{ + GSList *list = NULL; + + for (int i = 0; i < HASH_FUNCS_N; i++) + if (page->hash_file.funcs[i].enabled) + list = g_slist_prepend(list, (void *)page->hash_file.funcs[i].name); + + if (list) { + gconf_client_set_list(client, KEY_HASH_FUNCTIONS, + GCONF_VALUE_STRING, list, NULL); + g_slist_free(list); + } +} + +static void gtkhash_properties_prefs_save_show_disabled_hash_functions(struct page_s *page, + GConfClient *client) +{ + bool active = gtk_check_menu_item_get_active(page->menuitem_show_funcs); + + gconf_client_set_bool(client, KEY_SHOW_DISABLED_HASH_FUNCTIONS, active, NULL); +} + +void gtkhash_properties_prefs_save(struct page_s *page) +{ + GConfClient *client = gconf_client_get_default(); + + gtkhash_properties_prefs_save_hash_functions(page, client); + gtkhash_properties_prefs_save_show_disabled_hash_functions(page, client); + + g_object_unref(client); +} diff --git a/src/nautilus/properties-prefs.h b/src/nautilus/properties-prefs.h new file mode 100644 index 0000000..020fb80 --- /dev/null +++ b/src/nautilus/properties-prefs.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_NAUTILUS_PROPERTIES_PREFS_H +#define GTKHASH_NAUTILUS_PROPERTIES_PREFS_H + +#include "properties.h" + +void gtkhash_properties_prefs_load(struct page_s *page); +void gtkhash_properties_prefs_save(struct page_s *page); + +#endif diff --git a/src/nautilus/properties.c b/src/nautilus/properties.c new file mode 100644 index 0000000..f59aeb5 --- /dev/null +++ b/src/nautilus/properties.c @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include +#include +#include +#include + +#include "properties.h" +#include "properties-list.h" +#include "properties-hash.h" +#include "properties-prefs.h" +#include "../hash/hash-func.h" +#include "../hash/hash-file.h" + +static GType page_type; + +static GObject *gtkhash_properties_get_object(GtkBuilder *builder, + const char *name) +{ + GObject *obj = gtk_builder_get_object(builder, name); + if (!obj) + g_warning("unknown object: \"%s\"", name); + + return obj; +} + +static void gtkhash_properties_busy(struct page_s *page) +{ + gtk_widget_set_sensitive(GTK_WIDGET(page->button_hash), false); + gtk_widget_set_sensitive(GTK_WIDGET(page->button_stop), true); + gtk_widget_set_sensitive(GTK_WIDGET(page->treeview), false); + + // Reset progress bar + gtk_progress_bar_set_fraction(page->progressbar, 0.0); + gtk_progress_bar_set_text(page->progressbar, " "); + gtk_widget_show(GTK_WIDGET(page->progressbar)); +} + +void gtkhash_properties_idle(struct page_s *page) +{ + gtk_widget_hide(GTK_WIDGET(page->progressbar)); + + gtk_widget_set_sensitive(GTK_WIDGET(page->treeview), true); + gtk_widget_set_sensitive(GTK_WIDGET(page->button_stop), false); + gtk_widget_set_sensitive(GTK_WIDGET(page->button_hash), true); +} + +static void gtkhash_properties_on_cell_toggled(struct page_s *page, char *path) +{ + int id = gtkhash_properties_list_get_row_id(page, path); + page->hash_file.funcs[id].enabled = !page->hash_file.funcs[id].enabled; + + gtkhash_properties_list_update_enabled(page, id); +} + +static void gtkhash_properties_on_treeview_popup_menu(struct page_s *page) +{ + gtk_menu_popup(page->menu, NULL, NULL, NULL, NULL, 0, + gtk_get_current_event_time()); +} + +static bool gtkhash_properties_on_treeview_button_press(struct page_s *page, + GdkEventButton *event) +{ + // Right click + if (event->type == GDK_BUTTON_PRESS && event->button == 3) { + gtk_menu_popup(page->menu, NULL, NULL, NULL, NULL, 3, + gdk_event_get_time((GdkEvent *)event)); + } + + return false; +} + +static void gtkhash_properties_on_treeview_cursor_changed(struct page_s *page) +{ + bool sensitive = false; + char *digest = gtkhash_properties_list_get_selected_digest(page); + if (digest) { + sensitive = true; + g_free(digest); + } + + gtk_widget_set_sensitive(GTK_WIDGET(page->menuitem_copy), sensitive); +} + +static void gtkhash_properties_on_menuitem_copy_activate(struct page_s *page) +{ + GtkClipboard *clipboard = gtk_clipboard_get(GDK_NONE); + char *digest = gtkhash_properties_list_get_selected_digest(page); + + gtk_clipboard_set_text(clipboard, digest, -1); + + g_free(digest); +} + +static void gtkhash_properties_on_menuitem_show_funcs_toggled( + struct page_s *page) +{ + gtkhash_properties_list_refilter(page); +} + +static void gtkhash_properties_on_button_hash_clicked(struct page_s *page) +{ + gtkhash_properties_busy(page); + gtkhash_hash_file_clear_digests(&page->hash_file); + gtkhash_properties_list_update_digests(page); + + gtkhash_properties_hash_start(page); +} + +static void gtkhash_properties_on_button_stop_clicked(struct page_s *page) +{ + gtk_widget_set_sensitive(GTK_WIDGET(page->button_stop), false); + gtkhash_properties_hash_stop(page); +} + +static void gtkhash_properties_free_page(struct page_s *page) +{ + gtkhash_properties_hash_stop(page); + gtkhash_properties_prefs_save(page); + gtkhash_properties_hash_deinit(page); + g_free(page->uri); + g_free(page); +} + +static void gtkhash_properties_get_objects(struct page_s *page, + GtkBuilder *builder) +{ + // Main container + page->box = GTK_WIDGET(gtkhash_properties_get_object(builder, "vbox")); + + // Progress bar + page->progressbar = GTK_PROGRESS_BAR(gtkhash_properties_get_object(builder, + "progressbar")); + + // Treeview + page->treeview = GTK_TREE_VIEW(gtkhash_properties_get_object(builder, + "treeview")); + page->cellrendtoggle = GTK_CELL_RENDERER_TOGGLE(gtkhash_properties_get_object(builder, + "cellrenderertoggle")); + + // Popup menu + page->menu = GTK_MENU(gtkhash_properties_get_object(builder, + "menu")); + page->menuitem_copy = GTK_IMAGE_MENU_ITEM(gtkhash_properties_get_object(builder, + "imagemenuitem_copy")); + page->menuitem_show_funcs = GTK_CHECK_MENU_ITEM(gtkhash_properties_get_object(builder, + "checkmenuitem_show_funcs")); + + // Buttons + page->button_hash = GTK_BUTTON(gtkhash_properties_get_object(builder, + "button_hash")); + page->button_stop = GTK_BUTTON(gtkhash_properties_get_object(builder, + "button_stop")); +} + +static void gtkhash_properties_connect_signals(struct page_s *page) +{ + // Main container + g_signal_connect_swapped(page->box, "destroy", + G_CALLBACK(gtkhash_properties_free_page), page); + + // Treeview + g_signal_connect_swapped(page->cellrendtoggle, "toggled", + G_CALLBACK(gtkhash_properties_on_cell_toggled), page); + g_signal_connect_swapped(page->treeview, "popup-menu", + G_CALLBACK(gtkhash_properties_on_treeview_popup_menu), page); + g_signal_connect_swapped(page->treeview, "button-press-event", + G_CALLBACK(gtkhash_properties_on_treeview_button_press), page); + g_signal_connect_swapped(page->treeview, "cursor-changed", + G_CALLBACK(gtkhash_properties_on_treeview_cursor_changed), page); + + // Popup menu + g_signal_connect_swapped(page->menuitem_copy, "activate", + G_CALLBACK(gtkhash_properties_on_menuitem_copy_activate), page); + g_signal_connect_swapped(page->menuitem_show_funcs, "toggled", + G_CALLBACK(gtkhash_properties_on_menuitem_show_funcs_toggled), page); + + // Buttons + g_signal_connect_swapped(page->button_hash, "clicked", + G_CALLBACK(gtkhash_properties_on_button_hash_clicked), page); + g_signal_connect_swapped(page->button_stop, "clicked", + G_CALLBACK(gtkhash_properties_on_button_stop_clicked), page); +} + +static struct page_s *gtkhash_properties_new_page(char *uri) +{ + GtkBuilder *builder = gtk_builder_new(); + +#if ENABLE_NLS + gtk_builder_set_translation_domain(builder, PACKAGE); +#endif + + if (!gtk_builder_add_from_file(builder, BUILDER_XML, NULL)) { + g_warning("failed to read %s", BUILDER_XML); + return NULL; + } + + struct page_s *page = g_new(struct page_s, 1); + + page->uri = uri; + + gtkhash_properties_get_objects(page, builder); + g_object_ref(page->box); + g_object_ref(page->menu); + g_object_unref(builder); + + gtkhash_properties_hash_init(page, uri); + gtkhash_properties_prefs_load(page); + gtkhash_properties_list_init(page); + gtkhash_properties_idle(page); + + gtkhash_properties_connect_signals(page); + + return page; +} + +static GList *gtkhash_properties_get_pages( + G_GNUC_UNUSED NautilusPropertyPageProvider *provider, GList *files) +{ + // Only display page for a single file + if (!files || files->next) + return NULL; + + // Only display page for regular files + if (nautilus_file_info_get_file_type(files->data) != G_FILE_TYPE_REGULAR) + return NULL; + + char *uri = nautilus_file_info_get_uri(files->data); + struct page_s *page = gtkhash_properties_new_page(uri); + if (!page) + return NULL; + + NautilusPropertyPage *ppage = nautilus_property_page_new( + "GtkHash::properties", gtk_label_new(_("Digests")), page->box); + + GList *pages = g_list_append(NULL, ppage); + + return pages; +} + +static void gtkhash_properties_iface_init(NautilusPropertyPageProviderIface *iface) +{ + iface->get_pages = gtkhash_properties_get_pages; +} + +static void gtkhash_properties_register_type(GTypeModule *module) +{ + const GTypeInfo info = { + sizeof(GObjectClass), + (GBaseInitFunc)NULL, + (GBaseFinalizeFunc)NULL, + (GClassInitFunc)NULL, + (GClassFinalizeFunc)NULL, + NULL, + sizeof(GObject), + 0, + (GInstanceInitFunc)NULL, + (GTypeValueTable *)NULL + }; + + page_type = g_type_module_register_type(module, G_TYPE_OBJECT, + "GtkHash", &info, 0); + + const GInterfaceInfo iface_info = { + (GInterfaceInitFunc)gtkhash_properties_iface_init, + (GInterfaceFinalizeFunc)NULL, + NULL + }; + + g_type_module_add_interface(module, page_type, + NAUTILUS_TYPE_PROPERTY_PAGE_PROVIDER, &iface_info); +} + +void nautilus_module_initialize(GTypeModule *module) +{ + gtkhash_properties_register_type(module); + +#if ENABLE_NLS + bindtextdomain(PACKAGE, LOCALEDIR); + bind_textdomain_codeset(PACKAGE, "UTF-8"); +#endif +} + +void nautilus_module_shutdown(void) +{ +} + +void nautilus_module_list_types(const GType **types, int *num_types) +{ + static GType type_list[1]; + + type_list[0] = page_type; + *types = type_list; + *num_types = G_N_ELEMENTS(type_list); +} diff --git a/src/nautilus/properties.h b/src/nautilus/properties.h new file mode 100644 index 0000000..d14970f --- /dev/null +++ b/src/nautilus/properties.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_NAUTILUS_PROPERTIES_H +#define GTKHASH_NAUTILUS_PROPERTIES_H + +#include + +#include "../hash/hash-file.h" + +#if ENABLE_NLS + #include +#else + #define _(X) (X) +#endif + +struct page_s { + char *uri; + GtkWidget *box; + GtkProgressBar *progressbar; + GtkTreeView *treeview; + GtkCellRendererToggle *cellrendtoggle; + GtkMenu *menu; + GtkImageMenuItem *menuitem_copy; + GtkCheckMenuItem *menuitem_show_funcs; + GtkButton *button_hash, *button_stop; + struct hash_func_s funcs[HASH_FUNCS_N]; + struct hash_file_s hash_file; +}; + +void gtkhash_properties_idle(struct page_s *page); + +#endif diff --git a/src/prefs.c b/src/prefs.c new file mode 100644 index 0000000..46adbf6 --- /dev/null +++ b/src/prefs.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifdef HAVE_CONFIG_H + #include "config.h" +#endif + +#include +#include +#include + +#include "prefs.h" +#include "main.h" +#include "hash.h" +#include "gui.h" + +static void load_hash_funcs(GKeyFile *keyfile) +{ + for (int i = 0; i < HASH_FUNCS_N; i++) { + GError *error = NULL; + bool active = g_key_file_get_boolean(keyfile, "hash-funcs", hash.funcs[i].name, &error); + + if (!error) { + hash.funcs[i].enabled = active; + gtk_toggle_button_set_active(gui.hash_widgets[i].button, active); + } else + g_error_free(error); // Ignore the error + } +} + +static void load_view(GKeyFile *keyfile) +{ + GError *error = NULL; + int view = g_key_file_get_integer(keyfile, "window", "view", &error); + + if (error) { + g_error_free(error); + return; + } + + switch (view) { + case VIEW_FILE: + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM( + gui.radiomenuitem_file), true); + break; + case VIEW_TEXT: + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM( + gui.radiomenuitem_text), true); + break; + case VIEW_FILE_LIST: + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM( + gui.radiomenuitem_file_list), true); + break; + default: + g_assert_not_reached(); + } +} + +static void load_window_size(GKeyFile *keyfile) +{ + GError *error = NULL; + int width, height; + + width = g_key_file_get_integer(keyfile, "window", "width", &error); + if (error) { + g_error_free(error); + error = NULL; + } + + height = g_key_file_get_integer(keyfile, "window", "height", &error); + if (error) { + g_error_free(error); + error = NULL; + } + + prefs.width = width; + prefs.height = height; +} + +void prefs_load(void) +{ + GKeyFile *keyfile = g_key_file_new(); + char *filename = g_build_filename(g_get_user_config_dir(), PACKAGE, NULL); + + if (g_key_file_load_from_file(keyfile, filename, G_KEY_FILE_NONE, NULL)) { + load_hash_funcs(keyfile); + load_view(keyfile); + load_window_size(keyfile); + } + + g_free(filename); + g_key_file_free(keyfile); + + gui_update(); +} + +static void save_hash_funcs(GKeyFile *keyfile) +{ + for (int i = 0; i < HASH_FUNCS_N; i++) + g_key_file_set_boolean(keyfile, "hash-funcs", hash.funcs[i].name, + hash.funcs[i].enabled); +} + +static void save_view(GKeyFile *keyfile) +{ + g_key_file_set_integer(keyfile, "window", "view", gui_get_view()); +} + +static void save_window_size(GKeyFile *keyfile) +{ + g_key_file_set_integer(keyfile, "window", "width", prefs.width); + g_key_file_set_integer(keyfile, "window", "height", prefs.height); +} + +void prefs_save(void) +{ + GKeyFile *keyfile = g_key_file_new(); + char *filename = g_build_filename(g_get_user_config_dir(), PACKAGE, NULL); + char *data; + + save_hash_funcs(keyfile); + save_view(keyfile); + save_window_size(keyfile); + + data = g_key_file_to_data(keyfile, NULL, NULL); + g_file_set_contents(filename, data, -1, NULL); + + g_free(data); + g_free(filename); + g_key_file_free(keyfile); +} diff --git a/src/prefs.h b/src/prefs.h new file mode 100644 index 0000000..bce6be2 --- /dev/null +++ b/src/prefs.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2007-2010 Tristan Heaven + * + * This file is part of GtkHash. + * + * GtkHash is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * GtkHash is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GtkHash. If not, see . + */ + +#ifndef GTKHASH_PREFS_H +#define GTKHASH_PREFS_H + +struct { + int width, height; // Window size +} prefs; + +void prefs_load(void); +void prefs_save(void); + +#endif