Initial checkin
authorWerner Koch <wk@gnupg.org>
Fri, 18 Jun 2010 05:23:43 +0000 (07:23 +0200)
committerWerner Koch <wk@gnupg.org>
Fri, 18 Jun 2010 05:23:43 +0000 (07:23 +0200)
32 files changed:
AUTHORS [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
README~ [new file with mode: 0644]
THANKS [new file with mode: 0644]
assuan-buffer.c [new file with mode: 0644]
assuan-defs.h [new file with mode: 0644]
assuan-errors.c [new file with mode: 0644]
assuan-handler.c [new file with mode: 0644]
assuan-listen.c [new file with mode: 0644]
assuan-pipe-server.c [new file with mode: 0644]
assuan-util.c [new file with mode: 0644]
assuan.h [new file with mode: 0644]
config.h [new file with mode: 0644]
config.h.in [new file with mode: 0644]
document-encrypt.png [new file with mode: 0644]
getopt.c [new file with mode: 0644]
getopt.h [new file with mode: 0644]
main.cpp [new file with mode: 0644]
memory.h [new file with mode: 0644]
pinentry.c [new file with mode: 0644]
pinentry.h [new file with mode: 0644]
pinentrydialog.cpp [new file with mode: 0644]
pinentrydialog.h [new file with mode: 0644]
pinentrydialog.moc [new file with mode: 0644]
qrc_pinentry.cpp [new file with mode: 0644]
secmem-util.c [new file with mode: 0644]
secmem-util.h [new file with mode: 0644]
secmem.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..a55491a
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,10 @@
+Program: Pinentry
+Bug reports: <gnupg-devel@gnupg.org>
+Security related bug reports: <security@gnupg.org>
+License: GPLv2+
+
+Robert Bihlmeyer <robbe@orcus.priv.at>
+Werner Koch, g10 Code GmbH <wk@gnupg.org>
+Steffen Hansen, Klarälvdalens Datakonsult AB <steffen@klaralvdalens-datakonsult.se>
+Marcus Brinkmann, g10 Code GmbH <marcus@g10code.com>
+Timo Schulz, g10 Code GmbH
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..8552d27
--- /dev/null
@@ -0,0 +1,76 @@
+project(pinentry-qt)
+cmake_minimum_required(VERSION 2.6.0)
+
+set(PINENTRY_QT_VERSION_MAJOR "0")
+set(PINENTRY_QT_VERSION_MINOR "8")
+set(PINENTRY_QT_VERSION_PATCH "1")
+
+set(PINENTRY_QT_VERSION "${PINENTRY_QT_VERSION_MAJOR}.${PINENTRY_QT_VERSION_MINOR}.${PINENTRY_QT_VERSION_PATCH}")
+
+add_definitions(-DVERSION="${PINENTRY_QT_VERSION}")
+
+# Checks
+find_package(Qt4 REQUIRED)
+
+include(CheckIncludeFiles)
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+add_definitions(-DHAVE_CONFIG_H=1)
+
+if(WIN32)
+add_definitions(-DHAVE_W32_SYSTEM=1)
+add_definitions(-DHAVE_DOSISH_SYSTEM=1)
+endif(WIN32)
+if(WINCE)
+add_definitions(-DHAVE_W32CE_SYSTEM=1)
+endif(WINCE)
+
+# Build rules
+#   set(QT_USE_OPENGL TRUE)
+include(${QT_USE_FILE})
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+
+set(pinentry_qt_SRCS
+    qrc_pinentry.cpp   
+    pinentrydialog.cpp
+    main.cpp
+    assuan-buffer.c
+    assuan-defs.h
+    assuan-errors.c
+    assuan.h
+    assuan-handler.c
+    assuan-listen.c
+    assuan-pipe-server.c
+    assuan-util.c
+    memory.h
+    secmem-util.h
+    secmem-util.c
+    secmem.c
+    pinentry.c
+    getopt.h
+    getopt.c
+)
+
+# Automatically figure out moc files.
+qt4_automoc(${qtproject_SRCS})
+
+add_executable(pinentry-qt ${pinentry_qt_SRCS})
+target_link_libraries(pinentry-qt ${QT_LIBRARIES})
+
+install(TARGETS pinentry-qt DESTINATION bin)
+
+
+# Packaging
+set(CPACK_PACKAGE_VENDOR "g10 Code GmbH")
+set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Pinentry Qt4")
+set(CPACK_PACKAGE_VERSION_MAJOR ${PINENTRY_QT_VERSION_MAJOR})
+set(CPACK_PACKAGE_VERSION_MINOR ${PINENTRY_QT_VERSION_MINOR})
+set(CPACK_PACKAGE_VERSION_PATCH ${PINENTRY_QT_VERSION_PATCH})
+if (APPLE)
+#  set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/cpack/README.txt")
+#  set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/cpack/LICENSE.txt")
+  set(CPACK_SET_DESTDIR ON)
+  set(CPACK_PACKAGE_RELOCATABLE OFF)
+endif (APPLE)
+  
+include(CPack)
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..c7aea18
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,280 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..5079adb
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,5 @@
+2010-05-21  Marcus Brinkmann  <marcus@g10code.de>
+
+       * Initial release, based on pinentry SVN 2010-05-21.
+
+
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..4074e6a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,394 @@
+# CMAKE generated file: DO NOT EDIT!
+# Generated by "Unix Makefiles" Generator, CMake Version 2.8
+
+# Default target executed when no arguments are given to make.
+default_target: all
+.PHONY : default_target
+
+#=============================================================================
+# Special targets provided by cmake.
+
+# Disable implicit rules so canoncical targets will work.
+.SUFFIXES:
+
+# Remove some rules from gmake that .SUFFIXES does not remove.
+SUFFIXES =
+
+.SUFFIXES: .hpux_make_needs_suffix_list
+
+# Suppress display of executed commands.
+$(VERBOSE).SILENT:
+
+# A target that is always out of date.
+cmake_force:
+.PHONY : cmake_force
+
+#=============================================================================
+# Set environment variables for the build.
+
+# The shell in which to execute make rules.
+SHELL = /bin/sh
+
+# The CMake executable.
+CMAKE_COMMAND = /usr/bin/cmake
+
+# The command to remove a file.
+RM = /usr/bin/cmake -E remove -f
+
+# The top-level source directory on which CMake was run.
+CMAKE_SOURCE_DIR = /home/marcus/g10/projects/komo3/cmake/pinentry-qt
+
+# The top-level build directory on which CMake was run.
+CMAKE_BINARY_DIR = /home/marcus/g10/projects/komo3/cmake/pinentry-qt
+
+#=============================================================================
+# Targets provided globally by CMake.
+
+# Special rule for the target edit_cache
+edit_cache:
+       @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running interactive CMake command-line interface..."
+       /usr/bin/cmake -i .
+.PHONY : edit_cache
+
+# Special rule for the target edit_cache
+edit_cache/fast: edit_cache
+.PHONY : edit_cache/fast
+
+# Special rule for the target install
+install: preinstall
+       @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
+       /usr/bin/cmake -P cmake_install.cmake
+.PHONY : install
+
+# Special rule for the target install
+install/fast: preinstall/fast
+       @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..."
+       /usr/bin/cmake -P cmake_install.cmake
+.PHONY : install/fast
+
+# Special rule for the target install/local
+install/local: preinstall
+       @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..."
+       /usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake
+.PHONY : install/local
+
+# Special rule for the target install/local
+install/local/fast: install/local
+.PHONY : install/local/fast
+
+# Special rule for the target install/strip
+install/strip: preinstall
+       @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..."
+       /usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake
+.PHONY : install/strip
+
+# Special rule for the target install/strip
+install/strip/fast: install/strip
+.PHONY : install/strip/fast
+
+# Special rule for the target list_install_components
+list_install_components:
+       @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\""
+.PHONY : list_install_components
+
+# Special rule for the target list_install_components
+list_install_components/fast: list_install_components
+.PHONY : list_install_components/fast
+
+# Special rule for the target rebuild_cache
+rebuild_cache:
+       @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
+       /usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
+.PHONY : rebuild_cache
+
+# Special rule for the target rebuild_cache
+rebuild_cache/fast: rebuild_cache
+.PHONY : rebuild_cache/fast
+
+# The main all target
+all: cmake_check_build_system
+       $(CMAKE_COMMAND) -E cmake_progress_start /home/marcus/g10/projects/komo3/cmake/pinentry-qt/CMakeFiles /home/marcus/g10/projects/komo3/cmake/pinentry-qt/CMakeFiles/progress.marks
+       $(MAKE) -f CMakeFiles/Makefile2 all
+       $(CMAKE_COMMAND) -E cmake_progress_start /home/marcus/g10/projects/komo3/cmake/pinentry-qt/CMakeFiles 0
+.PHONY : all
+
+# The main clean target
+clean:
+       $(MAKE) -f CMakeFiles/Makefile2 clean
+.PHONY : clean
+
+# The main clean target
+clean/fast: clean
+.PHONY : clean/fast
+
+# Prepare targets for installation.
+preinstall: all
+       $(MAKE) -f CMakeFiles/Makefile2 preinstall
+.PHONY : preinstall
+
+# Prepare targets for installation.
+preinstall/fast:
+       $(MAKE) -f CMakeFiles/Makefile2 preinstall
+.PHONY : preinstall/fast
+
+# clear depends
+depend:
+       $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
+.PHONY : depend
+
+#=============================================================================
+# Target rules for targets named pinentry-qt
+
+# Build rule for target.
+pinentry-qt: cmake_check_build_system
+       $(MAKE) -f CMakeFiles/Makefile2 pinentry-qt
+.PHONY : pinentry-qt
+
+# fast build rule for target.
+pinentry-qt/fast:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/build
+.PHONY : pinentry-qt/fast
+
+# target to build an object file
+assuan-buffer.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-buffer.o
+.PHONY : assuan-buffer.o
+
+# target to preprocess a source file
+assuan-buffer.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-buffer.i
+.PHONY : assuan-buffer.i
+
+# target to generate assembly for a file
+assuan-buffer.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-buffer.s
+.PHONY : assuan-buffer.s
+
+# target to build an object file
+assuan-errors.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-errors.o
+.PHONY : assuan-errors.o
+
+# target to preprocess a source file
+assuan-errors.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-errors.i
+.PHONY : assuan-errors.i
+
+# target to generate assembly for a file
+assuan-errors.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-errors.s
+.PHONY : assuan-errors.s
+
+# target to build an object file
+assuan-handler.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-handler.o
+.PHONY : assuan-handler.o
+
+# target to preprocess a source file
+assuan-handler.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-handler.i
+.PHONY : assuan-handler.i
+
+# target to generate assembly for a file
+assuan-handler.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-handler.s
+.PHONY : assuan-handler.s
+
+# target to build an object file
+assuan-listen.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-listen.o
+.PHONY : assuan-listen.o
+
+# target to preprocess a source file
+assuan-listen.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-listen.i
+.PHONY : assuan-listen.i
+
+# target to generate assembly for a file
+assuan-listen.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-listen.s
+.PHONY : assuan-listen.s
+
+# target to build an object file
+assuan-pipe-server.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-pipe-server.o
+.PHONY : assuan-pipe-server.o
+
+# target to preprocess a source file
+assuan-pipe-server.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-pipe-server.i
+.PHONY : assuan-pipe-server.i
+
+# target to generate assembly for a file
+assuan-pipe-server.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-pipe-server.s
+.PHONY : assuan-pipe-server.s
+
+# target to build an object file
+assuan-util.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-util.o
+.PHONY : assuan-util.o
+
+# target to preprocess a source file
+assuan-util.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-util.i
+.PHONY : assuan-util.i
+
+# target to generate assembly for a file
+assuan-util.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/assuan-util.s
+.PHONY : assuan-util.s
+
+# target to build an object file
+main.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/main.o
+.PHONY : main.o
+
+# target to preprocess a source file
+main.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/main.i
+.PHONY : main.i
+
+# target to generate assembly for a file
+main.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/main.s
+.PHONY : main.s
+
+# target to build an object file
+pinentry.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/pinentry.o
+.PHONY : pinentry.o
+
+# target to preprocess a source file
+pinentry.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/pinentry.i
+.PHONY : pinentry.i
+
+# target to generate assembly for a file
+pinentry.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/pinentry.s
+.PHONY : pinentry.s
+
+# target to build an object file
+pinentrydialog.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/pinentrydialog.o
+.PHONY : pinentrydialog.o
+
+# target to preprocess a source file
+pinentrydialog.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/pinentrydialog.i
+.PHONY : pinentrydialog.i
+
+# target to generate assembly for a file
+pinentrydialog.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/pinentrydialog.s
+.PHONY : pinentrydialog.s
+
+# target to build an object file
+qrc_pinentry.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/qrc_pinentry.o
+.PHONY : qrc_pinentry.o
+
+# target to preprocess a source file
+qrc_pinentry.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/qrc_pinentry.i
+.PHONY : qrc_pinentry.i
+
+# target to generate assembly for a file
+qrc_pinentry.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/qrc_pinentry.s
+.PHONY : qrc_pinentry.s
+
+# target to build an object file
+secmem-util.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/secmem-util.o
+.PHONY : secmem-util.o
+
+# target to preprocess a source file
+secmem-util.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/secmem-util.i
+.PHONY : secmem-util.i
+
+# target to generate assembly for a file
+secmem-util.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/secmem-util.s
+.PHONY : secmem-util.s
+
+# target to build an object file
+secmem.o:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/secmem.o
+.PHONY : secmem.o
+
+# target to preprocess a source file
+secmem.i:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/secmem.i
+.PHONY : secmem.i
+
+# target to generate assembly for a file
+secmem.s:
+       $(MAKE) -f CMakeFiles/pinentry-qt.dir/build.make CMakeFiles/pinentry-qt.dir/secmem.s
+.PHONY : secmem.s
+
+# Help Target
+help:
+       @echo "The following are some of the valid targets for this Makefile:"
+       @echo "... all (the default if no target is provided)"
+       @echo "... clean"
+       @echo "... depend"
+       @echo "... edit_cache"
+       @echo "... install"
+       @echo "... install/local"
+       @echo "... install/strip"
+       @echo "... list_install_components"
+       @echo "... pinentry-qt"
+       @echo "... rebuild_cache"
+       @echo "... assuan-buffer.o"
+       @echo "... assuan-buffer.i"
+       @echo "... assuan-buffer.s"
+       @echo "... assuan-errors.o"
+       @echo "... assuan-errors.i"
+       @echo "... assuan-errors.s"
+       @echo "... assuan-handler.o"
+       @echo "... assuan-handler.i"
+       @echo "... assuan-handler.s"
+       @echo "... assuan-listen.o"
+       @echo "... assuan-listen.i"
+       @echo "... assuan-listen.s"
+       @echo "... assuan-pipe-server.o"
+       @echo "... assuan-pipe-server.i"
+       @echo "... assuan-pipe-server.s"
+       @echo "... assuan-util.o"
+       @echo "... assuan-util.i"
+       @echo "... assuan-util.s"
+       @echo "... main.o"
+       @echo "... main.i"
+       @echo "... main.s"
+       @echo "... pinentry.o"
+       @echo "... pinentry.i"
+       @echo "... pinentry.s"
+       @echo "... pinentrydialog.o"
+       @echo "... pinentrydialog.i"
+       @echo "... pinentrydialog.s"
+       @echo "... qrc_pinentry.o"
+       @echo "... qrc_pinentry.i"
+       @echo "... qrc_pinentry.s"
+       @echo "... secmem-util.o"
+       @echo "... secmem-util.i"
+       @echo "... secmem-util.s"
+       @echo "... secmem.o"
+       @echo "... secmem.i"
+       @echo "... secmem.s"
+.PHONY : help
+
+
+
+#=============================================================================
+# Special targets to cleanup operation of make.
+
+# Special rule to run CMake to check the build system integrity.
+# No rule that depends on this can have commands that come from listfiles
+# because they might be regenerated.
+cmake_check_build_system:
+       $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
+.PHONY : cmake_check_build_system
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..0875ad8
--- /dev/null
+++ b/README
@@ -0,0 +1,14 @@
+PIN Entry for QT
+----------------
+
+This is a stand alone version of the qt4 pinentry from the pinentry package.
+It does not use a secure line edit widget though, thereby decreasing security
+a bit but increasing compatibility with customized environments like found
+on mobile devices.  It also builds with cmake instead of autotools.  It does
+not feature a curses fallback either.
+
+Some of the code is taken from Robert Bihlmeyer's Quintuple-Agent.
+For security reasons, all internationalization has been removed.  The
+client is expected to tell the PIN entry the text strings to be
+displayed.
+
diff --git a/README~ b/README~
new file mode 100644 (file)
index 0000000..6290658
--- /dev/null
+++ b/README~
@@ -0,0 +1,14 @@
+PIN Entry
+---------
+
+This is a stand alone version of the qt4 pinentry from the pinentry package.
+It does not use a secure line edit widget though, thereby decreasing security
+a bit but increasing compatibility with customized environments like found
+on mobile devices.  It also builds with cmake instead of autotools.  It does
+not feature a curses fallback either.
+
+Some of the code is taken from Robert Bihlmeyer's Quintuple-Agent.
+For security reasons, all internationalization has been removed.  The
+client is expected to tell the PIN entry the text strings to be
+displayed.
+
diff --git a/THANKS b/THANKS
new file mode 100644 (file)
index 0000000..90fce79
--- /dev/null
+++ b/THANKS
@@ -0,0 +1,7 @@
+Alon Bar-Lev            alon.barlev@gmail.com
+Albrecht Dress         albrecht.dress@arcor.de
+Alexander Zangerl       az at snafu.priv.at
+Michael Nottebrock      michaelnottebrock at gmx.net
+Peter Eisentraut       peter_e@gmx.net
+Tobias Koenig          tokoe@kde.org
+Ed Marten               edman007x at mac com
diff --git a/assuan-buffer.c b/assuan-buffer.c
new file mode 100644 (file)
index 0000000..40fd8ce
--- /dev/null
@@ -0,0 +1,476 @@
+/* assuan-buffer.c - read and send data
+ *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#ifndef HAVE_W32CE_SYSTEM
+# include <errno.h>
+# include <unistd.h>
+#endif
+#include <assert.h>
+#ifdef USE_GNU_PTH
+# include <pth.h>
+#endif
+#ifdef HAVE_W32CE_SYSTEM
+# include <windows.h>
+#endif
+
+#include "assuan-defs.h"
+
+#ifdef HAVE_JNLIB_LOGGING
+#include "../jnlib/logging.h"
+#endif
+
+#ifdef HAVE_W32CE_SYSTEM
+const char *
+strerror (int e)
+{
+  return "error";
+}
+static int errno;
+#endif
+
+
+static const char *
+my_log_prefix (void)
+{
+#ifdef HAVE_JNLIB_LOGGING
+  return log_get_prefix (NULL);
+#else
+  return "";
+#endif
+}
+
+
+static int
+writen ( int fd, const char *buffer, size_t length )
+{
+  while (length)
+    {
+      int nwritten;
+#ifdef HAVE_W32CE_SYSTEM
+      do 
+        {
+          if (!WriteFile ((HANDLE)fd, buffer, length, &nwritten, NULL))
+            nwritten = -1;
+        }
+      while (nwritten == -1 && GetLastError () == ERROR_PIPE_NOT_CONNECTED);
+#elif defined(USE_GNU_PTH)
+      nwritten = pth_write (fd, buffer, length);
+#else
+      nwritten = write (fd, buffer, length);
+#endif
+      if (nwritten < 0)
+        {
+#ifndef HAVE_W32CE_SYSTEM
+          if (errno == EINTR)
+            continue;
+#endif
+          return -1; /* write error */
+        }
+      length -= nwritten;
+      buffer += nwritten;
+    }
+  return 0;  /* okay */
+}
+
+/* read an entire line */
+static int
+readline (int fd, char *buf, size_t buflen, int *r_nread, int *iseof)
+{
+  size_t nleft = buflen; char *p;
+
+  *iseof = 0;
+  *r_nread = 0;
+  while (nleft > 0)
+    {
+      int n;
+#ifdef HAVE_W32CE_SYSTEM
+      do
+        {
+          if (!ReadFile ((HANDLE)fd, buf, nleft, &n, NULL))
+            n = -1;
+        }
+      while (n == -1 && GetLastError () == ERROR_PIPE_NOT_CONNECTED);
+#elif defined(USE_GNU_PTH)
+      n = pth_read (fd, buf, nleft);
+#else
+      n = read (fd, buf, nleft);
+#endif
+      if (n < 0)
+        {
+#ifndef HAVE_W32CE_SYSTEM
+          if (errno == EINTR)
+            continue;
+#endif
+          return -1; /* read error */
+        }
+      else if (!n)
+        {
+          *iseof = 1;
+          break; /* allow incomplete lines */
+        }
+      p = buf;
+      nleft -= n;
+      buf += n;
+      *r_nread += n;
+      
+      for (; n && *p != '\n'; n--, p++)
+        ;
+      if (n)
+        break; /* at least one full line available - that's enough for now */
+    }
+
+  return 0;
+}
+
+
+int
+_assuan_read_line (ASSUAN_CONTEXT ctx)
+{
+  char *line = ctx->inbound.line;
+  int n, nread, atticlen;
+  int rc;
+
+  if (ctx->inbound.eof)
+    return -1;
+
+  atticlen = ctx->inbound.attic.linelen;
+  if (atticlen)
+    {
+      memcpy (line, ctx->inbound.attic.line, atticlen);
+      ctx->inbound.attic.linelen = 0;
+      for (n=0; n < atticlen && line[n] != '\n'; n++)
+        ;
+      if (n < atticlen)
+       {
+         rc = 0; /* found another line in the attic */
+         nread = atticlen;
+         atticlen = 0;
+       }
+      else
+        { /* read the rest */
+          assert (atticlen < LINELENGTH);
+          rc = readline (ctx->inbound.fd, line + atticlen,
+                        LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
+        }
+    }
+  else
+    rc = readline (ctx->inbound.fd, line, LINELENGTH,
+                   &nread, &ctx->inbound.eof);
+  if (rc)
+    {
+      if (ctx->log_fp)
+        fprintf (ctx->log_fp, "%s[%p] <- [Error: %s]\n",
+                 my_log_prefix (), ctx, strerror (errno)); 
+      return ASSUAN_Read_Error;
+    }
+  if (!nread)
+    {
+      assert (ctx->inbound.eof);
+      if (ctx->log_fp)
+        fprintf (ctx->log_fp, "%s[%p] <- [EOF]\n", my_log_prefix (),ctx); 
+      return -1; 
+    }
+
+  ctx->inbound.attic.pending = 0;
+  nread += atticlen;
+  for (n=0; n < nread; n++)
+    {
+      if (line[n] == '\n')
+        {
+          if (n+1 < nread)
+            {
+              char *s, *d;
+              int i;
+
+              n++;
+              /* we have to copy the rest because the handlers are
+                 allowed to modify the passed buffer */
+              for (d=ctx->inbound.attic.line, s=line+n, i=nread-n; i; i--)
+                {
+                  if (*s=='\n')
+                    ctx->inbound.attic.pending = 1;
+                  *d++ = *s++;
+                }
+              ctx->inbound.attic.linelen = nread-n;
+              n--;
+            }
+          if (n && line[n-1] == '\r')
+            n--;
+          line[n] = 0;
+          ctx->inbound.linelen = n;
+          if (ctx->log_fp)
+            {
+              fprintf (ctx->log_fp, "%s[%p] <- ", my_log_prefix (), ctx); 
+              if (ctx->confidential)
+                fputs ("[Confidential data not shown]", ctx->log_fp);
+              else
+                _assuan_log_print_buffer (ctx->log_fp, 
+                                          ctx->inbound.line,
+                                          ctx->inbound.linelen);
+              putc ('\n', ctx->log_fp);
+            }
+          return 0;
+        }
+    }
+
+  if (ctx->log_fp)
+    fprintf (ctx->log_fp, "%s[%p] <- [Invalid line]\n", my_log_prefix (), ctx);
+  *line = 0;
+  ctx->inbound.linelen = 0;
+  return ctx->inbound.eof? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long;
+}
+
+
+/* Read the next line from the client or server and return a pointer
+   to a buffer with holding that line.  linelen returns the length of
+   the line.  This buffer is valid until another read operation is
+   done on this buffer.  The caller is allowed to modify this buffer.
+   He should only use the buffer if the function returns without an
+   error.
+
+   Returns: 0 on success or an assuan error code
+   See also: assuan_pending_line().
+*/
+AssuanError
+assuan_read_line (ASSUAN_CONTEXT ctx, char **line, size_t *linelen)
+{
+  AssuanError err;
+
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+
+  err = _assuan_read_line (ctx);
+  *line = ctx->inbound.line;
+  *linelen = ctx->inbound.linelen;
+  return err;
+}
+
+
+/* Return true when a full line is pending for a read, without the need
+   for actual IO */
+int
+assuan_pending_line (ASSUAN_CONTEXT ctx)
+{
+  return ctx && ctx->inbound.attic.pending;
+}
+
+
+AssuanError 
+assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
+{
+  int rc;
+  
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+
+  /* fixme: we should do some kind of line buffering */
+  if (ctx->log_fp)
+    {
+      fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
+      if (ctx->confidential)
+        fputs ("[Confidential data not shown]", ctx->log_fp);
+      else
+        _assuan_log_print_buffer (ctx->log_fp, 
+                                  line, strlen (line));
+      putc ('\n', ctx->log_fp);
+    }
+
+  rc = writen (ctx->outbound.fd, line, strlen(line));
+  if (rc)
+    rc = ASSUAN_Write_Error;
+  if (!rc)
+    {
+      rc = writen (ctx->outbound.fd, "\n", 1);
+      if (rc)
+        rc = ASSUAN_Write_Error;
+    }
+
+  return rc;
+}
+
+
+\f
+/* Write out the data in buffer as datalines with line wrapping and
+   percent escaping.  This fucntion is used for GNU's custom streams */
+int
+_assuan_cookie_write_data (void *cookie, const char *buffer, size_t size)
+{
+  ASSUAN_CONTEXT ctx = cookie;
+  char *line;
+  size_t linelen;
+
+  if (ctx->outbound.data.error)
+    return 0;
+
+  line = ctx->outbound.data.line;
+  linelen = ctx->outbound.data.linelen;
+  line += linelen;
+  while (size)
+    {
+      /* insert data line header */
+      if (!linelen)
+        {
+          *line++ = 'D';
+          *line++ = ' ';
+          linelen += 2;
+        }
+      
+      /* copy data, keep some space for the CRLF and to escape one character */
+      while (size && linelen < LINELENGTH-2-2)
+        {
+          if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
+            {
+              sprintf (line, "%%%02X", *(unsigned char*)buffer);
+              line += 3;
+              linelen += 3;
+              buffer++;
+            }
+          else
+            {
+              *line++ = *buffer++;
+              linelen++;
+            }
+          size--;
+        }
+      
+      if (linelen >= LINELENGTH-2-2)
+        {
+          if (ctx->log_fp)
+            {
+              fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
+              if (ctx->confidential)
+                fputs ("[Confidential data not shown]", ctx->log_fp);
+              else 
+                _assuan_log_print_buffer (ctx->log_fp, 
+                                          ctx->outbound.data.line,
+                                          linelen);
+              putc ('\n', ctx->log_fp);
+            }
+          *line++ = '\n';
+          linelen++;
+          if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
+            {
+              ctx->outbound.data.error = ASSUAN_Write_Error;
+              return 0;
+            }
+          line = ctx->outbound.data.line;
+          linelen = 0;
+        }
+    }
+
+  ctx->outbound.data.linelen = linelen;
+  return 0;
+}
+
+
+/* Write out any buffered data 
+   This fucntion is used for GNU's custom streams */
+int
+_assuan_cookie_write_flush (void *cookie)
+{
+  ASSUAN_CONTEXT ctx = cookie;
+  char *line;
+  size_t linelen;
+
+  if (ctx->outbound.data.error)
+    return 0;
+
+  line = ctx->outbound.data.line;
+  linelen = ctx->outbound.data.linelen;
+  line += linelen;
+  if (linelen)
+    {
+      if (ctx->log_fp)
+        {
+          fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
+          if (ctx->confidential)
+            fputs ("[Confidential data not shown]", ctx->log_fp);
+          else
+            _assuan_log_print_buffer (ctx->log_fp, 
+                                      ctx->outbound.data.line,
+                                      linelen);
+          putc ('\n', ctx->log_fp);
+            }
+      *line++ = '\n';
+      linelen++;
+      if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
+        {
+          ctx->outbound.data.error = ASSUAN_Write_Error;
+          return 0;
+        }
+      ctx->outbound.data.linelen = 0;
+    }
+  return 0;
+}
+
+
+/**
+ * assuan_send_data:
+ * @ctx: An assuan context
+ * @buffer: Data to send or NULL to flush
+ * @length: length of the data to send/
+ * 
+ * This function may be used by the server or the client to send data
+ * lines.  The data will be escaped as required by the Assuan protocol
+ * and may get buffered until a line is full.  To force sending the
+ * data out @buffer may be passed as NULL (in which case @length must
+ * also be 0); however when used by a client this flush operation does
+ * also send the terminating "END" command to terminate the reponse on
+ * a INQUIRE response.  However, when assuan_transact() is used, this
+ * function takes care of sending END itself.
+ * 
+ * Return value: 0 on success or an error code
+ **/
+\f
+AssuanError
+assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length)
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  if (!buffer && length)
+    return ASSUAN_Invalid_Value;
+
+  if (!buffer)
+    { /* flush what we have */
+      _assuan_cookie_write_flush (ctx);
+      if (ctx->outbound.data.error)
+        return ctx->outbound.data.error;
+      if (!ctx->is_server)
+        return assuan_write_line (ctx, "END");
+    }
+  else
+    {
+      _assuan_cookie_write_data (ctx, buffer, length);
+      if (ctx->outbound.data.error)
+        return ctx->outbound.data.error;
+    }
+
+  return 0;
+}
+
+
+
+
diff --git a/assuan-defs.h b/assuan-defs.h
new file mode 100644 (file)
index 0000000..d72741a
--- /dev/null
@@ -0,0 +1,141 @@
+/* assuan-defs.c - Internal definitions to Assuan
+ *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef ASSUAN_DEFS_H
+#define ASSUAN_DEFS_H
+
+#ifndef HAVE_W32CE_SYSTEM
+# include <sys/types.h>
+#endif
+#include "assuan.h"
+
+#define LINELENGTH ASSUAN_LINELENGTH
+
+struct cmdtbl_s {
+  const char *name;
+  int cmd_id;
+  int (*handler)(ASSUAN_CONTEXT, char *line);
+};
+
+struct assuan_context_s {
+  AssuanError err_no;
+  const char *err_str;
+  int os_errno;  /* last system error number used with certain error codes*/
+
+  int confidential;
+  int is_server;  /* set if this is context belongs to a server */
+  int in_inquire;
+  char *hello_line;
+  char *okay_line; /* see assan_set_okay_line() */
+  
+  void *user_pointer;  /* for assuan_[gs]et_pointer () */
+
+  FILE *log_fp;
+
+  struct {
+    int fd;
+    int eof;
+    char line[LINELENGTH];
+    int linelen;  /* w/o CR, LF - might not be the same as
+                     strlen(line) due to embedded nuls. However a nul
+                     is always written at this pos */
+    struct {
+      char line[LINELENGTH];
+      int linelen ;
+      int pending; /* i.e. at least one line is available in the attic */
+    } attic;
+  } inbound;
+
+  struct {
+    int fd;
+    struct {
+      FILE *fp;
+      char line[LINELENGTH];
+      int linelen; 
+      int error;
+    } data; 
+  } outbound;
+
+  int pipe_mode;  /* We are in pipe mode, i.e. we can handle just one
+                     connection and must terminate then */
+  pid_t pid;     /* In pipe mode, the pid of the child server process.  
+                     In socket mode, the pid of the server */
+  int listen_fd;  /* The fd we are listening on (used by socket servers) */
+
+  pid_t client_pid; /* for a socket server the PID of the client or -1
+                       if not available */
+
+  void (*deinit_handler)(ASSUAN_CONTEXT);  
+  int (*accept_handler)(ASSUAN_CONTEXT);
+  int (*finish_handler)(ASSUAN_CONTEXT);
+
+  struct cmdtbl_s *cmdtbl;
+  size_t cmdtbl_used; /* used entries */
+  size_t cmdtbl_size; /* allocated size of table */
+
+  void (*bye_notify_fnc)(ASSUAN_CONTEXT);
+  void (*reset_notify_fnc)(ASSUAN_CONTEXT);
+  void (*cancel_notify_fnc)(ASSUAN_CONTEXT);
+  int  (*option_handler_fnc)(ASSUAN_CONTEXT,const char*, const char*);
+  void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *);
+  void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *);
+
+  int input_fd;   /* set by INPUT command */
+  int output_fd;  /* set by OUTPUT command */
+
+};
+
+
+/*-- assuan-pipe-server.c --*/
+int _assuan_new_context (ASSUAN_CONTEXT *r_ctx);
+void _assuan_release_context (ASSUAN_CONTEXT ctx);
+
+
+/*-- assuan-handler.c --*/
+int _assuan_register_std_commands (ASSUAN_CONTEXT ctx);
+
+/*-- assuan-buffer.c --*/
+int _assuan_read_line (ASSUAN_CONTEXT ctx);
+int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size);
+int _assuan_cookie_write_flush (void *cookie);
+
+/*-- assuan-client.c --*/
+AssuanError _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off);
+
+
+/*-- assuan-util.c --*/
+void *_assuan_malloc (size_t n);
+void *_assuan_calloc (size_t n, size_t m);
+void *_assuan_realloc (void *p, size_t n);
+void  _assuan_free (void *p);
+
+#define xtrymalloc(a)    _assuan_malloc ((a))
+#define xtrycalloc(a,b)  _assuan_calloc ((a),(b))
+#define xtryrealloc(a,b) _assuan_realloc((a),(b))
+#define xfree(a)         _assuan_free ((a))
+
+#define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t))
+
+void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t  length);
+void _assuan_log_sanitized_string (const char *string);
+
+
+#endif /*ASSUAN_DEFS_H*/
+
diff --git a/assuan-errors.c b/assuan-errors.c
new file mode 100644 (file)
index 0000000..499b013
--- /dev/null
@@ -0,0 +1,57 @@
+/* Generated automatically by mkerrors */
+/* Do not edit! */
+
+#include <stdio.h>
+#include "assuan.h"
+
+/**
+ * assuan_strerror:
+ * @err:  Error code 
+ * 
+ * This function returns a textual representaion of the given
+ * errorcode. If this is an unknown value, a string with the value
+ * is returned (Beware: it is hold in a static buffer).
+ * 
+ * Return value: String with the error description.
+ **/
+const char *
+assuan_strerror (AssuanError err)
+{
+  const char *s;
+  static char buf[25];
+
+  switch (err)
+    {
+    case ASSUAN_No_Error: s="no error"; break;
+    case ASSUAN_General_Error: s="general error"; break;
+    case ASSUAN_Out_Of_Core: s="out of core"; break;
+    case ASSUAN_Invalid_Value: s="invalid value"; break;
+    case ASSUAN_Timeout: s="timeout"; break;
+    case ASSUAN_Read_Error: s="read error"; break;
+    case ASSUAN_Write_Error: s="write error"; break;
+    case ASSUAN_Problem_Starting_Server: s="problem starting server"; break;
+    case ASSUAN_Not_A_Server: s="not a server"; break;
+    case ASSUAN_Not_A_Client: s="not a client"; break;
+    case ASSUAN_Nested_Commands: s="nested commands"; break;
+    case ASSUAN_Invalid_Response: s="invalid response"; break;
+    case ASSUAN_No_Data_Callback: s="no data callback"; break;
+    case ASSUAN_No_Inquire_Callback: s="no inquire callback"; break;
+    case ASSUAN_Connect_Failed: s="connect failed"; break;
+    case ASSUAN_Accept_Failed: s="accept failed"; break;
+    case ASSUAN_Not_Implemented: s="not implemented"; break;
+    case ASSUAN_Server_Fault: s="server fault"; break;
+    case ASSUAN_Unknown_Command: s="unknown command"; break;
+    case ASSUAN_Syntax_Error: s="syntax error"; break;
+    case ASSUAN_Parameter_Conflict: s="parameter conflict"; break;
+    case ASSUAN_Line_Too_Long: s="line too long"; break;
+    case ASSUAN_Line_Not_Terminated: s="line not terminated"; break;
+    case ASSUAN_Canceled: s="canceled"; break;
+    case ASSUAN_Invalid_Option: s="invalid option"; break;
+    case ASSUAN_Locale_Problem: s="locale problem"; break;
+    case ASSUAN_Not_Confirmed: s="not confirmed"; break;
+    default:  sprintf (buf, "ec=%d", err ); s=buf; break;
+    }
+
+  return s;
+}
+
diff --git a/assuan-handler.c b/assuan-handler.c
new file mode 100644 (file)
index 0000000..d7d6172
--- /dev/null
@@ -0,0 +1,664 @@
+/* assuan-handler.c - dispatch commands 
+ *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "assuan-defs.h"
+
+#define spacep(p)  (*(p) == ' ' || *(p) == '\t')
+#define digitp(a) ((a) >= '0' && (a) <= '9')
+
+
+static int
+dummy_handler (ASSUAN_CONTEXT ctx, char *line)
+{
+  return set_error (ctx, Server_Fault, "no handler registered");
+}
+
+
+static int
+std_handler_nop (ASSUAN_CONTEXT ctx, char *line)
+{
+  return 0; /* okay */
+}
+  
+static int
+std_handler_cancel (ASSUAN_CONTEXT ctx, char *line)
+{
+  if (ctx->cancel_notify_fnc)
+    ctx->cancel_notify_fnc (ctx);
+  return set_error (ctx, Not_Implemented, NULL); 
+}
+
+static int
+std_handler_option (ASSUAN_CONTEXT ctx, char *line)
+{
+  char *key, *value, *p;
+
+  for (key=line; spacep (key); key++)
+    ;
+  if (!*key)
+    return set_error (ctx, Syntax_Error, "argument required");
+  if (*key == '=')
+    return set_error (ctx, Syntax_Error, "no option name given");
+  for (value=key; *value && !spacep (value) && *value != '='; value++)
+    ;
+  if (*value)
+    {
+      if (spacep (value))
+        *value++ = 0; /* terminate key */
+      for (; spacep (value); value++)
+        ;
+      if (*value == '=')
+        {
+          *value++ = 0; /* terminate key */
+          for (; spacep (value); value++)
+            ;
+          if (!*value)
+            return set_error (ctx, Syntax_Error, "option argument expected");
+        }
+      if (*value)
+        {
+          for (p = value + strlen(value) - 1; p > value && spacep (p); p--)
+            ;
+          if (p > value)
+            *++p = 0; /* strip trailing spaces */
+        }
+    }
+
+  if (*key == '-' && key[1] == '-' && key[2])
+    key += 2; /* the double dashes are optional */
+  if (*key == '-')
+    return set_error (ctx, Syntax_Error,
+                      "option should not begin with one dash");
+
+  if (ctx->option_handler_fnc)
+    return ctx->option_handler_fnc (ctx, key, value);
+  return 0;
+}
+  
+static int
+std_handler_bye (ASSUAN_CONTEXT ctx, char *line)
+{
+  if (ctx->bye_notify_fnc)
+    ctx->bye_notify_fnc (ctx);
+  assuan_close_input_fd (ctx);
+  assuan_close_output_fd (ctx);
+  return -1; /* pretty simple :-) */
+}
+  
+static int
+std_handler_auth (ASSUAN_CONTEXT ctx, char *line)
+{
+  return set_error (ctx, Not_Implemented, NULL); 
+}
+  
+static int
+std_handler_reset (ASSUAN_CONTEXT ctx, char *line)
+{
+  if (ctx->reset_notify_fnc)
+    ctx->reset_notify_fnc (ctx);
+  assuan_close_input_fd (ctx);
+  assuan_close_output_fd (ctx);
+  return 0;
+}
+  
+static int
+std_handler_end (ASSUAN_CONTEXT ctx, char *line)
+{
+  return set_error (ctx, Not_Implemented, NULL); 
+}
+
+static int
+parse_cmd_input_output (ASSUAN_CONTEXT ctx, char *line, int *rfd)
+{
+  char *endp;
+
+  if (strncmp (line, "FD=", 3))
+    return set_error (ctx, Syntax_Error, "FD=<n> expected");
+  line += 3;
+  if (!digitp (*line))
+    return set_error (ctx, Syntax_Error, "number required");
+  *rfd = strtoul (line, &endp, 10);
+  /* remove that argument so that a notify handler won't see it */
+  memset (line, ' ', endp? (endp-line):strlen(line));
+
+  if (*rfd == ctx->inbound.fd)
+    return set_error (ctx, Parameter_Conflict, "fd same as inbound fd");
+  if (*rfd == ctx->outbound.fd)
+    return set_error (ctx, Parameter_Conflict, "fd same as outbound fd");
+  return 0;
+}
+
+/* Format is INPUT FD=<n> */
+static int
+std_handler_input (ASSUAN_CONTEXT ctx, char *line)
+{
+  int rc, fd;
+
+  rc = parse_cmd_input_output (ctx, line, &fd);
+  if (rc)
+    return rc;
+  ctx->input_fd = fd;
+  if (ctx->input_notify_fnc)
+    ctx->input_notify_fnc (ctx, line);
+  return 0;
+}
+
+/* Format is OUTPUT FD=<n> */
+static int
+std_handler_output (ASSUAN_CONTEXT ctx, char *line)
+{
+  int rc, fd;
+
+  rc = parse_cmd_input_output (ctx, line, &fd);
+  if (rc)
+    return rc;
+  ctx->output_fd = fd;
+  if (ctx->output_notify_fnc)
+    ctx->output_notify_fnc (ctx, line);
+  return 0;
+}
+
+
+
+  
+
+/* This is a table with the standard commands and handler for them.
+   The table is used to initialize a new context and assuciate strings
+   and handlers with cmd_ids */
+static struct {
+  const char *name;
+  int cmd_id;
+  int (*handler)(ASSUAN_CONTEXT, char *line);
+  int always; /* always initialize this command */
+} std_cmd_table[] = {
+  { "NOP",    ASSUAN_CMD_NOP,    std_handler_nop, 1 },
+  { "CANCEL", ASSUAN_CMD_CANCEL, std_handler_cancel, 1 },
+  { "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
+  { "BYE",    ASSUAN_CMD_BYE,    std_handler_bye, 1 },
+  { "AUTH",   ASSUAN_CMD_AUTH,   std_handler_auth, 1 },
+  { "RESET",  ASSUAN_CMD_RESET,  std_handler_reset, 1 },
+  { "END",    ASSUAN_CMD_END,    std_handler_end, 1 },
+
+  { "INPUT",  ASSUAN_CMD_INPUT,  std_handler_input },
+  { "OUTPUT", ASSUAN_CMD_OUTPUT, std_handler_output },
+  { "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
+  { NULL }
+};
+
+
+/**
+ * assuan_register_command:
+ * @ctx: the server context
+ * @cmd_id: An ID value for the command
+ * @cmd_name: A string with the command name
+ * @handler: The handler function to be called
+ * 
+ * Register a handler to be used for a given command.
+ * 
+ * The @cmd_name must be %NULL or an empty string for all @cmd_ids
+ * below %ASSUAN_CMD_USER because predefined values are used.
+ * 
+ * Return value: 
+ **/
+int
+assuan_register_command (ASSUAN_CONTEXT ctx,
+                         int cmd_id, const char *cmd_name,
+                         int (*handler)(ASSUAN_CONTEXT, char *))
+{
+  int i;
+
+  if (cmd_name && !*cmd_name)
+    cmd_name = NULL;
+
+  if (cmd_id < ASSUAN_CMD_USER)
+    { 
+      if (cmd_name)
+        return ASSUAN_Invalid_Value; /* must be NULL for these values*/
+
+      for (i=0; std_cmd_table[i].name; i++)
+        {
+          if (std_cmd_table[i].cmd_id == cmd_id)
+            {
+              cmd_name = std_cmd_table[i].name;
+              if (!handler)
+                handler = std_cmd_table[i].handler;
+              break;
+            }
+        }
+      if (!std_cmd_table[i].name)
+        return ASSUAN_Invalid_Value; /* not a pre-registered one */
+    }
+  
+  if (!handler)
+    handler = dummy_handler;
+
+  if (!cmd_name)
+    return ASSUAN_Invalid_Value;
+
+/*    fprintf (stderr, "DBG-assuan: registering %d as `%s'\n", cmd_id, cmd_name); */
+
+  if (!ctx->cmdtbl)
+    {
+      ctx->cmdtbl_size = 50;
+      ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl);
+      if (!ctx->cmdtbl)
+        return ASSUAN_Out_Of_Core;
+      ctx->cmdtbl_used = 0;
+    }
+  else if (ctx->cmdtbl_used >= ctx->cmdtbl_size)
+    {
+      struct cmdtbl_s *x;
+
+      x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
+      if (!x)
+        return ASSUAN_Out_Of_Core;
+      ctx->cmdtbl = x;
+      ctx->cmdtbl_size += 50;
+    }
+
+  ctx->cmdtbl[ctx->cmdtbl_used].name = cmd_name;
+  ctx->cmdtbl[ctx->cmdtbl_used].cmd_id = cmd_id;
+  ctx->cmdtbl[ctx->cmdtbl_used].handler = handler;
+  ctx->cmdtbl_used++;
+  return 0;
+}
+
+int
+assuan_register_bye_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  ctx->bye_notify_fnc = fnc;
+  return 0;
+}
+
+int
+assuan_register_reset_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  ctx->reset_notify_fnc = fnc;
+  return 0;
+}
+
+int
+assuan_register_cancel_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  ctx->cancel_notify_fnc = fnc;
+  return 0;
+}
+
+int
+assuan_register_option_handler (ASSUAN_CONTEXT ctx,
+                               int (*fnc)(ASSUAN_CONTEXT,
+                                          const char*, const char*))
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  ctx->option_handler_fnc = fnc;
+  return 0;
+}
+
+int
+assuan_register_input_notify (ASSUAN_CONTEXT ctx,
+                              void (*fnc)(ASSUAN_CONTEXT, const char *))
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  ctx->input_notify_fnc = fnc;
+  return 0;
+}
+
+int
+assuan_register_output_notify (ASSUAN_CONTEXT ctx,
+                              void (*fnc)(ASSUAN_CONTEXT, const char *))
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  ctx->output_notify_fnc = fnc;
+  return 0;
+}
+
+
+/* Helper to register the standards commands */
+int
+_assuan_register_std_commands (ASSUAN_CONTEXT ctx)
+{
+  int i, rc;
+
+  for (i=0; std_cmd_table[i].name; i++)
+    {
+      if (std_cmd_table[i].always)
+        {
+          rc = assuan_register_command (ctx, std_cmd_table[i].cmd_id,
+                                        NULL, NULL);
+          if (rc)
+            return rc;
+        }
+    } 
+  return 0;
+}
+
+
+\f
+/* Process the special data lines.  The "D " has already been removed
+   from the line.  As all handlers this function may modify the line.  */
+static int
+handle_data_line (ASSUAN_CONTEXT ctx, char *line, int linelen)
+{
+  return set_error (ctx, Not_Implemented, NULL);
+}
+
+/* like ascii_strcasecmp but assume that B is already uppercase */
+static int
+my_strcasecmp (const char *a, const char *b)
+{
+    if (a == b)
+        return 0;
+
+    for (; *a && *b; a++, b++)
+      {
+       if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b)
+           break;
+      }
+    return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b);
+}
+
+/* Parse the line, break out the command, find it in the command
+   table, remove leading and white spaces from the arguments, all the
+   handler with the argument line and return the error */
+static int 
+dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen)
+{
+  char *p;
+  const char *s;
+  int shift, i;
+
+  if (*line == 'D' && line[1] == ' ') /* divert to special handler */
+    return handle_data_line (ctx, line+2, linelen-2);
+
+  for (p=line; *p && *p != ' ' && *p != '\t'; p++)
+    ;
+  if (p==line)
+    return set_error (ctx, Syntax_Error, "leading white-space"); 
+  if (*p) 
+    { /* Skip over leading WS after the keyword */
+      *p++ = 0;
+      while ( *p == ' ' || *p == '\t')
+        p++;
+    }
+  shift = p - line;
+
+  for (i=0; (s=ctx->cmdtbl[i].name); i++)
+    {
+      if (!strcmp (line, s))
+        break;
+    }
+  if (!s)
+    { /* and try case insensitive */
+      for (i=0; (s=ctx->cmdtbl[i].name); i++)
+        {
+          if (!my_strcasecmp (line, s))
+            break;
+        }
+    }
+  if (!s)
+    return set_error (ctx, Unknown_Command, NULL);
+  line += shift;
+  linelen -= shift;
+
+/*    fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */
+  return ctx->cmdtbl[i].handler (ctx, line);
+}
+
+
+
+\f
+static int
+process_request (ASSUAN_CONTEXT ctx)
+{
+  int rc;
+
+  if (ctx->in_inquire)
+    return ASSUAN_Nested_Commands;
+
+  rc = _assuan_read_line (ctx);
+  if (rc)
+    return rc;
+  if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
+    return 0; /* comment line - ignore */
+
+  ctx->outbound.data.error = 0;
+  ctx->outbound.data.linelen = 0;
+  /* dispatch command and return reply */
+  rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
+  /* check from data write errors */
+  if (ctx->outbound.data.fp)
+    { /* Flush the data lines */
+      fclose (ctx->outbound.data.fp);
+      ctx->outbound.data.fp = NULL;
+      if (!rc && ctx->outbound.data.error)
+        rc = ctx->outbound.data.error;
+    }
+  else /* flush any data send w/o using the data fp */
+    {
+      assuan_send_data (ctx, NULL, 0);
+      if (!rc && ctx->outbound.data.error)
+        rc = ctx->outbound.data.error;
+    }
+  /* Error handling */
+  if (!rc)
+    {
+      rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
+    }
+  else if (rc == -1)
+    { /* No error checking because the peer may have already disconnect */ 
+      assuan_write_line (ctx, "OK closing connection");
+      ctx->finish_handler (ctx);
+    }
+  else 
+    {
+      char errline[256];
+
+      if (rc < 100)
+        sprintf (errline, "ERR %d server fault (%.50s)",
+                 ASSUAN_Server_Fault, assuan_strerror (rc));
+      else
+        {
+          const char *text = ctx->err_no == rc? ctx->err_str:NULL;
+
+          sprintf (errline, "ERR %d %.50s%s%.100s",
+                   rc, assuan_strerror (rc), text? " - ":"", text?text:"");
+        }
+      rc = assuan_write_line (ctx, errline);
+    }
+
+  ctx->confidential = 0;
+  if (ctx->okay_line)
+    {
+      xfree (ctx->okay_line);
+      ctx->okay_line = NULL;
+    }
+  return rc;
+}
+
+/**
+ * assuan_process:
+ * @ctx: assuan context
+ * 
+ * This fucntion is used to handle the assuan protocol after a
+ * connection has been established using assuan_accept().  This is the
+ * main protocol handler.
+ * 
+ * Return value: 0 on success or an error code if the assuan operation
+ * failed.  Note, that no error is returned for operational errors.
+ **/
+int
+assuan_process (ASSUAN_CONTEXT ctx)
+{
+  int rc;
+
+  do {
+    rc = process_request (ctx);
+  } while (!rc);
+
+  if (rc == -1)
+    rc = 0;
+
+  return rc;
+}
+
+
+/**
+ * assuan_process_next:
+ * @ctx: Assuan context
+ * 
+ * Same as assuan_process() but the user has to provide the outer
+ * loop.  He should loop as long as the return code is zero and stop
+ * otherwise; -1 is regular end.
+ * 
+ * See also: assuan_get_active_fds()
+ * Return value: -1 for end of server, 0 on success or an error code
+ **/
+int 
+assuan_process_next (ASSUAN_CONTEXT ctx)
+{
+  return process_request (ctx);
+}
+
+
+/**
+ * assuan_get_active_fds:
+ * @ctx: Assuan context
+ * @what: 0 for read fds, 1 for write fds
+ * @fdarray: Caller supplied array to store the FDs
+ * @fdarraysize: size of that array
+ * 
+ * Return all active filedescriptors for the given context.  This
+ * function can be used to select on the fds and call
+ * assuan_process_next() if there is an active one.  The first fd in
+ * the array is the one used for the command connection.
+ *
+ * Note, that write FDs are not yet supported.
+ * 
+ * Return value: number of FDs active and put into @fdarray or -1 on
+ * error which is most likely a too small fdarray.
+ **/
+int 
+assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
+                       int *fdarray, int fdarraysize)
+{
+  int n = 0;
+
+  if (!ctx || fdarraysize < 2 || what < 0 || what > 1)
+    return -1;
+
+  if (!what)
+    {
+      if (ctx->inbound.fd != -1)
+        fdarray[n++] = ctx->inbound.fd;
+    }
+  else
+    {
+      if (ctx->outbound.fd != -1)
+        fdarray[n++] = ctx->outbound.fd;
+      if (ctx->outbound.data.fp)
+        fdarray[n++] = fileno (ctx->outbound.data.fp);
+    }
+
+  return n;
+}
+
+
+/* Set the text used for the next OK reponse.  This string is
+   automatically reset to NULL after the next command. */
+AssuanError
+assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line)
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  if (!line)
+    {
+      xfree (ctx->okay_line);
+      ctx->okay_line = NULL;
+    }
+  else
+    {
+      /* FIXME: we need to use gcry_is_secure() to test whether
+         we should allocate the entire line in secure memory */
+      char *buf = xtrymalloc (3+strlen(line)+1);
+      if (!buf)
+        return ASSUAN_Out_Of_Core;
+      strcpy (buf, "OK ");
+      strcpy (buf+3, line);
+      xfree (ctx->okay_line);
+      ctx->okay_line = buf;
+    }
+  return 0;
+}
+
+
+
+void
+assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
+{
+  char buffer[256];
+  char *helpbuf;
+  size_t n;
+
+  if ( !ctx || !keyword)
+    return;
+  if (!text)
+    text = "";
+
+  n = 2 + strlen (keyword) + 1 + strlen (text) + 1;
+  if (n < sizeof (buffer))
+    {
+      strcpy (buffer, "S ");
+      strcat (buffer, keyword);
+      if (*text)
+        {
+          strcat (buffer, " ");
+          strcat (buffer, text);
+        }
+      assuan_write_line (ctx, buffer);
+    }
+  else if ( (helpbuf = xtrymalloc (n)) )
+    {
+      strcpy (helpbuf, "S ");
+      strcat (helpbuf, keyword);
+      if (*text)
+        {
+          strcat (helpbuf, " ");
+          strcat (helpbuf, text);
+        }
+      assuan_write_line (ctx, helpbuf);
+      xfree (helpbuf);
+    }
+}
diff --git a/assuan-listen.c b/assuan-listen.c
new file mode 100644 (file)
index 0000000..d36a72e
--- /dev/null
@@ -0,0 +1,138 @@
+/* assuan-listen.c - Wait for a connection (server) 
+ *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef HAVE_W32CE_SYSTEM
+# include <unistd.h>
+#else
+# define close CloseHandle
+#endif
+
+#include "assuan-defs.h"
+
+AssuanError
+assuan_set_hello_line (ASSUAN_CONTEXT ctx, const char *line)
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  if (!line)
+    {
+      xfree (ctx->hello_line);
+      ctx->hello_line = NULL;
+    }
+  else
+    {
+      char *buf = xtrymalloc (3+strlen(line)+1);
+      if (!buf)
+        return ASSUAN_Out_Of_Core;
+      strcpy (buf, "OK ");
+      strcpy (buf+3, line);
+      xfree (ctx->hello_line);
+      ctx->hello_line = buf;
+    }
+  return 0;
+}
+
+
+/**
+ * assuan_accept:
+ * @ctx: context
+ * 
+ * Cancel any existing connectiion and wait for a connection from a
+ * client.  The initial handshake is performed which may include an
+ * initial authentication or encryption negotiation.
+ * 
+ * Return value: 0 on success or an error if the connection could for
+ * some reason not be established.
+ **/
+AssuanError
+assuan_accept (ASSUAN_CONTEXT ctx)
+{
+  int rc;
+
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+
+  if (ctx->pipe_mode > 1)
+    return -1; /* second invocation for pipemode -> terminate */
+  ctx->finish_handler (ctx);
+
+  rc = ctx->accept_handler (ctx);
+  if (rc)
+    return rc;
+
+  /* send the hello */
+  rc = assuan_write_line (ctx, ctx->hello_line? ctx->hello_line
+                                              : "OK Your orders please");
+  if (rc)
+    return rc;
+  
+  if (ctx->pipe_mode)
+    ctx->pipe_mode = 2;
+  
+  return 0;
+}
+
+
+
+int
+assuan_get_input_fd (ASSUAN_CONTEXT ctx)
+{
+  return ctx? ctx->input_fd : -1;
+}
+
+
+int
+assuan_get_output_fd (ASSUAN_CONTEXT ctx)
+{
+  return ctx? ctx->output_fd : -1;
+}
+
+
+/* Close the fd descriptor set by the command INPUT FD=n.  We handle
+   this fd inside assuan so that we can do some initial checks */
+AssuanError
+assuan_close_input_fd (ASSUAN_CONTEXT ctx)
+{
+  if (!ctx || ctx->input_fd == -1)
+    return ASSUAN_Invalid_Value;
+  close (ctx->input_fd);
+  ctx->input_fd = -1;
+  return 0;
+}
+
+/* Close the fd descriptor set by the command OUTPUT FD=n.  We handle
+   this fd inside assuan so that we can do some initial checks */
+AssuanError
+assuan_close_output_fd (ASSUAN_CONTEXT ctx)
+{
+  if (!ctx || ctx->output_fd == -1)
+    return ASSUAN_Invalid_Value;
+
+  close (ctx->output_fd);
+  ctx->output_fd = -1;
+  return 0;
+}
+
diff --git a/assuan-pipe-server.c b/assuan-pipe-server.c
new file mode 100644 (file)
index 0000000..b2cb210
--- /dev/null
@@ -0,0 +1,126 @@
+/* assuan-pipe-server.c - Assuan server working over a pipe 
+ *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "assuan-defs.h"
+
+static void
+deinit_pipe_server (ASSUAN_CONTEXT ctx)
+{
+  /* nothing to do for this simple server */
+}
+
+static int
+accept_connection (ASSUAN_CONTEXT ctx)
+{
+  /* This is a NOP for a pipe server */
+  return 0;
+}
+
+static int
+finish_connection (ASSUAN_CONTEXT ctx)
+{
+  /* This is a NOP for a pipe server */
+  return 0;
+}
+
+
+/* Create a new context.  Note that the handlers are set up for a pipe
+   server/client - this way we don't need extra dummy functions */
+int
+_assuan_new_context (ASSUAN_CONTEXT *r_ctx)
+{
+  ASSUAN_CONTEXT ctx;
+  int rc;
+
+  *r_ctx = NULL;
+  ctx = xtrycalloc (1, sizeof *ctx);
+  if (!ctx)
+    return ASSUAN_Out_Of_Core;
+  ctx->input_fd = -1;
+  ctx->output_fd = -1;
+
+  ctx->inbound.fd = -1;
+  ctx->outbound.fd = -1;
+
+  ctx->listen_fd = -1;
+  ctx->client_pid = (pid_t)-1;
+  /* use the pipe server handler as a default */
+  ctx->deinit_handler = deinit_pipe_server;
+  ctx->accept_handler = accept_connection;
+  ctx->finish_handler = finish_connection;
+
+  rc = _assuan_register_std_commands (ctx);
+  if (rc)
+    xfree (ctx);
+  else
+    *r_ctx = ctx;
+  return rc;
+}
+
+
+
+int
+assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
+{
+  int rc;
+
+  rc = _assuan_new_context (r_ctx);
+  if (!rc)
+    {
+      ASSUAN_CONTEXT ctx = *r_ctx;
+
+      ctx->is_server = 1;
+      ctx->inbound.fd = filedes[0];
+      ctx->outbound.fd = filedes[1];
+      ctx->pipe_mode = 1;
+    }
+  return rc;
+}
+
+
+void
+_assuan_release_context (ASSUAN_CONTEXT ctx)
+{
+  if (ctx)
+    {
+      xfree (ctx->hello_line);
+      xfree (ctx->okay_line);
+      xfree (ctx);
+    }
+}
+
+void
+assuan_deinit_server (ASSUAN_CONTEXT ctx)
+{
+  if (ctx)
+    {
+      /* We use this function pointer to avoid linking other server
+         when not needed but still allow for a generic deinit function */
+      ctx->deinit_handler (ctx);
+      ctx->deinit_handler = NULL;
+      _assuan_release_context (ctx);
+    }
+}
diff --git a/assuan-util.c b/assuan-util.c
new file mode 100644 (file)
index 0000000..fa48db9
--- /dev/null
@@ -0,0 +1,198 @@
+/* assuan-util.c - Utility functions for Assuan 
+ *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "assuan-defs.h"
+
+#ifdef HAVE_JNLIB_LOGGING
+#include "../jnlib/logging.h"
+#endif
+
+
+static void *(*alloc_func)(size_t n) = malloc;
+static void *(*realloc_func)(void *p, size_t n) = realloc;
+static void (*free_func)(void*) = free;
+
+
+
+void
+assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
+                          void *(*new_realloc_func)(void *p, size_t n),
+                          void (*new_free_func)(void*) )
+{
+  alloc_func       = new_alloc_func;
+  realloc_func      = new_realloc_func;
+  free_func        = new_free_func;
+}
+
+void *
+_assuan_malloc (size_t n)
+{
+  return alloc_func (n);
+}
+
+void *
+_assuan_realloc (void *a, size_t n)
+{
+  return realloc_func (a, n);
+}
+
+void *
+_assuan_calloc (size_t n, size_t m)
+{
+  void *p = _assuan_malloc (n*m);
+  if (p)
+    memset (p, 0, n* m);
+  return p;
+}
+
+void
+_assuan_free (void *p)
+{
+  if (p)
+    free_func (p);
+}
+
+
+\f
+/* Store the error in the context so that the error sending function
+  can take out a descriptive text.  Inside the assuan code, use the
+  macro set_error instead of this function. */
+int
+assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text)
+{
+  ctx->err_no = err;
+  ctx->err_str = text;
+  return err;
+}
+
+void
+assuan_set_pointer (ASSUAN_CONTEXT ctx, void *pointer)
+{
+  if (ctx)
+    ctx->user_pointer = pointer;
+}
+
+void *
+assuan_get_pointer (ASSUAN_CONTEXT ctx)
+{
+  return ctx? ctx->user_pointer : NULL;
+}
+
+
+void
+assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp)
+{
+  if (ctx)
+    {
+      if (ctx->log_fp)
+        fflush (ctx->log_fp);
+      ctx->log_fp = fp;
+    }
+}
+
+
+void
+assuan_begin_confidential (ASSUAN_CONTEXT ctx)
+{
+  if (ctx)
+    {
+      ctx->confidential = 1;
+    }
+}
+
+void
+assuan_end_confidential (ASSUAN_CONTEXT ctx)
+{
+  if (ctx)
+    {
+      ctx->confidential = 0;
+    }
+}
+
+void
+_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length)
+{
+  const unsigned char *s;
+  int n;
+
+  for (n=length,s=buffer; n; n--, s++)
+    {
+      if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
+        break;
+    }
+  s = buffer;
+  if (!n && *s != '[')
+    fwrite (buffer, length, 1, fp);
+  else
+    {
+      putc ('[', fp);
+      for (n=0; n < length; n++, s++)
+          fprintf (fp, " %02x", *s);
+      putc (' ', fp);
+      putc (']', fp);
+    }
+}
+
+
+/* print a user supplied string after filtering out potential bad
+   characters*/
+void
+_assuan_log_sanitized_string (const char *string)
+{
+  const unsigned char *s = (const unsigned char*)string;
+#ifdef HAVE_JNLIB_LOGGING
+  FILE *fp = log_get_stream ();
+#else
+  FILE *fp = stderr;
+#endif
+
+  for (; *s; s++)
+    {
+      if (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0))
+        {
+          putc ('\\', fp);
+          if (*s == '\n')
+            putc ('n', fp);
+          else if (*s == '\r')
+            putc ('r', fp);
+          else if (*s == '\f')
+            putc ('f', fp);
+          else if (*s == '\v')
+            putc ('v', fp);
+          else if (*s == '\b')
+            putc ('b', fp);
+          else if (!*s)
+            putc ('0', fp);
+          else
+            fprintf (fp, "x%02x", *s );
+       }
+      else
+        putc (*s, fp);
+    }
+}
+
+
diff --git a/assuan.h b/assuan.h
new file mode 100644 (file)
index 0000000..8d3adc6
--- /dev/null
+++ b/assuan.h
@@ -0,0 +1,203 @@
+/* assuan.c - Definitions for the Assuna protocol
+ *     Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef ASSUAN_H
+#define ASSUAN_H
+
+#include <stdio.h>
+#ifndef HAVE_W32CE_SYSTEM
+# include <sys/types.h>
+#else
+typedef int pid_t;
+#endif
+
+#ifdef __cplusplus
+extern "C" { 
+#if 0
+ }
+#endif
+#endif
+
+/* 5 is pinentry.  */
+#define ASSUAN_ERROR(code) ((5 << 24)  | code)
+
+typedef enum {
+  ASSUAN_No_Error = 0,
+  ASSUAN_General_Error = ASSUAN_ERROR (257),
+  ASSUAN_Out_Of_Core = ASSUAN_ERROR (86 | (1 << 15)),
+  ASSUAN_Invalid_Value = ASSUAN_ERROR (261),
+  ASSUAN_Timeout = ASSUAN_ERROR (62),
+  ASSUAN_Read_Error = ASSUAN_ERROR (270),  /* Not 100%, but sufficient here. */
+  ASSUAN_Write_Error = ASSUAN_ERROR (271), /* Not 100%, but sufficient here. */
+  ASSUAN_Problem_Starting_Server = ASSUAN_ERROR (269),
+  ASSUAN_Not_A_Server = ASSUAN_ERROR (267),
+  ASSUAN_Not_A_Client = ASSUAN_ERROR (268),
+  ASSUAN_Nested_Commands = ASSUAN_ERROR (264),
+  ASSUAN_Invalid_Response = ASSUAN_ERROR (260),
+  ASSUAN_No_Data_Callback = ASSUAN_ERROR (265),
+  ASSUAN_No_Inquire_Callback = ASSUAN_ERROR (266),
+  ASSUAN_Connect_Failed = ASSUAN_ERROR (259),
+  ASSUAN_Accept_Failed = ASSUAN_ERROR (258),
+
+  /* error codes above 99 are meant as status codes */
+  ASSUAN_Not_Implemented = ASSUAN_ERROR (69),
+  ASSUAN_Server_Fault    = ASSUAN_ERROR (80),
+  ASSUAN_Unknown_Command = ASSUAN_ERROR (275),
+  ASSUAN_Syntax_Error    = ASSUAN_ERROR (276),
+  ASSUAN_Parameter_Conflict = ASSUAN_ERROR (280),
+  ASSUAN_Line_Too_Long = ASSUAN_ERROR (263),
+  ASSUAN_Line_Not_Terminated = ASSUAN_ERROR (262),
+  ASSUAN_Canceled = ASSUAN_ERROR (99),
+  ASSUAN_Invalid_Option = ASSUAN_ERROR (174), /* GPG_ERR_UNKNOWN_OPTION */
+  ASSUAN_Locale_Problem = ASSUAN_ERROR (166),
+  ASSUAN_Not_Confirmed = ASSUAN_ERROR (114),
+
+} assuan_error_t;
+
+#define ASSUAN_Parameter_Error ASSUAN_Parameter_Conflict
+
+
+typedef assuan_error_t AssuanError; /* Deprecated. */
+
+/* This is a list of pre-registered ASSUAN commands */
+typedef enum {
+  ASSUAN_CMD_NOP = 0,
+  ASSUAN_CMD_CANCEL,    /* cancel the current request */
+  ASSUAN_CMD_BYE,
+  ASSUAN_CMD_AUTH,
+  ASSUAN_CMD_RESET,
+  ASSUAN_CMD_OPTION,
+  ASSUAN_CMD_DATA,
+  ASSUAN_CMD_END,
+  ASSUAN_CMD_INPUT,
+  ASSUAN_CMD_OUTPUT,
+
+  ASSUAN_CMD_USER = 256  /* Other commands should be used with this offset*/
+} AssuanCommand;
+
+#define ASSUAN_LINELENGTH 1002 /* 1000 + [CR,]LF */
+
+struct assuan_context_s;
+typedef struct assuan_context_s *assuan_context_t; 
+typedef struct assuan_context_s *ASSUAN_CONTEXT; /* Deprecated.  */
+
+/*-- assuan-handler.c --*/
+int assuan_register_command (ASSUAN_CONTEXT ctx,
+                             int cmd_id, const char *cmd_string,
+                             int (*handler)(ASSUAN_CONTEXT, char *));
+int assuan_register_bye_notify (ASSUAN_CONTEXT ctx,
+                                void (*fnc)(ASSUAN_CONTEXT));
+int assuan_register_reset_notify (ASSUAN_CONTEXT ctx,
+                                  void (*fnc)(ASSUAN_CONTEXT));
+int assuan_register_cancel_notify (ASSUAN_CONTEXT ctx,
+                                   void (*fnc)(ASSUAN_CONTEXT));
+int assuan_register_input_notify (ASSUAN_CONTEXT ctx,
+                                  void (*fnc)(ASSUAN_CONTEXT, const char *));
+int assuan_register_output_notify (ASSUAN_CONTEXT ctx,
+                                  void (*fnc)(ASSUAN_CONTEXT, const char *));
+
+int assuan_register_option_handler (ASSUAN_CONTEXT ctx,
+                                    int (*fnc)(ASSUAN_CONTEXT,
+                                               const char*, const char*));
+
+int assuan_process (ASSUAN_CONTEXT ctx);
+int assuan_process_next (ASSUAN_CONTEXT ctx);
+int assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
+                           int *fdarray, int fdarraysize);
+
+
+AssuanError assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line);
+void assuan_write_status (ASSUAN_CONTEXT ctx,
+                          const char *keyword, const char *text);
+
+
+/*-- assuan-listen.c --*/
+AssuanError assuan_set_hello_line (ASSUAN_CONTEXT ctx, const char *line);
+AssuanError assuan_accept (ASSUAN_CONTEXT ctx);
+int assuan_get_input_fd (ASSUAN_CONTEXT ctx);
+int assuan_get_output_fd (ASSUAN_CONTEXT ctx);
+AssuanError assuan_close_input_fd (ASSUAN_CONTEXT ctx);
+AssuanError assuan_close_output_fd (ASSUAN_CONTEXT ctx);
+
+
+/*-- assuan-pipe-server.c --*/
+int assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]);
+void assuan_deinit_server (ASSUAN_CONTEXT ctx);
+
+/*-- assuan-socket-server.c --*/
+int assuan_init_socket_server (ASSUAN_CONTEXT *r_ctx, int listen_fd);
+
+
+/*-- assuan-pipe-connect.c --*/
+AssuanError assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name,
+                                 char *const argv[], int *fd_child_list);
+/*-- assuan-socket-connect.c --*/
+AssuanError assuan_socket_connect (ASSUAN_CONTEXT *ctx, const char *name,
+                                   pid_t server_pid);
+
+/*-- assuan-connect.c --*/
+void assuan_disconnect (ASSUAN_CONTEXT ctx);
+pid_t assuan_get_pid (ASSUAN_CONTEXT ctx);
+
+/*-- assuan-client.c --*/
+AssuanError 
+assuan_transact (ASSUAN_CONTEXT ctx,
+                 const char *command,
+                 AssuanError (*data_cb)(void *, const void *, size_t),
+                 void *data_cb_arg,
+                 AssuanError (*inquire_cb)(void*, const char *),
+                 void *inquire_cb_arg,
+                 AssuanError (*status_cb)(void*, const char *),
+                 void *status_cb_arg);
+
+
+/*-- assuan-inquire.c --*/
+AssuanError assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
+                            char **r_buffer, size_t *r_length, size_t maxlen);
+
+/*-- assuan-buffer.c --*/
+AssuanError assuan_read_line (ASSUAN_CONTEXT ctx,
+                              char **line, size_t *linelen);
+int assuan_pending_line (ASSUAN_CONTEXT ctx);
+AssuanError assuan_write_line (ASSUAN_CONTEXT ctx, const char *line );
+AssuanError assuan_send_data (ASSUAN_CONTEXT ctx,
+                              const void *buffer, size_t length);
+
+
+/*-- assuan-util.c --*/
+void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
+                               void *(*new_realloc_func)(void *p, size_t n),
+                               void (*new_free_func)(void*) );
+void assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp);
+int assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text);
+void assuan_set_pointer (ASSUAN_CONTEXT ctx, void *pointer);
+void *assuan_get_pointer (ASSUAN_CONTEXT ctx);
+
+void assuan_begin_confidential (ASSUAN_CONTEXT ctx);
+void assuan_end_confidential (ASSUAN_CONTEXT ctx);
+
+/*-- assuan-errors.c (built) --*/
+const char *assuan_strerror (AssuanError err);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*ASSUAN_H*/
diff --git a/config.h b/config.h
new file mode 100644 (file)
index 0000000..c6ad32d
--- /dev/null
+++ b/config.h
@@ -0,0 +1,2 @@
+/* #undef HAVE_DOSISH_SYSTEM */
+/* #undef HAVE_CONFIG_H */
diff --git a/config.h.in b/config.h.in
new file mode 100644 (file)
index 0000000..03d2d18
--- /dev/null
@@ -0,0 +1,2 @@
+#cmakedefine HAVE_DOSISH_SYSTEM 1
+#cmakedefine HAVE_CONFIG_H 1
diff --git a/document-encrypt.png b/document-encrypt.png
new file mode 100644 (file)
index 0000000..b80c2a6
Binary files /dev/null and b/document-encrypt.png differ
diff --git a/getopt.c b/getopt.c
new file mode 100644 (file)
index 0000000..e0dc60a
--- /dev/null
+++ b/getopt.c
@@ -0,0 +1,1265 @@
+/*TE: getopt is now part of the C library, so if you don't know what
+   "Keep this file name-space clean" means, talk to drepper@gnu.org
+   before changing it!
+   Copyright (C) 1987,88,89,90,91,92,93,94,95,96,98,99,2000,2001
+        Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+   Ditto for AIX 3.2 and <stdlib.h>.  */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+#define getenv(x) 0 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+   reject `defined (const)'.  */
+# ifndef const
+#  define const
+# endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself.  This code is part of the GNU C
+   Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object files,
+   it is simpler to just do this in the source for each such file.  */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#  define ELIDE_CODE
+# endif
+#endif
+
+#ifndef ELIDE_CODE
+
+
+/* This needs to come after some library #include
+   to get __GNU_LIBRARY__ defined.  */
+#ifdef  __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+   contain conflicting prototypes for getopt.  */
+# include <stdlib.h>
+# include <unistd.h>
+#endif  /* GNU C library.  */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+#  include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.  */
+# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC
+#  include <libintl.h>
+#  ifndef _
+#   define _(msgid)     gettext (msgid)
+#  endif
+# else
+#  define _(msgid)      (msgid)
+# endif
+# if defined _LIBC && defined USE_IN_LIBIO
+#  include <wchar.h>
+# endif
+#endif
+
+/* This version of `getopt' appears to the caller like standard Unix `getopt'
+   but it behaves differently for the user, since it allows the user
+   to intersperse the options with the other arguments.
+
+   As `getopt' works, it permutes the elements of ARGV so that,
+   when it is done, all the options precede everything else.  Thus
+   all application programs are extended to handle flexible argument order.
+
+   Setting the environment variable POSIXLY_CORRECT disables permutation.
+   Then the behavior is completely standard.
+
+   GNU application programs can use a third alternative mode in which
+   they can distinguish the relative order of options and other arguments.  */
+
+#include "getopt.h"
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+/* 1003.2 says this must be 1 before any call.  */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+   causes problems with re-calling getopt as programs generally don't
+   know that. */
+
+int __getopt_initialized;
+
+/* The next char to be scanned in the option-element
+   in which the last option character we returned was found.
+   This allows us to pick up the scan where we left off.
+
+   If this is zero, or a null string, it means resume the scan
+   by advancing to the next ARGV-element.  */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+   for unrecognized options.  */
+
+int opterr = 1;
+
+/* Set to an option character which was unrecognized.
+   This must be initialized on some systems to avoid linking in the
+   system's own getopt implementation.  */
+
+int optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+   If the caller did not specify anything,
+   the default is REQUIRE_ORDER if the environment variable
+   POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+   REQUIRE_ORDER means don't recognize them as options;
+   stop option processing when the first non-option is seen.
+   This is what Unix does.
+   This mode of operation is selected by either setting the environment
+   variable POSIXLY_CORRECT, or using `+' as the first character
+   of the list of option characters.
+
+   PERMUTE is the default.  We permute the contents of ARGV as we scan,
+   so that eventually all the non-options are at the end.  This allows options
+   to be given in any order, even with programs that were not written to
+   expect this.
+
+   RETURN_IN_ORDER is an option available to programs that were written
+   to expect options and other ARGV-elements in any order and that care about
+   the ordering of the two.  We describe each non-option ARGV-element
+   as if it were the argument of an option with character code 1.
+   Using `-' as the first character of the list of option characters
+   selects this mode of operation.
+
+   The special argument `--' forces an end of option-scanning regardless
+   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
+   `--' can cause `getopt' to return -1 with `optind' != ARGC.  */
+
+static enum
+{
+  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable.  */
+static char *posixly_correct;
+
+#ifdef  __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+   because there are many ways it can cause trouble.
+   On some systems, it contains special magic macros that don't work
+   in GCC.  */
+# include <string.h>
+# define my_index       strchr
+#else
+
+# if HAVE_STRING_H || WIN32 /* Pete Wilson mod 7/28/02 */
+#  include <string.h>
+# else
+#  include <strings.h>
+# endif
+
+/* Avoid depending on library functions or files
+   whose names are inconsistent.  */
+
+#ifndef getenv
+extern char *getenv ();
+#endif
+
+static char *
+my_index (str, chr)
+     const char *str;
+     int chr;
+{
+  while (*str)
+    {
+      if (*str == chr)
+        return (char *) str;
+      str++;
+    }
+  return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+   If not using GCC, it is ok not to declare it.  */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+   That was relevant to code that was here before.  */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+   and has done so at least since version 2.4.5. -- rms.  */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments.  */
+
+/* Describe the part of ARGV that contains non-options that have
+   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
+   `last_nonopt' is the index after the last of them.  */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Stored original parameters.
+   XXX This is no good solution.  We should rather copy the args so
+   that we can compare them later.  But we must not use malloc(3).  */
+extern int __libc_argc;
+extern char **__libc_argv;
+
+/* Bash 2.0 gives us an environment variable containing flags
+   indicating ARGV elements that should not be considered arguments.  */
+
+# ifdef USE_NONOPTION_FLAGS
+/* Defined in getopt_init.c  */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+# endif
+
+# ifdef USE_NONOPTION_FLAGS
+#  define SWAP_FLAGS(ch1, ch2) \
+  if (nonoption_flags_len > 0)                                                \
+    {                                                                         \
+      char __tmp = __getopt_nonoption_flags[ch1];                             \
+      __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2];          \
+      __getopt_nonoption_flags[ch2] = __tmp;                                  \
+    }
+# else
+#  define SWAP_FLAGS(ch1, ch2)
+# endif
+#else   /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif  /* _LIBC */
+
+int getopt_long (int argc, char * const *argv, const char
+*options, const struct option *long_options, int *opt_index)
+{ 
+return _getopt_internal (argc, (char **) argv, options, long_options, opt_index, 0);
+ }
+/* Exchange two adjacent subsequences of ARGV.
+   One subsequence is elements [first_nonopt,last_nonopt)
+   which contains all the non-options that have been skipped so far.
+   The other is elements [last_nonopt,optind), which contains all
+   the options processed since those non-options were skipped.
+
+   `first_nonopt' and `last_nonopt' are relocated so that they describe
+   the new indices of the non-options in ARGV after they are moved.  */
+
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+     char **argv;
+{
+  int bottom = first_nonopt;
+  int middle = last_nonopt;
+  int top = optind;
+  char *tem;
+
+  /* Exchange the shorter segment with the far end of the longer segment.
+     That puts the shorter segment into the right place.
+     It leaves the longer segment in the right place overall,
+     but it consists of two parts that need to be swapped next.  */
+
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+  /* First make sure the handling of the `__getopt_nonoption_flags'
+     string can work normally.  Our top argument must be in the range
+     of the string.  */
+  if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+    {
+      /* We must extend the array.  The user plays games with us and
+         presents new arguments.  */
+      char *new_str = malloc (top + 1);
+      if (new_str == NULL)
+        nonoption_flags_len = nonoption_flags_max_len = 0;
+      else
+        {
+          memset (__mempcpy (new_str, __getopt_nonoption_flags,
+                             nonoption_flags_max_len),
+                  '\0', top + 1 - nonoption_flags_max_len);
+          nonoption_flags_max_len = top + 1;
+          __getopt_nonoption_flags = new_str;
+        }
+    }
+#endif
+
+  while (top > middle && middle > bottom)
+    {
+      if (top - middle > middle - bottom)
+        {
+          /* Bottom segment is the short one.  */
+          int len = middle - bottom;
+          register int i;
+
+          /* Swap it with the top part of the top segment.  */
+          for (i = 0; i < len; i++)
+            {
+              tem = argv[bottom + i];
+              argv[bottom + i] = argv[top - (middle - bottom) + i];
+              argv[top - (middle - bottom) + i] = tem;
+              SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+            }
+          /* Exclude the moved bottom segment from further swapping.  */
+          top -= len;
+        }
+      else
+        {
+          /* Top segment is the short one.  */
+          int len = top - middle;
+          register int i;
+
+          /* Swap it with the bottom part of the bottom segment.  */
+          for (i = 0; i < len; i++)
+            {
+              tem = argv[bottom + i];
+              argv[bottom + i] = argv[middle + i];
+              argv[middle + i] = tem;
+              SWAP_FLAGS (bottom + i, middle + i);
+            }
+          /* Exclude the moved top segment from further swapping.  */
+          bottom += len;
+        }
+    }
+
+  /* Update records for the slots the non-options now occupy.  */
+
+  first_nonopt += (optind - last_nonopt);
+  last_nonopt = optind;
+}
+
+/* Initialize the internal data when the first call is made.  */
+
+#if defined __STDC__ && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
+static const char *
+_getopt_initialize (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  /* Start processing options with ARGV-element 1 (since ARGV-element 0
+     is the program name); the sequence of previously skipped
+     non-option ARGV-elements is empty.  */
+
+  first_nonopt = last_nonopt = optind;
+
+  nextchar = NULL;
+
+  posixly_correct = getenv ("POSIXLY_CORRECT");
+
+  /* Determine how to handle the ordering of options and nonoptions.  */
+
+  if (optstring[0] == '-')
+    {
+      ordering = RETURN_IN_ORDER;
+      ++optstring;
+    }
+  else if (optstring[0] == '+')
+    {
+      ordering = REQUIRE_ORDER;
+      ++optstring;
+    }
+  else if (posixly_correct != NULL)
+    ordering = REQUIRE_ORDER;
+  else
+    ordering = PERMUTE;
+
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+  if (posixly_correct == NULL
+      && argc == __libc_argc && argv == __libc_argv)
+    {
+      if (nonoption_flags_max_len == 0)
+        {
+          if (__getopt_nonoption_flags == NULL
+              || __getopt_nonoption_flags[0] == '\0')
+            nonoption_flags_max_len = -1;
+          else
+            {
+              const char *orig_str = __getopt_nonoption_flags;
+              int len = nonoption_flags_max_len = strlen (orig_str);
+              if (nonoption_flags_max_len < argc)
+                nonoption_flags_max_len = argc;
+              __getopt_nonoption_flags =
+                (char *) malloc (nonoption_flags_max_len);
+              if (__getopt_nonoption_flags == NULL)
+                nonoption_flags_max_len = -1;
+              else
+                memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+                        '\0', nonoption_flags_max_len - len);
+            }
+        }
+      nonoption_flags_len = nonoption_flags_max_len;
+    }
+  else
+    nonoption_flags_len = 0;
+#endif
+
+  return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+   given in OPTSTRING.
+
+   If an element of ARGV starts with '-', and is not exactly "-" or "--",
+   then it is an option element.  The characters of this element
+   (aside from the initial '-') are option characters.  If `getopt'
+   is called repeatedly, it returns successively each of the option characters
+   from each of the option elements.
+
+   If `getopt' finds another option character, it returns that character,
+   updating `optind' and `nextchar' so that the next call to `getopt' can
+   resume the scan with the following option character or ARGV-element.
+
+   If there are no more option characters, `getopt' returns -1.
+   Then `optind' is the index in ARGV of the first ARGV-element
+   that is not an option.  (The ARGV-elements have been permuted
+   so that those that are not options now come last.)
+
+   OPTSTRING is a string containing the legitimate option characters.
+   If an option character is seen that is not listed in OPTSTRING,
+   return '?' after printing an error message.  If you set `opterr' to
+   zero, the error message is suppressed but we still return '?'.
+
+   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+   so the following text in the same ARGV-element, or the text of the following
+   ARGV-element, is returned in `optarg'.  Two colons mean an option that
+   wants an optional arg; if there is text in the current ARGV-element,
+   it is returned in `optarg', otherwise `optarg' is set to zero.
+
+   If OPTSTRING starts with `-' or `+', it requests different methods of
+   handling the non-option ARGV-elements.
+   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+   Long-named options begin with `--' instead of `-'.
+   Their names may be abbreviated as long as the abbreviation is unique
+   or is an exact match for some defined option.  If they have an
+   argument, it follows the option name in the same ARGV-element, separated
+   from the option name by a `=', or else the in next ARGV-element.
+   When `getopt' finds a long-named option, it returns 0 if that option's
+   `flag' field is nonzero, the value of the option's `val' field
+   if the `flag' field is zero.
+
+   The elements of ARGV aren't really const, because we permute them.
+   But we pretend they're const in the prototype to be compatible
+   with other systems.
+
+   LONGOPTS is a vector of `struct option' terminated by an
+   element containing a name which is zero.
+
+   LONGIND returns the index in LONGOPT of the long-named option found.
+   It is only valid when a long-named option has been found by the most
+   recent call.
+
+   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+   long-named options.  */
+
+int
+_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+     const struct option *longopts;
+     int *longind;
+     int long_only;
+{
+  int print_errors = opterr;
+  if (optstring[0] == ':')
+    print_errors = 0;
+
+  if (argc < 1)
+    return -1;
+
+  optarg = NULL;
+
+  if (optind == 0 || !__getopt_initialized)
+    {
+      if (optind == 0)
+        optind = 1;     /* Don't scan ARGV[0], the program name.  */
+      optstring = _getopt_initialize (argc, argv, optstring);
+      __getopt_initialized = 1;
+    }
+
+  /* Test whether ARGV[optind] points to a non-option argument.
+     Either it does not have option syntax, or there is an environment flag
+     from the shell indicating it is not an option.  The later information
+     is only used when the used in the GNU libc.  */
+#if defined _LIBC && defined USE_NONOPTION_FLAGS
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0'       \
+                      || (optind < nonoption_flags_len                        \
+                          && __getopt_nonoption_flags[optind] == '1'))
+#else
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
+  if (nextchar == NULL || *nextchar == '\0')
+    {
+      /* Advance to the next ARGV-element.  */
+
+      /* Give FIRST_NONOPT and LAST_NONOPT rational values if OPTIND has been
+         moved back by the user (who may also have changed the arguments).  */
+      if (last_nonopt > optind)
+        last_nonopt = optind;
+      if (first_nonopt > optind)
+        first_nonopt = optind;
+
+      if (ordering == PERMUTE)
+        {
+          /* If we have just processed some options following some non-options,
+             exchange them so that the options come first.  */
+
+          if (first_nonopt != last_nonopt && last_nonopt != optind)
+            exchange ((char **) argv);
+          else if (last_nonopt != optind)
+            first_nonopt = optind;
+
+          /* Skip any additional non-options
+             and extend the range of non-options previously skipped.  */
+
+          while (optind < argc && NONOPTION_P)
+            optind++;
+          last_nonopt = optind;
+        }
+
+      /* The special ARGV-element `--' means premature end of options.
+         Skip it like a null option,
+         then exchange with previous non-options as if it were an option,
+         then skip everything else like a non-option.  */
+
+      if (optind != argc && !strcmp (argv[optind], "--"))
+        {
+          optind++;
+
+          if (first_nonopt != last_nonopt && last_nonopt != optind)
+            exchange ((char **) argv);
+          else if (first_nonopt == last_nonopt)
+            first_nonopt = optind;
+          last_nonopt = argc;
+
+          optind = argc;
+        }
+
+      /* If we have done all the ARGV-elements, stop the scan
+         and back over any non-options that we skipped and permuted.  */
+
+      if (optind == argc)
+        {
+          /* Set the next-arg-index to point at the non-options
+             that we previously skipped, so the caller will digest them.  */
+          if (first_nonopt != last_nonopt)
+            optind = first_nonopt;
+          return -1;
+        }
+
+      /* If we have come to a non-option and did not permute it,
+         either stop the scan or describe it to the caller and pass it by.  */
+
+      if (NONOPTION_P)
+        {
+          if (ordering == REQUIRE_ORDER)
+            return -1;
+          optarg = argv[optind++];
+          return 1;
+        }
+
+      /* We have found another option-ARGV-element.
+         Skip the initial punctuation.  */
+
+      nextchar = (argv[optind] + 1
+                  + (longopts != NULL && argv[optind][1] == '-'));
+    }
+
+  /* Decode the current option-ARGV-element.  */
+
+  /* Check whether the ARGV-element is a long option.
+
+     If long_only and the ARGV-element has the form "-f", where f is
+     a valid short option, don't consider it an abbreviated form of
+     a long option that starts with f.  Otherwise there would be no
+     way to give the -f short option.
+
+     On the other hand, if there's a long option "fubar" and
+     the ARGV-element is "-fu", do consider that an abbreviation of
+     the long option, just like "--fu", and not "-f" with arg "u".
+
+     This distinction seems to be the most useful approach.  */
+
+  if (longopts != NULL
+      && (argv[optind][1] == '-'
+          || (long_only && (argv[optind][2] || !my_index (optstring,
+argv[optind][1])))))
+    {
+      char *nameend;
+      const struct option *p;
+      const struct option *pfound = NULL;
+      int exact = 0;
+      int ambig = 0;
+      int indfound = -1;
+      int option_index;
+
+      for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+        /* Do nothing.  */ ;
+
+      /* Test all long options for either exact match
+         or abbreviated matches.  */
+      for (p = longopts, option_index = 0; p->name; p++, option_index++)
+        if (!strncmp (p->name, nextchar, nameend - nextchar))
+          {
+            if ((unsigned int) (nameend - nextchar)
+                == (unsigned int) strlen (p->name))
+              {
+                /* Exact match found.  */
+                pfound = p;
+                indfound = option_index;
+                exact = 1;
+                break;
+              }
+            else if (pfound == NULL)
+              {
+                /* First nonexact match found.  */
+                pfound = p;
+                indfound = option_index;
+              }
+            else if (long_only
+                     || pfound->has_arg != p->has_arg
+                     || pfound->flag != p->flag
+                     || pfound->val != p->val)
+              /* Second or later nonexact match found.  */
+              ambig = 1;
+          }
+
+      if (ambig && !exact)
+        {
+          if (print_errors)
+            {
+#if defined _LIBC && defined USE_IN_LIBIO
+              char *buf;
+
+              __asprintf (&buf, _("%s: option `%s' is ambiguous\n"),
+                          argv[0], argv[optind]);
+
+              if (_IO_fwide (stderr, 0) > 0)
+                __fwprintf (stderr, L"%s", buf);
+              else
+                fputs (buf, stderr);
+
+              free (buf);
+#else
+              fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+                       argv[0], argv[optind]);
+#endif
+            }
+          nextchar += strlen (nextchar);
+          optind++;
+          optopt = 0;
+          return '?';
+        }
+
+      if (pfound != NULL)
+        {
+          option_index = indfound;
+          optind++;
+          if (*nameend)
+            {
+              /* Don't test has_arg with >, because some C compilers don't
+                 allow it to be used on enums.  */
+              if (pfound->has_arg)
+                optarg = nameend + 1;
+              else
+                {
+                  if (print_errors)
+                    {
+#if defined _LIBC && defined USE_IN_LIBIO
+                      char *buf;
+#endif
+
+                      if (argv[optind - 1][1] == '-')
+                        {
+                          /* --option */
+#if defined _LIBC && defined USE_IN_LIBIO
+                          __asprintf (&buf, _("\
+%s: option `--%s' doesn't allow an argument\n"),
+                                      argv[0], pfound->name);
+#else
+                          fprintf (stderr, _("\
+%s: option `--%s' doesn't allow an argument\n"),
+                                   argv[0], pfound->name);
+#endif
+                        }
+                      else
+                        {
+                          /* +option or -option */
+#if defined _LIBC && defined USE_IN_LIBIO
+                          __asprintf (&buf, _("\
+%s: option `%c%s' doesn't allow an argument\n"),
+                                      argv[0], argv[optind - 1][0],
+                                      pfound->name);
+#else
+                          fprintf (stderr, _("\
+%s: option `%c%s' doesn't allow an argument\n"),
+                                   argv[0], argv[optind - 1][0], pfound->name);
+#endif
+                        }
+
+#if defined _LIBC && defined USE_IN_LIBIO
+                      if (_IO_fwide (stderr, 0) > 0)
+                        __fwprintf (stderr, L"%s", buf);
+                      else
+                        fputs (buf, stderr);
+
+                      free (buf);
+#endif
+                    }
+
+                  nextchar += strlen (nextchar);
+
+                  optopt = pfound->val;
+                  return '?';
+                }
+            }
+          else if (pfound->has_arg == 1)
+            {
+              if (optind < argc)
+                optarg = argv[optind++];
+              else
+                {
+                  if (print_errors)
+                    {
+#if defined _LIBC && defined USE_IN_LIBIO
+                      char *buf;
+
+                      __asprintf (&buf,
+                                  _("%s: option `%s' requires an argument\n"),
+                                  argv[0], argv[optind - 1]);
+
+                      if (_IO_fwide (stderr, 0) > 0)
+                        __fwprintf (stderr, L"%s", buf);
+                      else
+                        fputs (buf, stderr);
+
+                      free (buf);
+#else
+                      fprintf (stderr,
+                               _("%s: option `%s' requires an argument\n"),
+                               argv[0], argv[optind - 1]);
+#endif
+                    }
+                  nextchar += strlen (nextchar);
+                  optopt = pfound->val;
+                  return optstring[0] == ':' ? ':' : '?';
+                }
+            }
+          nextchar += strlen (nextchar);
+          if (longind != NULL)
+            *longind = option_index;
+          if (pfound->flag)
+            {
+              *(pfound->flag) = pfound->val;
+              return 0;
+            }
+          return pfound->val;
+        }
+
+      /* Can't find it as a long option.  If this is not getopt_long_only,
+         or the option starts with '--' or is not a valid short
+         option, then it's an error.
+         Otherwise interpret it as a short option.  */
+      if (!long_only || argv[optind][1] == '-'
+          || my_index (optstring, *nextchar) == NULL)
+        {
+          if (print_errors)
+            {
+#if defined _LIBC && defined USE_IN_LIBIO
+              char *buf;
+#endif
+
+              if (argv[optind][1] == '-')
+                {
+                  /* --option */
+#if defined _LIBC && defined USE_IN_LIBIO
+                  __asprintf (&buf, _("%s: unrecognized option `--%s'\n"),
+                              argv[0], nextchar);
+#else
+                  fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+                           argv[0], nextchar);
+#endif
+                }
+              else
+                {
+                  /* +option or -option */
+#if defined _LIBC && defined USE_IN_LIBIO
+                  __asprintf (&buf, _("%s: unrecognized option `%c%s'\n"),
+                              argv[0], argv[optind][0], nextchar);
+#else
+                  fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+                           argv[0], argv[optind][0], nextchar);
+#endif
+                }
+
+#if defined _LIBC && defined USE_IN_LIBIO
+              if (_IO_fwide (stderr, 0) > 0)
+                __fwprintf (stderr, L"%s", buf);
+              else
+                fputs (buf, stderr);
+
+              free (buf);
+#endif
+            }
+          nextchar = (char *) "";
+          optind++;
+          optopt = 0;
+          return '?';
+        }
+    }
+
+  /* Look at and handle the next short option-character.  */
+
+  {
+    char c = *nextchar++;
+    char *temp = my_index (optstring, c);
+
+    /* Increment `optind' when we start to process its last character.  */
+    if (*nextchar == '\0')
+      ++optind;
+
+    if (temp == NULL || c == ':')
+      {
+        if (print_errors)
+          {
+#if defined _LIBC && defined USE_IN_LIBIO
+              char *buf;
+#endif
+
+            if (posixly_correct)
+              {
+                /* 1003.2 specifies the format of this message.  */
+#if defined _LIBC && defined USE_IN_LIBIO
+                __asprintf (&buf, _("%s: illegal option -- %c\n"),
+                            argv[0], c);
+#else
+                fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c);
+#endif
+              }
+            else
+              {
+#if defined _LIBC && defined USE_IN_LIBIO
+                __asprintf (&buf, _("%s: invalid option -- %c\n"),
+                            argv[0], c);
+#else
+                fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c);
+#endif
+              }
+
+#if defined _LIBC && defined USE_IN_LIBIO
+            if (_IO_fwide (stderr, 0) > 0)
+              __fwprintf (stderr, L"%s", buf);
+            else
+              fputs (buf, stderr);
+
+            free (buf);
+#endif
+          }
+        optopt = c;
+        return '?';
+      }
+    /* Convenience. Treat POSIX -W foo same as long option --foo */
+    if (temp[0] == 'W' && temp[1] == ';')
+      {
+        char *nameend;
+        const struct option *p;
+        const struct option *pfound = NULL;
+        int exact = 0;
+        int ambig = 0;
+        int indfound = 0;
+        int option_index;
+
+        /* This is an option that requires an argument.  */
+        if (*nextchar != '\0')
+          {
+            optarg = nextchar;
+            /* If we end this ARGV-element by taking the rest as an arg,
+               we must advance to the next element now.  */
+            optind++;
+          }
+        else if (optind == argc)
+          {
+            if (print_errors)
+              {
+                /* 1003.2 specifies the format of this message.  */
+#if defined _LIBC && defined USE_IN_LIBIO
+                char *buf;
+
+                __asprintf (&buf, _("%s: option requires an argument -- %c\n"),
+                            argv[0], c);
+
+                if (_IO_fwide (stderr, 0) > 0)
+                  __fwprintf (stderr, L"%s", buf);
+                else
+                  fputs (buf, stderr);
+
+                free (buf);
+#else
+                fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+                         argv[0], c);
+#endif
+              }
+            optopt = c;
+            if (optstring[0] == ':')
+              c = ':';
+            else
+              c = '?';
+            return c;
+          }
+        else
+          /* We already incremented `optind' once;
+             increment it again when taking next ARGV-elt as argument.  */
+          optarg = argv[optind++];
+
+        /* optarg is now the argument, see if it's in the
+           table of longopts.  */
+
+        for (nextchar = nameend = optarg; *nameend && *nameend != '=';
+nameend++)
+          /* Do nothing.  */ ;
+
+        /* Test all long options for either exact match
+           or abbreviated matches.  */
+        for (p = longopts, option_index = 0; p->name; p++, option_index++)
+          if (!strncmp (p->name, nextchar, nameend - nextchar))
+            {
+              if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+                {
+                  /* Exact match found.  */
+                  pfound = p;
+                  indfound = option_index;
+                  exact = 1;
+                  break;
+                }
+              else if (pfound == NULL)
+                {
+                  /* First nonexact match found.  */
+                  pfound = p;
+                  indfound = option_index;
+                }
+              else
+                /* Second or later nonexact match found.  */
+                ambig = 1;
+            }
+        if (ambig && !exact)
+          {
+            if (print_errors)
+              {
+#if defined _LIBC && defined USE_IN_LIBIO
+                char *buf;
+
+                __asprintf (&buf, _("%s: option `-W %s' is ambiguous\n"),
+                            argv[0], argv[optind]);
+
+                if (_IO_fwide (stderr, 0) > 0)
+                  __fwprintf (stderr, L"%s", buf);
+                else
+                  fputs (buf, stderr);
+
+                free (buf);
+#else
+                fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+                         argv[0], argv[optind]);
+#endif
+              }
+            nextchar += strlen (nextchar);
+            optind++;
+            return '?';
+          }
+        if (pfound != NULL)
+          {
+            option_index = indfound;
+            if (*nameend)
+              {
+                /* Don't test has_arg with >, because some C compilers don't
+                   allow it to be used on enums.  */
+                if (pfound->has_arg)
+                  optarg = nameend + 1;
+                else
+                  {
+                    if (print_errors)
+                      {
+#if defined _LIBC && defined USE_IN_LIBIO
+                        char *buf;
+
+                        __asprintf (&buf, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+                                    argv[0], pfound->name);
+
+                        if (_IO_fwide (stderr, 0) > 0)
+                          __fwprintf (stderr, L"%s", buf);
+                        else
+                          fputs (buf, stderr);
+
+                        free (buf);
+#else
+                        fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+                                 argv[0], pfound->name);
+#endif
+                      }
+
+                    nextchar += strlen (nextchar);
+                    return '?';
+                  }
+              }
+            else if (pfound->has_arg == 1)
+              {
+                if (optind < argc)
+                  optarg = argv[optind++];
+                else
+                  {
+                    if (print_errors)
+                      {
+#if defined _LIBC && defined USE_IN_LIBIO
+                        char *buf;
+
+                        __asprintf (&buf, _("\
+%s: option `%s' requires an argument\n"),
+                                    argv[0], argv[optind - 1]);
+
+                        if (_IO_fwide (stderr, 0) > 0)
+                          __fwprintf (stderr, L"%s", buf);
+                        else
+                          fputs (buf, stderr);
+
+                        free (buf);
+#else
+                        fprintf (stderr,
+                                 _("%s: option `%s' requires an argument\n"),
+                                 argv[0], argv[optind - 1]);
+#endif
+                      }
+                    nextchar += strlen (nextchar);
+                    return optstring[0] == ':' ? ':' : '?';
+                  }
+              }
+            nextchar += strlen (nextchar);
+            if (longind != NULL)
+              *longind = option_index;
+            if (pfound->flag)
+              {
+                *(pfound->flag) = pfound->val;
+                return 0;
+              }
+            return pfound->val;
+          }
+          nextchar = NULL;
+          return 'W';   /* Let the application handle it.   */
+      }
+    if (temp[1] == ':')
+      {
+        if (temp[2] == ':')
+          {
+            /* This is an option that accepts an argument optionally.  */
+            if (*nextchar != '\0')
+              {
+                optarg = nextchar;
+                optind++;
+              }
+            else
+              optarg = NULL;
+            nextchar = NULL;
+          }
+        else
+          {
+            /* This is an option that requires an argument.  */
+            if (*nextchar != '\0')
+              {
+                optarg = nextchar;
+                /* If we end this ARGV-element by taking the rest as an arg,
+                   we must advance to the next element now.  */
+                optind++;
+              }
+            else if (optind == argc)
+              {
+                if (print_errors)
+                  {
+                    /* 1003.2 specifies the format of this message.  */
+#if defined _LIBC && defined USE_IN_LIBIO
+                    char *buf;
+
+                    __asprintf (&buf,
+                                _("%s: option requires an argument -- %c\n"),
+                                argv[0], c);
+
+                    if (_IO_fwide (stderr, 0) > 0)
+                      __fwprintf (stderr, L"%s", buf);
+                    else
+                      fputs (buf, stderr);
+
+                    free (buf);
+#else
+                    fprintf (stderr,
+                             _("%s: option requires an argument -- %c\n"),
+                             argv[0], c);
+#endif
+                  }
+                optopt = c;
+                if (optstring[0] == ':')
+                  c = ':';
+                else
+                  c = '?';
+              }
+            else
+              /* We already incremented `optind' once;
+                 increment it again when taking next ARGV-elt as argument.  */
+              optarg = argv[optind++];
+            nextchar = NULL;
+          }
+      }
+    return c;
+  }
+}
+
+int
+getopt (argc, argv, optstring)
+     int argc;
+     char *const *argv;
+     const char *optstring;
+{
+  return _getopt_internal (argc, argv, optstring,
+                           (const struct option *) 0,
+                           (int *) 0,
+                           0);
+}
+
+#endif  /* Not ELIDE_CODE.  */
+
+
+/* Compile with -DTEST to make an executable for use in testing
+   the above definition of `getopt'.  */
+
+/* #define TEST */        /* Pete Wilson mod 7/28/02 */
+#ifdef TEST
+
+#ifndef exit         /* Pete Wilson mod 7/28/02 */
+  int exit(int);     /* Pete Wilson mod 7/28/02 */
+#endif               /* Pete Wilson mod 7/28/02 */
+
+int
+main (argc, argv)
+     int argc;
+     char **argv;
+{
+  int c;
+  int digit_optind = 0;
+
+  while (1)
+    {
+      int this_option_optind = optind ? optind : 1;
+
+      c = getopt (argc, argv, "abc:d:0123456789");
+      if (c == -1)
+        break;
+
+      switch (c)
+        {
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+          if (digit_optind != 0 && digit_optind != this_option_optind)
+            printf ("digits occur in two different argv-elements.\n");
+          digit_optind = this_option_optind;
+          printf ("option %c\n", c);
+          break;
+
+        case 'a':
+          printf ("option a\n");
+          break;
+
+        case 'b':
+          printf ("option b\n");
+          break;
+
+        case 'c':
+          printf ("option c with value `%s'\n", optarg);
+          break;
+
+        case '?':
+          break;
+
+        default:
+          printf ("?? getopt returned character code 0%o ??\n", c);
+        }
+    }
+
+  if (optind < argc)
+    {
+      printf ("non-option ARGV-elements: ");
+      while (optind < argc)
+        printf ("%s ", argv[optind++]);
+      printf ("\n");
+    }
+
+  exit (0);
+}
+
+#endif /* TEST */
+
diff --git a/getopt.h b/getopt.h
new file mode 100644 (file)
index 0000000..e3420f3
--- /dev/null
+++ b/getopt.h
@@ -0,0 +1,189 @@
+
+/* getopt.h */
+/* Declarations for getopt.
+   Copyright (C) 1989-1994, 1996-1999, 2001 Free Software 
+   Foundation, Inc. This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute 
+   it and/or modify it under the terms of the GNU Lesser 
+   General Public License as published by the Free Software 
+   Foundation; either version 2.1 of the License, or 
+   (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will 
+   be useful, but WITHOUT ANY WARRANTY; without even the 
+   implied warranty of MERCHANTABILITY or FITNESS FOR A 
+   PARTICULAR PURPOSE.  See the GNU Lesser General Public 
+   License for more details.
+
+   You should have received a copy of the GNU Lesser General 
+   Public License along with the GNU C Library; if not, write 
+   to the Free Software Foundation, Inc., 59 Temple Place,
+   Suite 330, Boston, MA 02111-1307 USA.  */
+
+  
+
+  
+
+#ifndef _GETOPT_H
+
+#ifndef __need_getopt
+# define _GETOPT_H 1
+#endif
+
+/* If __GNU_LIBRARY__ is not already defined, either we are being used
+   standalone, or this is the first header included in the source file.
+   If we are being used with glibc, we need to include <features.h>, but
+   that does not exist if we are standalone.  So: if __GNU_LIBRARY__ is
+   not defined, include <ctype.h>, which will pull in <features.h> for us
+   if it's from glibc.  (Why ctype.h?  It's guaranteed to exist and it
+   doesn't flood the namespace with stuff the way some other headers do.)  */
+#if !defined __GNU_LIBRARY__
+# include <ctype.h>
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `getopt' to the caller.
+   When `getopt' finds an option that takes an argument,
+   the argument value is returned here.
+   Also, when `ordering' is RETURN_IN_ORDER,
+   each non-option ARGV-element is returned here.  */
+
+extern char *optarg;
+
+/* Index in ARGV of the next element to be scanned.
+   This is used for communication to and from the caller
+   and for communication between successive calls to `getopt'.
+
+   On entry to `getopt', zero means this is the first call; initialize.
+
+   When `getopt' returns -1, this is the index of the first of the
+   non-option elements that the caller should itself scan.
+
+   Otherwise, `optind' communicates from one call to the next
+   how much of ARGV has been scanned so far.  */
+
+extern int optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+   for unrecognized options.  */
+
+extern int opterr;
+
+/* Set to an option character which was unrecognized.  */
+
+extern int optopt;
+
+#ifndef __need_getopt
+/* Describe the long-named options requested by the application.
+   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
+   of `struct option' terminated by an element containing a name which is
+   zero.
+
+   The field `has_arg' is:
+   no_argument          (or 0) if the option does not take an argument,
+   required_argument    (or 1) if the option requires an argument,
+   optional_argument    (or 2) if the option takes an optional argument.
+
+   If the field `flag' is not NULL, it points to a variable that is set
+   to the value given in the field `val' when the option is found, but
+   left unchanged if the option is not found.
+
+   To have a long-named option do something other than set an `int' to
+   a compiled-in constant, such as set a value from `optarg', set the
+   option's `flag' field to zero and its `val' field to a nonzero
+   value (the equivalent single-letter option character, if there is
+   one).  For long options that have a zero `flag' field, `getopt'
+   returns the contents of the `val' field.  */
+
+struct option
+{
+# if (defined __STDC__ && __STDC__) || defined __cplusplus
+  const char *name;
+# else
+  char *name;
+# endif
+  /* has_arg can't be an enum because some compilers complain about
+     type mismatches in all the code that assumes it is an int.  */
+  int has_arg;
+  int *flag;
+  int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct option'.  */
+
+# define no_argument            0
+# define required_argument      1
+# define optional_argument      2
+#endif  /* need getopt */
+
+
+/* Get definitions and prototypes for functions to process the
+   arguments in ARGV (ARGC of them, minus the program name) for
+   options given in OPTS.
+
+   Return the option character from OPTS just read.  Return -1 when
+   there are no more options.  For unrecognized options, or options
+   missing arguments, `optopt' is set to the option letter, and '?' is
+   returned.
+
+   The OPTS string is a list of characters which are recognized option
+   letters, optionally followed by colons, specifying that that letter
+   takes an argument, to be placed in `optarg'.
+
+   If a letter in OPTS is followed by two colons, its argument is
+   optional.  This behavior is specific to the GNU `getopt'.
+
+   The argument `--' causes premature termination of argument
+   scanning, explicitly telling `getopt' that there are no more
+   options.
+
+   If OPTS begins with `--', then non-option arguments are treated as
+   arguments to the option '\0'.  This behavior is specific to the GNU
+   `getopt'.  */
+
+#if (defined __STDC__ && __STDC__) || defined __cplusplus
+# ifdef __GNU_LIBRARY__
+/* Many other libraries have conflicting prototypes for getopt, with
+   differences in the consts, in stdlib.h.  To avoid compilation
+   errors, only prototype getopt for the GNU C library.  */
+extern int getopt (int ___argc, char *const *___argv, const char *__shortopts);
+# else /* not __GNU_LIBRARY__ */
+extern int getopt ();
+# endif /* __GNU_LIBRARY__ */
+
+# ifndef __need_getopt
+extern int getopt_long (int ___argc, char *const *___argv,
+                        const char *__shortopts,
+                        const struct option *__longopts, int *__longind);
+extern int getopt_long_only (int ___argc, char *const *___argv,
+                             const char *__shortopts,
+                             const struct option *__longopts, int *__longind);
+
+/* Internal only.  Users should not call this directly.  */
+extern int _getopt_internal (int ___argc, char *const *___argv,
+                             const char *__shortopts,
+                             const struct option *__longopts, int *__longind,
+                             int __long_only);
+# endif
+#else /* not __STDC__ */
+extern int getopt ();
+# ifndef __need_getopt
+extern int getopt_long ();
+extern int getopt_long_only ();
+
+extern int _getopt_internal ();
+# endif
+#endif /* __STDC__ */
+
+#ifdef  __cplusplus
+}
+#endif
+
+/* Make sure we later can get all the definitions and declarations.  */
+#undef __need_getopt
+
+#endif /* getopt.h */
diff --git a/main.cpp b/main.cpp
new file mode 100644 (file)
index 0000000..168f96b
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,328 @@
+/*
+   main.cpp - A (not yet) secure Qt 4 dialog for PIN entry.
+
+   Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB)
+   Copyright (C) 2003 g10 Code GmbH
+   Copyright 2007 Ingo Klöcker
+
+   Written by Steffen Hansen <steffen@klaralvdalens-datakonsult.se>.
+   Modified by Marcus Brinkmann <marcus@g10code.de>.
+   Modified by Marc Mutz <marc@kdab.com>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pinentrydialog.h"
+#include "pinentry.h"
+
+#include <qapplication.h>
+#include <QIcon>
+#include <QString>
+#include <qwidget.h>
+#include <qmessagebox.h>
+#include <QPushButton>
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef HAVE_W32CE_SYSTEM
+#include <errno.h>
+#endif
+
+#include <memory>
+#include <stdexcept>
+
+#ifdef FALLBACK_CURSES
+#include <pinentry-curses.h>
+#endif
+
+static QString escape_accel( const QString & s ) {
+
+  QString result;
+  result.reserve( s.size() );
+
+  bool afterUnderscore = false;
+
+  for ( unsigned int i = 0, end = s.size() ; i != end ; ++i ) {
+    const QChar ch = s[i];
+    if ( ch == QLatin1Char( '_' ) )
+      {
+        if ( afterUnderscore ) // escaped _
+          {
+            result += QLatin1Char( '_' );
+            afterUnderscore = false;
+          }
+        else // accel
+          {
+            afterUnderscore = true;
+          }
+      }
+    else
+      {
+        if ( afterUnderscore || // accel
+             ch == QLatin1Char( '&' ) ) // escape & from being interpreted by Qt
+          result += QLatin1Char( '&' );
+        result += ch;
+        afterUnderscore = false;
+      }
+  }
+
+  if ( afterUnderscore )
+    // trailing single underscore: shouldn't happen, but deal with it robustly:
+    result += QLatin1Char( '_' );
+
+  return result;
+}
+
+/* Hack for creating a QWidget with a "foreign" window ID */
+class ForeignWidget : public QWidget
+{
+public:
+  explicit ForeignWidget( WId wid ) : QWidget( 0 )
+  {
+    QWidget::destroy();
+    create( wid, false, false );
+  }
+
+  ~ForeignWidget()
+  {
+    destroy( false, false );
+  }
+};
+
+namespace {
+    class InvalidUtf8 : public std::invalid_argument {
+    public:
+        InvalidUtf8() : std::invalid_argument( "invalid utf8" ) {}
+        ~InvalidUtf8() throw() {}
+    };
+}
+
+static const bool GPG_AGENT_IS_PORTED_TO_ONLY_SEND_UTF8 = false;
+
+static QString from_utf8( const char * s ) {
+    const QString result = QString::fromUtf8( s );
+    if ( result.contains( QChar::ReplacementCharacter ) )
+      {
+        if ( GPG_AGENT_IS_PORTED_TO_ONLY_SEND_UTF8 )
+            throw InvalidUtf8();
+        else
+            return QString::fromLocal8Bit( s );
+      }
+    
+    return result;
+}
+
+static int
+qt_cmd_handler (pinentry_t pe)
+{
+  QWidget *parent = 0;
+
+  /* FIXME: Add parent window ID to pinentry and GTK.  */
+  if (pe->parent_wid)
+    parent = new ForeignWidget ((WId) pe->parent_wid);
+
+  int want_pass = !!pe->pin;
+
+  const QString ok =
+      pe->ok             ? escape_accel( from_utf8( pe->ok ) ) :
+      pe->default_ok     ? escape_accel( from_utf8( pe->default_ok ) ) :
+      /* else */           QLatin1String( "&OK" ) ;
+  const QString cancel =
+      pe->cancel         ? escape_accel( from_utf8( pe->cancel ) ) :
+      pe->default_cancel ? escape_accel( from_utf8( pe->default_cancel ) ) :
+      /* else */           QLatin1String( "&Cancel" ) ;
+  const QString title =
+      pe->title ? from_utf8( pe->title ) :
+      /* else */  QLatin1String( "pinentry-qt4" ) ;
+      
+
+  if (want_pass)
+    {
+      PinEntryDialog pinentry (parent, 0, true, !!pe->quality_bar);
+
+      pinentry.setPinentryInfo (pe);
+      pinentry.setPrompt (escape_accel (from_utf8 (pe->prompt)) );
+      pinentry.setDescription (from_utf8 (pe->description));
+      if ( pe->title )
+          pinentry.setWindowTitle( from_utf8( pe->title ) );
+
+      /* If we reuse the same dialog window.  */
+      pinentry.setPin (secqstring());
+
+      pinentry.setOkText (ok);
+      pinentry.setCancelText (cancel);
+      if (pe->error)
+       pinentry.setError (from_utf8 (pe->error));
+      if (pe->quality_bar)
+       pinentry.setQualityBar (from_utf8 (pe->quality_bar));
+      if (pe->quality_bar_tt)
+       pinentry.setQualityBarTT (from_utf8 (pe->quality_bar_tt));
+
+      bool ret = pinentry.exec ();
+      if (!ret)
+       return -1;
+
+      const secstring pinUtf8(pinentry.pin().toUtf8());
+      const char *pin = pinUtf8.data();
+
+      int len = strlen (pin);
+      if (len >= 0)
+       {
+         pinentry_setbufferlen (pe, len + 1);
+         if (pe->pin)
+           {
+             strcpy (pe->pin, pin);
+             return len;
+           }
+       }
+      return -1;
+    }
+  else
+    {
+      const QString desc  = pe->description ? from_utf8 ( pe->description ) : QString();
+      const QString notok = pe->notok       ? escape_accel (from_utf8 ( pe->notok )) : QString();
+
+      const QMessageBox::StandardButtons buttons =
+          pe->one_button ? QMessageBox::Ok :
+          pe->notok      ? QMessageBox::Yes|QMessageBox::No|QMessageBox::Cancel :
+          /* else */       QMessageBox::Ok|QMessageBox::Cancel ;
+
+      QMessageBox box( QMessageBox::Information, title, desc, buttons, parent );
+
+      const struct {
+          QMessageBox::StandardButton button;
+          QString label;
+      } buttonLabels[] = {
+          { QMessageBox::Ok,     ok     },
+          { QMessageBox::Yes,    ok     },
+          { QMessageBox::No,     notok  },
+          { QMessageBox::Cancel, cancel },
+      };
+
+      for ( size_t i = 0 ; i < sizeof buttonLabels / sizeof *buttonLabels ; ++i )
+        if ( (buttons & buttonLabels[i].button) && !buttonLabels[i].label.isEmpty() )
+            box.button( buttonLabels[i].button )->setText( buttonLabels[i].label );
+
+      box.setIconPixmap( icon() );
+
+      if ( !pe->one_button )
+        box.setDefaultButton( QMessageBox::Cancel );
+
+      box.show();
+      raiseWindow( &box );
+
+      const int rc = box.exec();
+
+      if ( rc == QMessageBox::Cancel )
+        pe->canceled = true;
+
+      return rc == QMessageBox::Ok || rc == QMessageBox::Yes ;
+
+    }
+}
+
+static int
+qt_cmd_handler_ex (pinentry_t pe)
+{
+  try {
+    return qt_cmd_handler (pe);
+  } catch ( const InvalidUtf8 & ) {
+    pe->locale_err = true;
+    return pe->pin ? -1 : false ;
+  } catch ( ... ) {
+    pe->canceled = true;
+    return pe->pin ? -1 : false ;
+  }
+}
+
+pinentry_cmd_handler_t pinentry_cmd_handler = qt_cmd_handler_ex;
+
+int
+main (int argc, char *argv[])
+{
+  pinentry_init ("pinentry-qt4");
+
+  std::auto_ptr<QApplication> app;
+
+#ifdef FALLBACK_CURSES
+  if (!pinentry_have_display (argc, argv))
+    pinentry_cmd_handler = curses_cmd_handler;
+  else
+#endif
+    {
+      /* Qt does only understand -display but not --display; thus we
+         are fixing that here.  The code is pretty simply and may get
+         confused if an argument is called "--display". */
+      char **new_argv, *p;
+      size_t n;
+      int i, done;
+
+      for (n=0,i=0; i < argc; i++)
+        n += strlen (argv[i])+1;
+      n++;
+      new_argv = (char**)calloc (argc+1, sizeof *new_argv);
+      if (new_argv)
+        *new_argv = (char*)malloc (n);
+      if (!new_argv || !*new_argv)
+        {
+#ifndef HAVE_W32CE_SYSTEM
+          fprintf (stderr, "pinentry-qt4: can't fixup argument list: %s\n",
+                   strerror (errno));
+#else
+          /* Since WinCE does not show the stderr output we leave out a 
+             GetLastError() message */
+          fprintf (stderr, "pinentry-qt4: can't fixup argument list"); 
+#endif
+          exit (EXIT_FAILURE);
+
+        }
+      for (done=0,p=*new_argv,i=0; i < argc; i++)
+        if (!done && !strcmp (argv[i], "--display"))
+          {
+            new_argv[i] = strcpy (p, argv[i]+1);
+            p += strlen (argv[i]+1) + 1;
+            done = 1;
+          }
+        else
+          {
+            new_argv[i] = strcpy (p, argv[i]);
+            p += strlen (argv[i]) + 1;
+          }
+
+      /* We use a modal dialog window, so we don't need the application
+         window anymore.  */
+      i = argc;
+      app.reset (new QApplication (i, new_argv));
+      const QIcon icon( QLatin1String( ":/document-encrypt.png" ) );
+      app->setWindowIcon( icon );
+    }
+
+
+  /* Consumes all arguments.  */
+  if (pinentry_parse_opts (argc, argv))
+    {
+      printf ("pinentry-qt4 (pinentry) " /* VERSION */ "\n");
+      return EXIT_SUCCESS;
+    }
+  else
+    {
+      return pinentry_loop () ? EXIT_FAILURE : EXIT_SUCCESS ;
+    }
+
+}
diff --git a/memory.h b/memory.h
new file mode 100644 (file)
index 0000000..9311c28
--- /dev/null
+++ b/memory.h
@@ -0,0 +1,57 @@
+/* Quintuple Agent secure memory allocation
+ * Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ * Copyright (C) 1999,2000 Robert Bihlmeyer <robbe@orcus.priv.at>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _MEMORY_H
+#define _MEMORY_H
+
+#ifndef HAVE_W32CE_SYSTEM
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#if 0 
+}
+#endif
+#endif
+
+
+/* values for flags, hardcoded in secmem.c */
+#define SECMEM_WARN            0
+#define SECMEM_DONT_WARN       1
+#define SECMEM_SUSPEND_WARN    2
+
+void secmem_init( size_t npool );
+void secmem_term( void );
+void *secmem_malloc( size_t size );
+void *secmem_realloc( void *a, size_t newsize );
+void secmem_free( void *a );
+int  m_is_secure( const void *p );
+void secmem_dump_stats(void);
+void secmem_set_flags( unsigned flags );
+unsigned secmem_get_flags(void);
+size_t secmem_get_max_size (void);
+
+#if 0 
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif /* _MEMORY_H */
diff --git a/pinentry.c b/pinentry.c
new file mode 100644 (file)
index 0000000..d3701ae
--- /dev/null
@@ -0,0 +1,1132 @@
+/* pinentry.c - The PIN entry support library
+   Copyright (C) 2002, 2003, 2007, 2008, 2010 g10 Code GmbH
+   
+   This file is part of PINENTRY.
+   
+   PINENTRY is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   PINENTRY is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifndef HAVE_W32CE_SYSTEM
+# include <errno.h>
+# include <locale.h>
+# include <unistd.h>
+#else
+# define STDIN_FILENO 0
+# define STDOUT_FILENO 1
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#ifdef HAVE_LANGINFO_H
+#include <langinfo.h>
+#endif
+#include <limits.h>
+#ifdef HAVE_W32CE_SYSTEM
+# include <windows.h>
+#endif
+
+#if defined FALLBACK_CURSES || defined PINENTRY_CURSES || defined PINENTRY_GTK
+#include <iconv.h>
+#endif
+
+#include "assuan.h"
+#include "memory.h"
+#include "secmem-util.h"
+#include "pinentry.h"
+
+#ifdef HAVE_W32CE_SYSTEM
+#define getpid() GetCurrentProcessId ()
+#endif
+
+/* Keep the name of our program here. */
+static char this_pgmname[50]; 
+
+
+struct pinentry pinentry =
+  {
+    NULL,      /* Title.  */
+    NULL,      /* Description.  */
+    NULL,      /* Error.  */
+    NULL,      /* Prompt.  */
+    NULL,      /* Ok button.  */
+    NULL,      /* Not-Ok button.  */
+    NULL,      /* Cancel button.  */
+    NULL,      /* PIN.  */
+    2048,      /* PIN length.  */
+    0,         /* Display.  */
+    0,         /* TTY name.  */
+    0,         /* TTY type.  */
+    0,         /* TTY LC_CTYPE.  */
+    0,         /* TTY LC_MESSAGES.  */
+    0,         /* Debug mode.  */
+#ifdef ENABLE_ENHANCED
+    0,         /* Enhanced mode.  */
+#endif
+    1,         /* Global grab.  */
+    0,         /* Parent Window ID.  */
+    NULL,       /* Touch file.  */
+    0,         /* Result.  */
+    0,         /* Result Not-OK.  */
+    0,          /* Locale error flag. */
+    0,          /* One-button flag.  */
+    NULL,       /* Quality-Bar flag and description.  */
+    NULL,       /* Quality-Bar tooltip.  */
+    PINENTRY_COLOR_DEFAULT,
+    0,
+    PINENTRY_COLOR_DEFAULT,
+    PINENTRY_COLOR_DEFAULT,
+    0,
+    NULL,        /* default_ok  */
+    NULL,        /* default_cancel  */
+    NULL,        /* default_prompt  */
+    NULL         /* Assuan context.  */
+  };
+
+\f
+#if defined FALLBACK_CURSES || defined PINENTRY_CURSES || defined PINENTRY_GTK
+char *
+pinentry_utf8_to_local (char *lc_ctype, char *text)
+{
+  iconv_t cd;
+  const char *input = text;
+  size_t input_len = strlen (text) + 1;
+  char *output;
+  size_t output_len;
+  char *output_buf;
+  size_t processed;
+  char *old_ctype;
+  char *target_encoding;
+
+  /* If no locale setting could be determined, simply copy the
+     string.  */
+  if (!lc_ctype)
+    {
+      fprintf (stderr, "%s: no LC_CTYPE known - assuming UTF-8\n",
+               this_pgmname);
+      return strdup (text);
+    }
+
+  old_ctype = strdup (setlocale (LC_CTYPE, NULL));
+  if (!old_ctype)
+    return NULL;
+  setlocale (LC_CTYPE, lc_ctype);
+  target_encoding = nl_langinfo (CODESET);
+  if (!target_encoding)
+    target_encoding = "?";
+  setlocale (LC_CTYPE, old_ctype);
+  free (old_ctype);
+
+  /* This is overkill, but simplifies the iconv invocation greatly.  */
+  output_len = input_len * MB_LEN_MAX;
+  output_buf = output = malloc (output_len);
+  if (!output)
+    return NULL;
+
+  cd = iconv_open (target_encoding, "UTF-8");
+  if (cd == (iconv_t) -1)
+    {
+      fprintf (stderr, "%s: can't convert from UTF-8 to %s: %s\n",
+               this_pgmname, target_encoding, strerror (errno));
+      free (output_buf);
+      return NULL;
+    }
+  processed = iconv (cd, &input, &input_len, &output, &output_len);
+  iconv_close (cd);
+  if (processed == (size_t) -1 || input_len)
+    {
+      fprintf (stderr, "%s: error converting from UTF-8 to %s: %s\n",
+               this_pgmname, target_encoding, strerror (errno));
+      free (output_buf);
+      return NULL;
+    }
+  return output_buf;
+}
+
+/* Convert TEXT which is encoded according to LC_CTYPE to UTF-8.  With
+   SECURE set to true, use secure memory for the returned buffer.
+   Return NULL on error. */
+char *
+pinentry_local_to_utf8 (char *lc_ctype, char *text, int secure)
+{
+  char *old_ctype;
+  char *source_encoding;
+  iconv_t cd;
+  const char *input = text;
+  size_t input_len = strlen (text) + 1;
+  char *output;
+  size_t output_len;
+  char *output_buf;
+  size_t processed;
+
+  /* If no locale setting could be determined, simply copy the
+     string.  */
+  if (!lc_ctype)
+    {
+      fprintf (stderr, "%s: no LC_CTYPE known - assuming UTF-8\n",
+               this_pgmname);
+      output_buf = secure? secmem_malloc (input_len) : malloc (input_len);
+      if (output_buf)
+        strcpy (output_buf, input);
+      return output_buf;
+    }
+
+  old_ctype = strdup (setlocale (LC_CTYPE, NULL));
+  if (!old_ctype)
+    return NULL;
+  setlocale (LC_CTYPE, lc_ctype);
+  source_encoding = nl_langinfo (CODESET);
+  setlocale (LC_CTYPE, old_ctype);
+  free (old_ctype);
+
+  /* This is overkill, but simplifies the iconv invocation greatly.  */
+  output_len = input_len * MB_LEN_MAX;
+  output_buf = output = secure? secmem_malloc (output_len):malloc (output_len);
+  if (!output)
+    return NULL;
+
+  cd = iconv_open ("UTF-8", source_encoding);
+  if (cd == (iconv_t) -1)
+    {
+      fprintf (stderr, "%s: can't convert from %s to UTF-8: %s\n",
+               this_pgmname, source_encoding? source_encoding : "?",
+               strerror (errno));
+      if (secure)
+        secmem_free (output_buf);
+      else
+        free (output_buf);
+      return NULL;
+    }
+  processed = iconv (cd, &input, &input_len, &output, &output_len);
+  iconv_close (cd);
+  if (processed == (size_t) -1 || input_len)
+    {
+      fprintf (stderr, "%s: error converting from %s to UTF-8: %s\n",
+               this_pgmname, source_encoding? source_encoding : "?",
+               strerror (errno));
+      if (secure)
+        secmem_free (output_buf);
+      else
+        free (output_buf);
+      return NULL;
+    }
+  return output_buf;
+}
+#endif
+
+
+/* Copy TEXT or TEXTLEN to BUFFER and escape as required.  Return a
+   pointer to the end of the new buffer.  Note that BUFFER must be
+   large enough to keep the entire text; allocataing it 3 times of
+   TEXTLEN is sufficient.  */
+static char *
+copy_and_escape (char *buffer, const void *text, size_t textlen)
+{
+  int i;
+  const unsigned char *s = (unsigned char *)text;
+  char *p = buffer;
+  
+  for (i=0; i < textlen; i++)
+    {
+      if (s[i] < ' ' || s[i] == '+')
+        {
+          snprintf (p, 4, "%%%02X", s[i]);
+          p += 3;
+        }
+      else if (s[i] == ' ')
+        *p++ = '+';
+      else
+        *p++ = s[i];
+    }
+  return p;
+}
+
+
+
+/* Run a quality inquiry for PASSPHRASE of LENGTH.  (We need LENGTH
+   because not all backends might be able to return a proper
+   C-string.).  Returns: A value between -100 and 100 to give an
+   estimate of the passphrase's quality.  Negative values are use if
+   the caller won't even accept that passphrase.  Note that we expect
+   just one data line which should not be escaped in any represent a
+   numeric signed decimal value.  Extra data is currently ignored but
+   should not be send at all.  */
+int
+pinentry_inq_quality (pinentry_t pin, const char *passphrase, size_t length)
+{
+  ASSUAN_CONTEXT ctx = pin->ctx_assuan;
+  const char prefix[] = "INQUIRE QUALITY ";
+  char *command;
+  char *line;
+  size_t linelen;
+  int gotvalue = 0;
+  int value = 0;
+  int rc;
+
+  if (!ctx)
+    return 0; /* Can't run the callback.  */
+
+  if (length > 300)
+    length = 300;  /* Limit so that it definitely fits into an Assuan
+                      line.  */
+
+  command = secmem_malloc (strlen (prefix) + 3*length + 1);
+  if (!command)
+    return 0;
+  strcpy (command, prefix);
+  copy_and_escape (command + strlen(command), passphrase, length);
+  rc = assuan_write_line (ctx, command);
+  secmem_free (command);
+  if (rc)
+    {
+      fprintf (stderr, "ASSUAN WRITE LINE failed: rc=%d\n", rc);
+      return 0;
+    }
+
+  for (;;)
+    {
+      do 
+        {
+          rc = assuan_read_line (ctx, &line, &linelen);
+          if (rc)
+            {
+              fprintf (stderr, "ASSUAN READ LINE failed: rc=%d\n", rc);
+              return 0;
+            }
+        }    
+      while (*line == '#' || !linelen);
+      if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
+          && (!line[3] || line[3] == ' '))
+        break; /* END command received*/
+      if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N'
+          && (!line[3] || line[3] == ' '))
+        break; /* CAN command received*/
+      if (line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
+          && (!line[3] || line[3] == ' '))
+        break; /* ERR command received*/
+      if (line[0] != 'D' || line[1] != ' ' || linelen < 3 || gotvalue)
+        continue;
+      gotvalue = 1;
+      value = atoi (line+2);
+    }
+  if (value < -100)
+    value = -100;
+  else if (value > 100)
+    value = 100;
+
+  return value;
+}
+
+
+
+/* Try to make room for at least LEN bytes in the pinentry.  Returns
+   new buffer on success and 0 on failure or when the old buffer is
+   sufficient.  */
+char *
+pinentry_setbufferlen (pinentry_t pin, int len)
+{
+  char *newp;
+  if (len < pinentry.pin_len)
+    return NULL;
+  newp = secmem_realloc (pin->pin, 2 * pin->pin_len);
+  if (newp)
+    {
+      pin->pin = newp;
+      pin->pin_len *= 2;
+    }
+  else
+    {
+      secmem_free (pin->pin);
+      pin->pin = 0;
+      pin->pin_len = 0;
+    }
+  return newp;
+}
+
+
+/* Initialize the secure memory subsystem, drop privileges and return.
+   Must be called early. */
+void
+pinentry_init (const char *pgmname)
+{
+  /* Store away our name. */
+  if (strlen (pgmname) > sizeof this_pgmname - 2)
+    abort ();
+  strcpy (this_pgmname, pgmname);
+
+  /* Initialize secure memory.  1 is too small, so the default size
+     will be used.  */
+  secmem_init (1);
+  secmem_set_flags (SECMEM_WARN);
+  drop_privs ();
+
+  if (atexit (secmem_term))
+    /* FIXME: Could not register at-exit function, bail out.  */
+    ;
+
+  assuan_set_malloc_hooks (secmem_malloc, secmem_realloc, secmem_free);
+}
+
+/* Simple test to check whether DISPLAY is set or the option --display
+   was given.  Used to decide whether the GUI or curses should be
+   initialized.  */
+int
+pinentry_have_display (int argc, char **argv)
+{
+#ifndef HAVE_W32CE_SYSTEM
+  const char *s;
+
+  s = getenv ("DISPLAY");
+  if (s && *s)
+    return 1;
+#endif
+  for (; argc; argc--, argv++)
+    if (!strcmp (*argv, "--display"))
+      return 1;
+  return 0;
+}
+
+
+\f
+static void 
+usage (void)
+{
+  fprintf (stdout, "Usage: %s [OPTION]...\n"
+"Ask securely for a secret and print it to stdout.\n"
+"\n"
+"      --display DISPLAY Set the X display\n"
+"      --ttyname PATH    Set the tty terminal node name\n"
+"      --ttytype NAME    Set the tty terminal type\n"
+"      --lc-ctype        Set the tty LC_CTYPE value\n"
+"      --lc-messages     Set the tty LC_MESSAGES value\n"
+#ifdef ENABLE_ENHANCED
+"  -e, --enhanced        Ask for timeout and insurance, too\n"
+#endif
+"  -g, --no-global-grab  Grab keyboard only while window is focused\n"
+"      --parent-wid     Parent window ID (for positioning)\n"
+"  -d, --debug           Turn on debugging output\n"
+"  -h, --help            Display this help and exit\n"
+"      --version         Output version information and exit\n", this_pgmname);
+}
+
+
+char *
+parse_color (char *arg, pinentry_color_t *color_p, int *bright_p)
+{
+  static struct
+  {
+    const char *name;
+    pinentry_color_t color;
+  } colors[] = { { "none", PINENTRY_COLOR_NONE },
+                { "default", PINENTRY_COLOR_DEFAULT },
+                { "black", PINENTRY_COLOR_BLACK },
+                { "red", PINENTRY_COLOR_RED },
+                { "green", PINENTRY_COLOR_GREEN },
+                { "yellow", PINENTRY_COLOR_YELLOW },
+                { "blue", PINENTRY_COLOR_BLUE },
+                { "magenta", PINENTRY_COLOR_MAGENTA },
+                { "cyan", PINENTRY_COLOR_CYAN },
+                { "white", PINENTRY_COLOR_WHITE } };
+
+  int i;
+  char *new_arg;
+  pinentry_color_t color = PINENTRY_COLOR_DEFAULT;
+
+  if (!arg)
+    return NULL;
+
+  new_arg = strchr (arg, ',');
+  if (new_arg)
+    new_arg++;
+
+  if (bright_p)
+    {
+      const char *bname[] = { "bright-", "bright", "bold-", "bold" };
+
+      *bright_p = 0;
+      for (i = 0; i < sizeof (bname) / sizeof (bname[0]); i++)
+       if (!strncasecmp (arg, bname[i], strlen (bname[i])))
+         {
+           *bright_p = 1;
+           arg += strlen (bname[i]);
+         }
+    }
+
+  for (i = 0; i < sizeof (colors) / sizeof (colors[0]); i++)
+    if (!strncasecmp (arg, colors[i].name, strlen (colors[i].name)))
+      color = colors[i].color;
+
+  *color_p = color;
+  return new_arg;
+}
+
+/* Parse the command line options.  Returns 1 if user should print
+   version and exit.  Can exit the program if only help output is
+   requested.  */
+int
+pinentry_parse_opts (int argc, char *argv[])
+{
+  int opt;
+  int opt_help = 0;
+  int opt_version = 0;
+  struct option opts[] =
+    {{ "debug", no_argument,             0, 'd' },
+     { "display", required_argument,     0, 'D' },
+     { "ttyname", required_argument,     0, 'T' },
+     { "ttytype", required_argument,     0, 'N' },
+     { "lc-ctype", required_argument,    0, 'C' },
+     { "lc-messages", required_argument, 0, 'M' },
+#ifdef ENABLE_ENHANCED
+     { "enhanced", no_argument,          0, 'e' },
+#endif
+     { "no-global-grab", no_argument,    0, 'g' },
+     { "parent-wid", required_argument,  0, 'W' },
+     { "colors", required_argument,     0, 'c' },
+     { "help", no_argument,              0, 'h' },
+     { "version", no_argument, &opt_version, 1 },
+     { NULL, 0, NULL, 0 }};
+  
+  while ((opt = getopt_long (argc, argv, "degh", opts, NULL)) != -1)
+    {
+      switch (opt)
+        {
+        case 0:
+        case '?':
+          break;
+        case 'd':
+          pinentry.debug = 1;
+          break;
+#ifdef ENABLE_ENHANCED
+        case 'e':
+          pinentry.enhanced = 1;
+          break;
+#endif
+        case 'g':
+          pinentry.grab = 0;
+          break;
+        case 'h':
+          opt_help = 1;
+          break;
+
+       case 'D':
+          /* Note, this is currently not used because the GUI engine
+             has already been initialized when parsing these options. */
+         pinentry.display = strdup (optarg);
+         if (!pinentry.display)
+           {
+#ifndef HAVE_W32CE_SYSTEM
+             fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
+#endif
+             exit (EXIT_FAILURE);
+           }
+         break; 
+       case 'T':
+         pinentry.ttyname = strdup (optarg);
+         if (!pinentry.ttyname)
+           {
+#ifndef HAVE_W32CE_SYSTEM
+             fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
+#endif
+             exit (EXIT_FAILURE);
+           }
+         break;
+       case 'N':
+         pinentry.ttytype = strdup (optarg);
+         if (!pinentry.ttytype)
+           {
+#ifndef HAVE_W32CE_SYSTEM
+             fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
+#endif
+             exit (EXIT_FAILURE);
+           }
+         break;
+       case 'C':
+         pinentry.lc_ctype = strdup (optarg);
+         if (!pinentry.lc_ctype)
+           {
+#ifndef HAVE_W32CE_SYSTEM
+             fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
+#endif
+             exit (EXIT_FAILURE);
+           }
+         break;
+       case 'M':
+         pinentry.lc_messages = strdup (optarg);
+         if (!pinentry.lc_messages)
+           {
+#ifndef HAVE_W32CE_SYSTEM
+             fprintf (stderr, "%s: %s\n", this_pgmname, strerror (errno));
+#endif
+             exit (EXIT_FAILURE);
+           }
+         break;
+       case 'W':
+         pinentry.parent_wid = atoi (optarg);
+         /* FIXME: Add some error handling.  Use strtol.  */
+         break;
+
+       case 'c':
+         optarg = parse_color (optarg, &pinentry.color_fg,
+                               &pinentry.color_fg_bright);
+         optarg = parse_color (optarg, &pinentry.color_bg, NULL);
+         optarg = parse_color (optarg, &pinentry.color_so,
+                               &pinentry.color_so_bright);
+         break;
+
+        default:
+          fprintf (stderr, "%s: oops: option not handled\n", this_pgmname);
+         break;
+        }
+    }
+  if (opt_version) 
+    return 1;
+  if (opt_help) 
+    {
+      usage ();
+      exit (EXIT_SUCCESS);
+    }
+  return 0;
+}
+
+\f
+static int
+option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
+{
+  if (!strcmp (key, "no-grab") && !*value)
+    pinentry.grab = 0;
+  else if (!strcmp (key, "grab") && !*value)
+    pinentry.grab = 1;
+  else if (!strcmp (key, "debug-wait"))
+    {
+#ifndef HAVE_W32CE_SYSTEM
+      fprintf (stderr, "%s: waiting for debugger - my pid is %u ...\n",
+              this_pgmname, (unsigned int) getpid());
+      sleep (*value?atoi (value):5);
+      fprintf (stderr, "%s: ... okay\n", this_pgmname);
+#endif
+    }
+  else if (!strcmp (key, "display"))
+    {
+      if (pinentry.display)
+       free (pinentry.display);
+      pinentry.display = strdup (value);
+      if (!pinentry.display)
+       return ASSUAN_Out_Of_Core;
+    }
+  else if (!strcmp (key, "ttyname"))
+    {
+      if (pinentry.ttyname)
+       free (pinentry.ttyname);
+      pinentry.ttyname = strdup (value);
+      if (!pinentry.ttyname)
+       return ASSUAN_Out_Of_Core;
+    }
+  else if (!strcmp (key, "ttytype"))
+    {
+      if (pinentry.ttytype)
+       free (pinentry.ttytype);
+      pinentry.ttytype = strdup (value);
+      if (!pinentry.ttytype)
+       return ASSUAN_Out_Of_Core;
+    }
+  else if (!strcmp (key, "lc-ctype"))
+    {
+      if (pinentry.lc_ctype)
+       free (pinentry.lc_ctype);
+      pinentry.lc_ctype = strdup (value);
+      if (!pinentry.lc_ctype)
+       return ASSUAN_Out_Of_Core;
+    }
+  else if (!strcmp (key, "lc-messages"))
+    {
+      if (pinentry.lc_messages)
+       free (pinentry.lc_messages);
+      pinentry.lc_messages = strdup (value);
+      if (!pinentry.lc_messages)
+       return ASSUAN_Out_Of_Core;
+    }
+  else if (!strcmp (key, "parent-wid"))
+    {
+      pinentry.parent_wid = atoi (value);
+      /* FIXME: Use strtol and add some error handling.  */
+    }
+  else if (!strcmp (key, "touch-file"))
+    {
+      if (pinentry.touch_file)
+        free (pinentry.touch_file);
+      pinentry.touch_file = strdup (value);
+      if (!pinentry.touch_file)
+       return ASSUAN_Out_Of_Core;
+    }
+  else if (!strcmp (key, "default-ok"))
+    {
+      pinentry.default_ok = strdup (value);
+      if (!pinentry.default_ok)
+       return ASSUAN_Out_Of_Core;
+    }
+  else if (!strcmp (key, "default-cancel"))
+    {
+      pinentry.default_cancel = strdup (value);
+      if (!pinentry.default_cancel)
+       return ASSUAN_Out_Of_Core;
+    }
+  else if (!strcmp (key, "default-prompt"))
+    {
+      pinentry.default_prompt = strdup (value);
+      if (!pinentry.default_prompt)
+       return ASSUAN_Out_Of_Core;
+    }
+  else
+    return ASSUAN_Invalid_Option;
+  return 0;
+}
+
+
+/* Note, that it is sufficient to allocate the target string D as
+   long as the source string S, i.e.: strlen(s)+1; */
+static void
+strcpy_escaped (char *d, const char *s)
+{
+  while (*s)
+    {
+      if (*s == '%' && s[1] && s[2])
+        { 
+          s++;
+          *d++ = xtoi_2 ( s);
+          s += 2;
+        }
+      else
+        *d++ = *s++;
+    }
+  *d = 0; 
+}
+
+
+static int
+cmd_setdesc (ASSUAN_CONTEXT ctx, char *line)
+{
+  char *newd;
+  newd = malloc (strlen (line) + 1);
+
+  if (!newd)
+    return ASSUAN_Out_Of_Core;
+
+  strcpy_escaped (newd, line);
+  if (pinentry.description)
+    free (pinentry.description);
+  pinentry.description = newd;
+  return 0;
+}
+
+
+static int
+cmd_setprompt (ASSUAN_CONTEXT ctx, char *line)
+{
+  char *newp;
+  newp = malloc (strlen (line) + 1);
+
+  if (!newp)
+    return ASSUAN_Out_Of_Core;
+
+  strcpy_escaped (newp, line);
+  if (pinentry.prompt)
+    free (pinentry.prompt);
+  pinentry.prompt = newp;
+  return 0;
+}
+
+
+static int
+cmd_seterror (ASSUAN_CONTEXT ctx, char *line)
+{
+  char *newe;
+  newe = malloc (strlen (line) + 1);
+
+  if (!newe)
+    return ASSUAN_Out_Of_Core;
+
+  strcpy_escaped (newe, line);
+  if (pinentry.error)
+    free (pinentry.error);
+  pinentry.error = newe;
+  return 0;
+}
+
+
+static int
+cmd_setok (ASSUAN_CONTEXT ctx, char *line)
+{
+  char *newo;
+  newo = malloc (strlen (line) + 1);
+
+  if (!newo)
+    return ASSUAN_Out_Of_Core;
+
+  strcpy_escaped (newo, line);
+  if (pinentry.ok)
+    free (pinentry.ok);
+  pinentry.ok = newo;
+  return 0;
+}
+
+
+static int
+cmd_setnotok (ASSUAN_CONTEXT ctx, char *line)
+{
+  char *newo;
+  newo = malloc (strlen (line) + 1);
+
+  if (!newo)
+    return ASSUAN_Out_Of_Core;
+
+  strcpy_escaped (newo, line);
+  if (pinentry.notok)
+    free (pinentry.notok);
+  pinentry.notok = newo;
+  return 0;
+}
+
+
+static int
+cmd_setcancel (ASSUAN_CONTEXT ctx, char *line)
+{
+  char *newc;
+  newc = malloc (strlen (line) + 1);
+
+  if (!newc)
+    return ASSUAN_Out_Of_Core;
+
+  strcpy_escaped (newc, line);
+  if (pinentry.cancel)
+    free (pinentry.cancel);
+  pinentry.cancel = newc;
+  return 0;
+}
+
+
+static int
+cmd_settitle (ASSUAN_CONTEXT ctx, char *line)
+{
+  char *newt;
+  newt = malloc (strlen (line) + 1);
+  
+  if (!newt)
+    return ASSUAN_Out_Of_Core;
+  
+  strcpy_escaped (newt, line);
+  if (pinentry.title)
+    free (pinentry.title);
+  pinentry.title = newt;
+  return 0;
+}
+
+static int
+cmd_setqualitybar (ASSUAN_CONTEXT ctx, char *line)
+{
+  char *newval;
+
+  if (!*line)
+    line = "Quality:";
+
+  newval = malloc (strlen (line) + 1);
+  if (!newval)
+    return ASSUAN_Out_Of_Core;
+
+  strcpy_escaped (newval, line);
+  if (pinentry.quality_bar)
+    free (pinentry.quality_bar);
+  pinentry.quality_bar = newval;
+  return 0;
+}
+
+/* Set the tooltip to be used for a quality bar.  */
+static int
+cmd_setqualitybar_tt (ASSUAN_CONTEXT ctx, char *line)
+{
+  char *newval;
+
+  if (*line)
+    {
+      newval = malloc (strlen (line) + 1);
+      if (!newval)
+        return ASSUAN_Out_Of_Core;
+      
+      strcpy_escaped (newval, line);
+    }
+  else
+    newval = NULL;
+  if (pinentry.quality_bar_tt)
+    free (pinentry.quality_bar_tt);
+  pinentry.quality_bar_tt = newval;
+  return 0;
+}
+
+
+static int
+cmd_getpin (ASSUAN_CONTEXT ctx, char *line)
+{
+  int result;
+  int set_prompt = 0;
+
+  pinentry.pin = secmem_malloc (pinentry.pin_len);
+  if (!pinentry.pin)
+    return ASSUAN_Out_Of_Core;
+  if (!pinentry.prompt)
+    {
+      pinentry.prompt = pinentry.default_prompt?pinentry.default_prompt:"PIN:";
+      set_prompt = 1;
+    }
+  pinentry.locale_err = 0;
+  pinentry.one_button = 0;
+  pinentry.ctx_assuan = ctx;
+  result = (*pinentry_cmd_handler) (&pinentry);
+  pinentry.ctx_assuan = NULL;
+  if (pinentry.error)
+    {
+      free (pinentry.error);
+      pinentry.error = NULL;
+    }
+  if (set_prompt)
+    pinentry.prompt = NULL;
+
+  pinentry.quality_bar = 0;  /* Reset it after the command.  */
+
+  if (result < 0)
+    {
+      if (pinentry.pin)
+       {
+         secmem_free (pinentry.pin);
+         pinentry.pin = NULL;
+       }
+      return pinentry.locale_err? ASSUAN_Locale_Problem: ASSUAN_Canceled;
+    }
+
+  if (result)
+    {
+      result = assuan_send_data (ctx, pinentry.pin, result);
+      if (!result)
+       result = assuan_send_data (ctx, NULL, 0);
+    }
+
+  if (pinentry.pin)
+    {
+      secmem_free (pinentry.pin);
+      pinentry.pin = NULL;
+    }
+
+  return result;
+}
+
+
+/* Note that the option --one-button is a hack to allow the use of old
+   pinentries while the caller is ignoring the result.  Given that
+   options have never been used or flagged as an error the new option
+   is an easy way to enable the messsage mode while not requiring to
+   update pinentry or to have the caller test for the message
+   command.  New applications which are free to require an updated
+   pinentry should use MESSAGE instead. */
+static int
+cmd_confirm (ASSUAN_CONTEXT ctx, char *line)
+{
+  int result;
+
+  pinentry.one_button = !!strstr (line, "--one-button");
+  pinentry.quality_bar = 0;
+  pinentry.locale_err = 0;
+  pinentry.canceled = 0;
+  result = (*pinentry_cmd_handler) (&pinentry);
+  if (pinentry.error)
+    {
+      free (pinentry.error);
+      pinentry.error = NULL;
+    }
+
+  return result ? 0
+                : (pinentry.locale_err? ASSUAN_Locale_Problem
+                                      : (pinentry.one_button 
+                                         ? 0
+                                         : (pinentry.canceled
+                                            ? ASSUAN_Canceled
+                                            : ASSUAN_Not_Confirmed)));
+}
+
+
+static int
+cmd_message (ASSUAN_CONTEXT ctx, char *line)
+{
+  int result;
+
+  pinentry.one_button = 1;
+  pinentry.quality_bar = 0;
+  pinentry.locale_err = 0;
+  result = (*pinentry_cmd_handler) (&pinentry);
+  if (pinentry.error)
+    {
+      free (pinentry.error);
+      pinentry.error = NULL;
+    }
+
+  return result ? 0 
+                : (pinentry.locale_err? ASSUAN_Locale_Problem
+                                      : 0);
+}
+
+/* GETINFO <what>
+
+   Multipurpose function to return a variety of information.
+   Supported values for WHAT are:
+
+     version     - Return the version of the program.
+     pid         - Return the process id of the server.
+ */
+static int
+cmd_getinfo (assuan_context_t ctx, char *line)
+{
+  int rc;
+
+  if (!strcmp (line, "version"))
+    {
+      const char *s = VERSION;
+      rc = assuan_send_data (ctx, s, strlen (s));
+    }
+  else if (!strcmp (line, "pid"))
+    {
+      char numbuf[50];
+
+      snprintf (numbuf, sizeof numbuf, "%lu", (unsigned long)getpid ());
+      rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
+    }
+  else
+    rc = ASSUAN_Parameter_Error;
+  return rc;
+}
+
+
+/* Tell the assuan library about our commands.  */
+static int
+register_commands (ASSUAN_CONTEXT ctx)
+{
+  static struct
+  {
+    const char *name;
+    int cmd_id;
+    int (*handler) (ASSUAN_CONTEXT, char *line);
+  } table[] =
+    {
+      { "SETDESC",    0,  cmd_setdesc },
+      { "SETPROMPT",  0,  cmd_setprompt },
+      { "SETERROR",   0,  cmd_seterror },
+      { "SETOK",      0,  cmd_setok },
+      { "SETNOTOK",   0,  cmd_setnotok },
+      { "SETCANCEL",  0,  cmd_setcancel },
+      { "GETPIN",     0,  cmd_getpin },
+      { "CONFIRM",    0,  cmd_confirm },
+      { "MESSAGE",    0,  cmd_message },
+      { "SETQUALITYBAR", 0,  cmd_setqualitybar },
+      { "SETQUALITYBAR_TT", 0,  cmd_setqualitybar_tt },
+      { "GETINFO",    0,  cmd_getinfo },
+      { "SETTITLE",   0,  cmd_settitle },
+      { NULL }
+    };
+  int i, j, rc;
+
+  for (i = j = 0; table[i].name; i++)
+    {
+      rc = assuan_register_command (ctx,
+                                    table[i].cmd_id ? table[i].cmd_id
+                                                   : (ASSUAN_CMD_USER + j++),
+                                    table[i].name, table[i].handler);
+      if (rc)
+        return rc;
+    } 
+  return 0;
+}
+
+
+int
+pinentry_loop2 (int infd, int outfd)
+{
+  int rc;
+  int filedes[2];
+  ASSUAN_CONTEXT ctx;
+
+  /* Extra check to make sure we have dropped privs. */
+#ifndef HAVE_DOSISH_SYSTEM
+  if (getuid() != geteuid())
+    abort ();
+#endif
+
+  /* For now we use a simple pipe based server so that we can work
+     from scripts.  We will later add options to run as a daemon and
+     wait for requests on a Unix domain socket.  */
+  filedes[0] = infd;
+  filedes[1] = outfd;
+  rc = assuan_init_pipe_server (&ctx, filedes);
+  if (rc)
+    {
+      fprintf (stderr, "%s: failed to initialize the server: %s\n",
+               this_pgmname, assuan_strerror(rc));
+      return -1;
+    }
+  rc = register_commands (ctx);
+  if (rc)
+    {
+      fprintf (stderr, "%s: failed to the register commands with Assuan: %s\n",
+               this_pgmname, assuan_strerror(rc));
+      return -1;
+    }
+
+  assuan_register_option_handler (ctx, option_handler);
+#if 0
+  assuan_set_log_stream (ctx, stderr);
+#endif
+  
+  for (;;)
+    {
+      rc = assuan_accept (ctx);
+      if (rc == -1)
+          break;
+      else if (rc)
+        {
+          fprintf (stderr, "%s: Assuan accept problem: %s\n",
+                   this_pgmname, assuan_strerror (rc));
+          break;
+        }
+      
+      rc = assuan_process (ctx);
+      if (rc)
+        {
+          fprintf (stderr, "%s: Assuan processing failed: %s\n",
+                   this_pgmname, assuan_strerror (rc));
+          continue;
+        }
+    }
+
+  assuan_deinit_server (ctx);
+  return 0;
+}
+
+
+/* Start the pinentry event loop.  The program will start to process
+   Assuan commands until it is finished or an error occurs.  If an
+   error occurs, -1 is returned.  Otherwise, 0 is returned.  */
+int
+pinentry_loop (void)
+{
+  return pinentry_loop2 (STDIN_FILENO, STDOUT_FILENO);
+}
diff --git a/pinentry.h b/pinentry.h
new file mode 100644 (file)
index 0000000..cfc78c5
--- /dev/null
@@ -0,0 +1,218 @@
+/* pinentry.h - The interface for the PIN entry support library.
+   Copyright (C) 2002, 2003, 2010 g10 Code GmbH
+   
+   This file is part of PINENTRY.
+   
+   PINENTRY is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   PINENTRY is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>. 
+ */
+
+#ifndef PINENTRY_H
+#define PINENTRY_H
+
+#ifdef __cplusplus
+extern "C" {
+#if 0 
+}
+#endif
+#endif
+
+#undef ENABLE_ENHANCED
+
+typedef enum {
+  PINENTRY_COLOR_NONE, PINENTRY_COLOR_DEFAULT,
+  PINENTRY_COLOR_BLACK, PINENTRY_COLOR_RED,
+  PINENTRY_COLOR_GREEN, PINENTRY_COLOR_YELLOW,
+  PINENTRY_COLOR_BLUE, PINENTRY_COLOR_MAGENTA,
+  PINENTRY_COLOR_CYAN, PINENTRY_COLOR_WHITE
+} pinentry_color_t;
+
+struct pinentry
+{
+  /* The window title, or NULL.  */
+  char *title;
+  /* The description to display, or NULL.  */
+  char *description;
+  /* The error message to display, or NULL.  */
+  char *error;
+  /* The prompt to display, or NULL.  */
+  char *prompt;
+  /* The OK button text to display, or NULL.  */
+  char *ok;
+  /* The Not-OK button text to display, or NULL.  */
+  char *notok;
+  /* The Cancel button text to display, or NULL.  */
+  char *cancel;
+  /* The buffer to store the secret into.  */
+  char *pin;
+  /* The length of the buffer.  */
+  int pin_len;
+
+  /* The name of the X display to use if X is available and supported.  */
+  char *display;
+  /* The name of the terminal node to open if X not available or supported.  */
+  char *ttyname;
+  /* The type of the terminal.  */
+  char *ttytype;
+  /* The LC_CTYPE value for the terminal.  */
+  char *lc_ctype;
+  /* The LC_MESSAGES value for the terminal.  */
+  char *lc_messages;
+
+  /* True if debug mode is requested.  */
+  int debug;
+
+#ifdef ENABLE_ENHANCED
+  /* True if enhanced mode is requested.  */
+  int enhanced;
+#endif
+
+  /* True if caller should grab the keyboard.  */
+  int grab;
+  /* The window ID of the parent window over which the pinentry window
+     should be displayed.  */
+  int parent_wid;
+
+  /* The name of an optional file which will be touched after a curses
+     entry has been displayed.  */
+  char *touch_file;
+
+  /* The user should set this to -1 if the user canceled the request,
+     and to the length of the PIN stored in pin otherwise.  */
+  int result;
+
+  /* The user should set this if the NOTOK button was pressed.  */
+  int canceled;
+
+  /* The user should set this to true if an error with the local
+     conversion occured. */
+  int locale_err;
+
+  /* The caller should set this to true if only one button is
+     required.  This is useful for notification dialogs where only a
+     dismiss button is required. */
+  int one_button;
+
+  /* If this is not NULL, a passphrase quality indicator is shown.
+     There will also be an inquiry back to the caller to get an
+     indication of the quality for the passphrase entered so far.  The
+     string is used as a label for the quality bar.  */
+  char *quality_bar;
+
+  /* The tooltip to be show for the qualitybar.  Malloced or NULL.  */
+  char *quality_bar_tt;
+
+  /* For the curses pinentry, the color of error messages.  */
+  pinentry_color_t color_fg;
+  int color_fg_bright;
+  pinentry_color_t color_bg;
+  pinentry_color_t color_so;
+  int color_so_bright;
+
+  /* Malloced and i18ned default strings or NULL.  These strings may
+     include an underscore character to indicate an accelerator key.
+     A double underscore represents a plain one.  */
+  char *default_ok;
+  char *default_cancel;
+  char *default_prompt;
+
+  /* For the quality indicator we need to do an inquiry.  Thus we need
+     to save the assuan ctx.  */
+  void *ctx_assuan;
+
+};
+typedef struct pinentry *pinentry_t;
+
+\f
+/* The pinentry command handler type processes the pinentry request
+   PIN.  If PIN->pin is zero, request a confirmation, otherwise a PIN
+   entry.  On confirmation, the function should return TRUE if
+   confirmed, and FALSE otherwise.  On PIN entry, the function should
+   return -1 if cancelled and the length of the secret otherwise.  */
+typedef int (*pinentry_cmd_handler_t) (pinentry_t pin);
+
+/* Start the pinentry event loop.  The program will start to process
+   Assuan commands until it is finished or an error occurs.  If an
+   error occurs, -1 is returned and errno indicates the type of an
+   error.  Otherwise, 0 is returned.  */
+int pinentry_loop (void);
+
+/* The same as above but allows to specify the i/o descriptors. */
+int pinentry_loop2 (int infd, int outfd);
+
+
+/* Convert the UTF-8 encoded string TEXT to the encoding given in
+   LC_CTYPE.  Return NULL on error. */
+char *pinentry_utf8_to_local (char *lc_ctype, char *text);
+
+/* Convert TEXT which is encoded according to LC_CTYPE to UTF-8.  With
+   SECURE set to true, use secure memory for the returned buffer.
+   Return NULL on error. */
+char *pinentry_local_to_utf8 (char *lc_ctype, char *text, int secure);
+
+
+/* Run a quality inquiry for PASSPHRASE of LENGTH. */
+int pinentry_inq_quality (pinentry_t pin, 
+                          const char *passphrase, size_t length);
+
+/* Try to make room for at least LEN bytes for the pin in the pinentry
+   PIN.  Returns new buffer on success and 0 on failure.  */
+char *pinentry_setbufferlen (pinentry_t pin, int len);
+
+/* Initialize the secure memory subsystem, drop privileges and
+   return.  Must be called early.  */
+void pinentry_init (const char *pgmname);
+
+/* Return true if either DISPLAY is set or ARGV contains the string
+   "--display". */
+int pinentry_have_display (int argc, char **argv);
+
+/* Parse the command line options.  Returns 1 if user should print
+   version and exit.  Can exit the program if only help output is
+   requested.  */
+int pinentry_parse_opts (int argc, char *argv[]);
+
+\f
+/* The caller must define this variable to process assuan commands.  */
+extern pinentry_cmd_handler_t pinentry_cmd_handler;
+
+
+
+
+\f
+#ifdef HAVE_W32_SYSTEM
+/* Windows declares sleep as obsolete, but provides a definition for
+   _sleep but non for the still existing sleep.  */
+#define sleep(a) _sleep ((a))
+
+#ifdef HAVE_W32CE_SYSTEM
+
+/* strdup also got a prefix */
+#define strdup _strdup
+/* without signals we need not abort */
+#define abort(a) exit(1)
+/* case insensitive comparisons are both */
+#define strncasecmp _strnicmp
+/* On MSVC snprintf is not defined but _snprintf is */
+#define snprintf _snprintf
+#endif /*HAVE_WIN32CE_SYSTEM*/
+#endif /*HAVE_W32_SYSTEM*/
+
+#if 0 
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PINENTRY_H */
diff --git a/pinentrydialog.cpp b/pinentrydialog.cpp
new file mode 100644 (file)
index 0000000..ca081a8
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+   pinentrydialog.cpp - A (not yet) secure Qt 4 dialog for PIN entry.
+
+   Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB)
+   Copyright 2007 Ingo Klöcker
+
+   Written by Steffen Hansen <steffen@klaralvdalens-datakonsult.se>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the 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.
+*/
+
+#include "pinentrydialog.h"
+#include <QGridLayout>
+
+#include <QProgressBar>
+#include <QApplication>
+#include <QStyle>
+#include <QPainter>
+#include <QPushButton>
+#include <QDialogButtonBox>
+#include <QKeyEvent>
+#include <QLabel>
+#include <QPalette>
+
+#ifdef Q_WS_WIN
+#include <windows.h>
+#endif
+
+#ifdef defined(Q_WS_WIN) && !defined(HAVE_W32CE_SYSTEM)
+void SetForegroundWindowEx( HWND hWnd )
+{
+   //Attach foreground window thread to our thread
+   const DWORD ForeGroundID = GetWindowThreadProcessId(::GetForegroundWindow(),NULL);
+   const DWORD CurrentID   = GetCurrentThreadId();
+   AttachThreadInput ( ForeGroundID, CurrentID, TRUE );
+   //Do our stuff here
+   HWND hLastActivePopupWnd = GetLastActivePopup( hWnd );
+   SetForegroundWindow( hLastActivePopupWnd );
+   //Detach the attached thread
+   AttachThreadInput ( ForeGroundID, CurrentID, FALSE );
+}// End SetForegroundWindowEx
+#endif
+
+void raiseWindow( QWidget* w )
+{
+#ifdef HAVE_W32CE_SYSTEM
+    SetForegroundWindow( w->winId() );
+#elif Q_WS_WIN
+    SetForegroundWindowEx( w->winId() );
+#endif
+    w->raise(); 
+    w->activateWindow();
+}
+
+QPixmap icon( QStyle::StandardPixmap which )
+{
+    QPixmap pm = qApp->windowIcon().pixmap( 48, 48 );
+   
+    if ( which != QStyle::SP_CustomBase ) {
+        const QIcon ic = qApp->style()->standardIcon( which );
+        QPainter painter( &pm );
+        const int emblemSize = 22;
+        painter.drawPixmap( pm.width()-emblemSize, 0,
+                            ic.pixmap( emblemSize, emblemSize ) );
+    }
+
+    return pm;
+}
+
+PinEntryDialog::PinEntryDialog( QWidget* parent, const char* name, bool modal,
+                                bool enable_quality_bar )
+  : QDialog( parent ), _grabbed( false )
+{
+  setWindowFlags( windowFlags() & ~Qt::WindowContextHelpButtonHint );
+
+  if ( modal ) {
+    setWindowModality( Qt::ApplicationModal );
+  }
+
+  _icon = new QLabel( this );
+  _icon->setPixmap( icon() );
+
+  _error = new QLabel( this );
+  _error->setWordWrap(true);
+  QPalette pal;
+  pal.setColor( QPalette::WindowText, Qt::red );
+  _error->setPalette( pal );
+  _error->hide();
+
+  _desc = new QLabel( this );
+  _desc->setWordWrap(true);
+  _desc->hide();
+
+  _prompt = new QLabel( this );
+  _prompt->hide();
+
+  _edit = new QSecureLineEdit( this );
+  _edit->setMaxLength( 256 );
+
+  _prompt->setBuddy( _edit );
+
+  if (enable_quality_bar)
+  {
+    _quality_bar_label = new QLabel( this );
+    _quality_bar_label->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
+    _quality_bar = new QProgressBar( this );
+    _quality_bar->setAlignment( Qt::AlignCenter );
+    _have_quality_bar = true;
+  }
+  else
+    _have_quality_bar = false;
+
+  QDialogButtonBox* const buttons = new QDialogButtonBox( this );
+  buttons->setStandardButtons( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
+  _ok = buttons->button( QDialogButtonBox::Ok );
+  _cancel = buttons->button( QDialogButtonBox::Cancel );
+
+  _ok->setDefault(true);
+
+  if ( style()->styleHint( QStyle::SH_DialogButtonBox_ButtonsHaveIcons ) )
+    {
+      _ok->setIcon( style()->standardIcon( QStyle::SP_DialogOkButton ) );
+      _cancel->setIcon( style()->standardIcon( QStyle::SP_DialogCancelButton ) );
+    }
+  connect( buttons, SIGNAL(accepted()), this, SLOT(accept()) );
+  connect( buttons, SIGNAL(rejected()), this, SLOT(reject()) );
+  connect( _edit, SIGNAL( textChanged(secqstring) ),
+          this, SLOT( updateQuality(secqstring) ) );
+
+  _edit->setFocus();
+
+  QGridLayout* const grid = new QGridLayout( this );
+  grid->addWidget( _icon, 0, 0, 5, 1, Qt::AlignTop|Qt::AlignLeft );
+  grid->addWidget( _error, 1, 1, 1, 2 );
+  grid->addWidget( _desc,  2, 1, 1, 2 );
+  //grid->addItem( new QSpacerItem( 0, _edit->height() / 10, QSizePolicy::Minimum, QSizePolicy::Fixed ), 1, 1 );
+  grid->addWidget( _prompt, 3, 1 );
+  grid->addWidget( _edit, 3, 2 );
+  if( enable_quality_bar )
+  {
+    grid->addWidget( _quality_bar_label, 4, 1 );
+    grid->addWidget( _quality_bar, 4, 2 );
+  }
+  grid->addWidget( buttons, 5, 0, 1, 3 );
+
+  grid->setSizeConstraint( QLayout::SetFixedSize );
+}
+
+void PinEntryDialog::hideEvent( QHideEvent* ev )
+{
+  if ( !_pinentry_info || _pinentry_info->grab )
+    _edit->releaseKeyboard();
+  _grabbed = false;
+  QDialog::hideEvent( ev );
+}
+
+void PinEntryDialog::showEvent( QShowEvent* event )
+{
+    QDialog::showEvent( event );
+    raiseWindow( this );
+}
+
+void PinEntryDialog::setDescription( const QString& txt )
+{
+  _desc->setVisible( !txt.isEmpty() );
+  _desc->setText( txt );
+  _icon->setPixmap( icon() );
+  setError( QString::null );
+}
+
+QString PinEntryDialog::description() const
+{
+  return _desc->text();
+}
+
+void PinEntryDialog::setError( const QString& txt )
+{
+  if( !txt.isNull() )_icon->setPixmap( icon( QStyle::SP_MessageBoxCritical ) );
+  _error->setText( txt );
+  _error->setVisible( !txt.isEmpty() );
+}
+
+QString PinEntryDialog::error() const
+{
+  return _error->text();
+}
+
+void PinEntryDialog::setPin( const secqstring & txt )
+{
+    _edit->setText( txt );
+}
+
+secqstring PinEntryDialog::pin() const
+{
+    return _edit->text();
+}
+
+void PinEntryDialog::setPrompt( const QString& txt )
+{
+  _prompt->setText( txt );
+  _prompt->setVisible( !txt.isEmpty() );
+}
+
+QString PinEntryDialog::prompt() const
+{
+  return _prompt->text();
+}
+
+void PinEntryDialog::setOkText( const QString& txt )
+{
+  _ok->setText( txt );
+  _ok->setVisible( !txt.isEmpty() );
+}
+
+void PinEntryDialog::setCancelText( const QString& txt )
+{
+  _cancel->setText( txt );
+  _cancel->setVisible( !txt.isEmpty() );
+}
+
+void PinEntryDialog::setQualityBar( const QString& txt )
+{
+  if (_have_quality_bar)
+    _quality_bar_label->setText( txt );
+}
+
+void PinEntryDialog::setQualityBarTT( const QString& txt )
+{
+  if (_have_quality_bar)
+    _quality_bar->setToolTip( txt );
+}
+
+void PinEntryDialog::updateQuality(const secqstring & txt )
+{
+  int length;
+  int percent;
+  QPalette pal;
+
+  if (!_have_quality_bar || !_pinentry_info)
+    return;
+  secstring pinStr(txt.toUtf8());
+  const char* pin = pinStr.c_str();
+  // The Qt3 version called ::secmem_free (pin) here, but from other usage of secstring,
+  // it seems like this is not needed anymore - 16 Mar. 2009 13:15 -- Jesper K. Pedersen
+  length = strlen (pin);
+  percent = length? pinentry_inq_quality (_pinentry_info, pin, length) : 0;
+  if (!length)
+    {
+      _quality_bar->reset ();
+    }
+  else
+    {
+      pal = _quality_bar->palette ();
+      if (percent < 0)
+        {
+          pal.setColor (QPalette::Highlight, QColor("red"));
+          percent = -percent;
+        }
+      else
+        {
+          pal.setColor (QPalette::Highlight, QColor("green"));
+        }
+      _quality_bar->setPalette (pal);
+      _quality_bar->setValue (percent);
+    }
+}
+
+void PinEntryDialog::setPinentryInfo(pinentry_t peinfo)
+{
+    _pinentry_info = peinfo;
+}
+
+void PinEntryDialog::paintEvent( QPaintEvent* event )
+{
+  // Grab keyboard. It might be a little weird to do it here, but it works!
+  // Previously this code was in showEvent, but that did not work in Qt4.
+  QDialog::paintEvent( event );
+  if ( !_grabbed && ( !_pinentry_info || _pinentry_info->grab ) ) {
+    _edit->grabKeyboard();
+    _grabbed = true;
+  }
+
+}
+
+#include "pinentrydialog.moc"
diff --git a/pinentrydialog.h b/pinentrydialog.h
new file mode 100644 (file)
index 0000000..7becc26
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+   pinentrydialog.h - A (not yet) secure Qt 4 dialog for PIN entry.
+
+   Copyright (C) 2002, 2008 Klarälvdalens Datakonsult AB (KDAB)
+   Copyright 2007 Ingo Klöcker
+
+   Written by Steffen Hansen <steffen@klaralvdalens-datakonsult.se>.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the 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.
+*/
+
+#ifndef __PINENTRYDIALOG_H__
+#define __PINENTRYDIALOG_H__
+
+#include <QDialog>
+#include <QStyle>
+
+#ifdef HAVE_W32CE_SYSTEM 
+#include <string>
+#endif
+
+typedef std::string secstring;
+typedef QString secqstring;
+#include <QLineEdit>
+typedef QLineEdit QSecureLineEdit;
+
+#include "pinentry.h"
+
+class QLabel;
+class QPushButton;
+class QString;
+class QProgressBar;
+
+QPixmap icon( QStyle::StandardPixmap which = QStyle::SP_CustomBase );
+
+void raiseWindow( QWidget* w );
+
+class PinEntryDialog : public QDialog {
+  Q_OBJECT
+
+  Q_PROPERTY( QString description READ description WRITE setDescription )
+  Q_PROPERTY( QString error READ error WRITE setError )
+  Q_PROPERTY( secqstring pin READ pin WRITE setPin )
+  Q_PROPERTY( QString prompt READ prompt WRITE setPrompt )
+public:
+  friend class PinEntryController; // TODO: remove when assuan lets me use Qt eventloop.
+  explicit PinEntryDialog( QWidget* parent = 0, const char* name = 0, bool modal = false, bool enable_quality_bar = false );
+
+  void setDescription( const QString& );
+  QString description() const;
+
+  void setError( const QString& );
+  QString error() const;
+
+  void setPin( const secqstring & );
+  secqstring pin() const;
+
+  void setPrompt( const QString& );
+  QString prompt() const;
+
+  void setOkText( const QString& );
+  void setCancelText( const QString& );
+
+  void setQualityBar( const QString& );
+  void setQualityBarTT( const QString& );
+
+  void setPinentryInfo (pinentry_t);
+
+public slots:
+  void updateQuality(const secqstring&);
+
+protected:
+  /* reimp */ void showEvent( QShowEvent* event );
+  /* reimp */ void hideEvent( QHideEvent* );
+  /* reimp */ void paintEvent( QPaintEvent* event );
+
+private:
+  QLabel*    _icon;
+  QLabel*    _desc;
+  QLabel*    _error;
+  QLabel*    _prompt;
+  QLabel*    _quality_bar_label;
+  QProgressBar* _quality_bar;
+  QSecureLineEdit* _edit;
+  QPushButton* _ok;
+  QPushButton* _cancel;
+  bool       _grabbed;
+  bool       _have_quality_bar;
+  pinentry_t _pinentry_info;
+};
+
+#endif // __PINENTRYDIALOG_H__
diff --git a/pinentrydialog.moc b/pinentrydialog.moc
new file mode 100644 (file)
index 0000000..c9a0930
--- /dev/null
@@ -0,0 +1,112 @@
+/****************************************************************************
+** Meta object code from reading C++ file 'pinentrydialog.h'
+**
+** Created: Mon Mar 16 13:03:03 2009
+**      by: The Qt Meta Object Compiler version 59 (Qt 4.4.1)
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#include "pinentrydialog.h"
+#if !defined(Q_MOC_OUTPUT_REVISION)
+#error "The header file 'pinentrydialog.h' doesn't include <QObject>."
+#elif Q_MOC_OUTPUT_REVISION < 59
+#error "This file was generated using the moc from 4.4.1. It"
+#error "cannot be used with the include files from this version of Qt."
+#error "(The moc has changed too much.)"
+#endif
+
+QT_BEGIN_MOC_NAMESPACE
+static const uint qt_meta_data_PinEntryDialog[] = {
+
+ // content:
+       1,       // revision
+       0,       // classname
+       0,    0, // classinfo
+       1,   10, // methods
+       4,   15, // properties
+       0,    0, // enums/sets
+
+ // slots: signature, parameters, type, tag, flags
+      16,   15,   15,   15, 0x0a,
+
+ // properties: name, type, flags
+      50,   42, 0x0a095103,
+      62,   42, 0x0a095103,
+      79,   68, 0x0009510b,
+      83,   42, 0x0a095103,
+
+       0        // eod
+};
+
+static const char qt_meta_stringdata_PinEntryDialog[] = {
+    "PinEntryDialog\0\0updateQuality(secqstring)\0"
+    "QString\0description\0error\0secqstring\0"
+    "pin\0prompt\0"
+};
+
+const QMetaObject PinEntryDialog::staticMetaObject = {
+    { &QDialog::staticMetaObject, qt_meta_stringdata_PinEntryDialog,
+      qt_meta_data_PinEntryDialog, 0 }
+};
+
+const QMetaObject *PinEntryDialog::metaObject() const
+{
+    return &staticMetaObject;
+}
+
+void *PinEntryDialog::qt_metacast(const char *_clname)
+{
+    if (!_clname) return 0;
+    if (!strcmp(_clname, qt_meta_stringdata_PinEntryDialog))
+        return static_cast<void*>(const_cast< PinEntryDialog*>(this));
+    return QDialog::qt_metacast(_clname);
+}
+
+int PinEntryDialog::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+    _id = QDialog::qt_metacall(_c, _id, _a);
+    if (_id < 0)
+        return _id;
+    if (_c == QMetaObject::InvokeMetaMethod) {
+        switch (_id) {
+        case 0: updateQuality((*reinterpret_cast< const secqstring(*)>(_a[1]))); break;
+        }
+        _id -= 1;
+    }
+#ifndef QT_NO_PROPERTIES
+      else if (_c == QMetaObject::ReadProperty) {
+        void *_v = _a[0];
+        switch (_id) {
+        case 0: *reinterpret_cast< QString*>(_v) = description(); break;
+        case 1: *reinterpret_cast< QString*>(_v) = error(); break;
+        case 2: *reinterpret_cast< secqstring*>(_v) = pin(); break;
+        case 3: *reinterpret_cast< QString*>(_v) = prompt(); break;
+        }
+        _id -= 4;
+    } else if (_c == QMetaObject::WriteProperty) {
+        void *_v = _a[0];
+        switch (_id) {
+        case 0: setDescription(*reinterpret_cast< QString*>(_v)); break;
+        case 1: setError(*reinterpret_cast< QString*>(_v)); break;
+        case 2: setPin(*reinterpret_cast< secqstring*>(_v)); break;
+        case 3: setPrompt(*reinterpret_cast< QString*>(_v)); break;
+        }
+        _id -= 4;
+    } else if (_c == QMetaObject::ResetProperty) {
+        _id -= 4;
+    } else if (_c == QMetaObject::QueryPropertyDesignable) {
+        _id -= 4;
+    } else if (_c == QMetaObject::QueryPropertyScriptable) {
+        _id -= 4;
+    } else if (_c == QMetaObject::QueryPropertyStored) {
+        _id -= 4;
+    } else if (_c == QMetaObject::QueryPropertyEditable) {
+        _id -= 4;
+    } else if (_c == QMetaObject::QueryPropertyUser) {
+        _id -= 4;
+    }
+#endif // QT_NO_PROPERTIES
+    return _id;
+}
+QT_END_MOC_NAMESPACE
diff --git a/qrc_pinentry.cpp b/qrc_pinentry.cpp
new file mode 100644 (file)
index 0000000..d15f01b
--- /dev/null
@@ -0,0 +1,180 @@
+/****************************************************************************
+** Resource object code
+**
+** Created: Wed Feb 17 23:35:02 2010
+**      by: The Resource Compiler for Qt version 4.4.3
+**
+** WARNING! All changes made in this file will be lost!
+*****************************************************************************/
+
+#include <QtCore/qglobal.h>
+
+static const unsigned char qt_resource_data[] = {
+  // /home/marc/KDE/src/gnupg-backend/pinentry/qt4/document-encrypt.png
+  0x0,0x0,0x7,0x2b,
+  0x89,
+  0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,
+  0x0,0x0,0x30,0x0,0x0,0x0,0x30,0x8,0x6,0x0,0x0,0x0,0x57,0x2,0xf9,0x87,
+  0x0,0x0,0x0,0x4,0x73,0x42,0x49,0x54,0x8,0x8,0x8,0x8,0x7c,0x8,0x64,0x88,
+  0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0x5,0x31,0x0,0x0,0x5,0x31,
+  0x1,0xb7,0xed,0x28,0x52,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x53,0x6f,0x66,
+  0x74,0x77,0x61,0x72,0x65,0x0,0x77,0x77,0x77,0x2e,0x69,0x6e,0x6b,0x73,0x63,0x61,
+  0x70,0x65,0x2e,0x6f,0x72,0x67,0x9b,0xee,0x3c,0x1a,0x0,0x0,0x6,0xa8,0x49,0x44,
+  0x41,0x54,0x78,0xda,0xd5,0x59,0x4b,0x6c,0x55,0x45,0x18,0xfe,0x67,0xce,0x7d,0xf5,
+  0xfd,0xc0,0x82,0xb1,0xd,0xb,0xdd,0x11,0x34,0x46,0xd1,0xd,0x1b,0x42,0x4c,0x48,
+  0x31,0xb4,0x68,0x52,0x16,0xb8,0x31,0xae,0x4c,0xec,0x92,0x85,0xa9,0x8b,0x6e,0x8c,
+  0xb2,0x60,0xa9,0x21,0xee,0x5c,0xdb,0xf8,0x58,0xb9,0xa1,0x6d,0x60,0x61,0x42,0xb4,
+  0xe0,0x2,0x41,0xd,0x8,0xd1,0xb6,0x94,0x36,0x5c,0xfb,0xa6,0xbd,0xf7,0x9e,0x73,
+  0xc6,0xef,0xfb,0x73,0x99,0x73,0xe3,0xc5,0x40,0xd3,0x9e,0x5b,0x99,0xe4,0xe3,0x9f,
+  0x33,0x33,0x67,0xce,0xff,0xfd,0xaf,0x99,0x72,0x8d,0x73,0x4e,0x9e,0xe6,0x96,0x91,
+  0x14,0xda,0x8d,0x1b,0x37,0x72,0xd7,0xaf,0x5f,0x7f,0xb1,0x54,0x2a,0xbd,0xba,0xb9,
+  0xb9,0xc9,0xa1,0x2b,0xb3,0xb3,0xb3,0xd7,0x46,0x47,0x47,0xcb,0xb2,0xc3,0x6d,0xc7,
+  0x3c,0x30,0x3e,0x3e,0xbe,0xbf,0x52,0xa9,0x7c,0x8,0xa5,0x5f,0xc9,0x66,0xb3,0x2f,
+  0x37,0x37,0x37,0xe7,0x3b,0x3a,0x3a,0xc4,0x5a,0x2b,0x2b,0x2b,0x2b,0xb2,0xbc,0xbc,
+  0x5c,0xba,0x7f,0xff,0xfe,0x35,0xcc,0xff,0xb4,0x67,0xcf,0x9e,0xb3,0x43,0x43,0x43,
+  0x7f,0xfd,0x6f,0x8,0x4c,0x4c,0x4c,0x7c,0x10,0x86,0xe1,0x68,0x6b,0x6b,0x6b,0x4f,
+  0x77,0x77,0xb7,0xe4,0x72,0x39,0xe1,0xbe,0x4b,0x4b,0x4b,0x2a,0xf7,0xee,0xdd,0x2b,
+  0x50,0x5a,0xc7,0x17,0x16,0x16,0xe4,0xd2,0xa5,0x4b,0x45,0x90,0x1c,0x3d,0x75,0xea,
+  0xd4,0xe7,0xbb,0x4a,0x60,0x72,0x72,0xb2,0x17,0x8a,0x7f,0x89,0xee,0x1b,0x5d,0x5d,
+  0x5d,0x2,0xf,0xc8,0xad,0x5b,0xb7,0x64,0x71,0x71,0x51,0x15,0x6f,0x6b,0x6b,0x13,
+  0x63,0xc,0x3d,0xa0,0x63,0x50,0x5a,0xe,0x1e,0x3c,0x28,0xc7,0x8e,0x1d,0x93,0xa9,
+  0xa9,0x29,0x29,0x16,0x8b,0xe3,0xed,0xed,0xed,0xef,0x1e,0x3d,0x7a,0x74,0xb6,0xe1,
+  0x4,0xc6,0xc6,0xc6,0x72,0xb0,0xf6,0x1f,0xe8,0xf6,0xc1,0xf2,0x72,0xf7,0xee,0x5d,
+  0x86,0x89,0x74,0x76,0x76,0x4a,0x14,0x45,0x12,0xc7,0xb1,0x80,0x9c,0xca,0x20,0x8,
+  0x24,0x93,0xc9,0x28,0x90,0xb,0x32,0x3d,0x3d,0x2d,0xc3,0xc3,0xc3,0x3a,0x7f,0xf3,
+  0xe6,0xcd,0x99,0xde,0xde,0xde,0x17,0xe,0x1c,0x38,0x50,0x6e,0x24,0x1,0x86,0xcd,
+  0x37,0x78,0xf7,0xad,0x7c,0x3e,0x2f,0xb7,0x6f,0xdf,0x16,0xc4,0x3c,0xad,0x4e,0x8b,
+  0xff,0xd,0xa5,0x3f,0x3,0xa6,0x40,0x64,0xea,0xc1,0x83,0x7,0x24,0x70,0xa8,0x5c,
+  0x2e,0x1f,0x82,0x1c,0x46,0x5e,0x74,0x93,0xe0,0xd5,0xab,0x57,0x65,0x70,0x70,0x50,
+  0xf0,0x3e,0x3d,0xf7,0xed,0xe1,0xc3,0x87,0xdf,0x6e,0x18,0x81,0xb,0x17,0x2e,0x1c,
+  0x47,0x72,0x7e,0x7,0x8b,0x66,0x69,0x51,0x48,0x2a,0x41,0x12,0x5f,0x6d,0x6c,0x6c,
+  0xbc,0x7f,0xfa,0xf4,0xe9,0x45,0x79,0x44,0x3b,0x7f,0xfe,0x7c,0x17,0xac,0xfe,0x5,
+  0x3c,0x36,0x54,0x28,0x14,0xe4,0xf2,0xe5,0xcb,0x32,0x32,0x32,0x42,0x2f,0x84,0x20,
+  0x3e,0x8,0x12,0xdf,0xa7,0x4e,0xe0,0xe2,0xc5,0x8b,0x19,0x28,0x39,0x3,0xcb,0xed,
+  0xa3,0xd2,0xf3,0xf3,0xf3,0x6a,0x79,0xe4,0xc0,0xc8,0xc0,0xc0,0xc0,0xa7,0xf2,0x4,
+  0xed,0xdc,0xb9,0x73,0x1f,0xf5,0xf4,0xf4,0x7c,0xbc,0xbe,0xbe,0xae,0x89,0xdd,0xdf,
+  0xdf,0x2f,0x73,0x73,0x73,0xf3,0x6b,0x6b,0x6b,0x7d,0x47,0x8e,0x1c,0x9,0x65,0xb,
+  0xcd,0x6e,0x91,0x30,0xe3,0xfc,0x24,0x3e,0xba,0x8f,0xc9,0x39,0x33,0x33,0xa3,0xf1,
+  0xe,0x32,0xbf,0x42,0xf9,0xb3,0xf2,0x84,0xed,0xcc,0x99,0x33,0x9f,0x20,0xb1,0x7f,
+  0x69,0x6a,0x6a,0xd2,0xdc,0x41,0x69,0xa5,0x7,0xf7,0x61,0xea,0x24,0x20,0x69,0x12,
+  0x60,0xe2,0xf5,0xb3,0x9a,0xd0,0xea,0x54,0x9e,0x7,0x55,0x4b,0x4b,0xcb,0x9b,0x98,
+  0xda,0x8a,0x2b,0x1d,0x94,0x1e,0x0,0x1c,0x3c,0xc7,0x83,0x8f,0x15,0x8a,0xf9,0xd3,
+  0x9f,0x36,0x1,0x5a,0x8a,0xc9,0x28,0x48,0x4a,0x92,0xe1,0x47,0x57,0x4f,0x9c,0x38,
+  0x71,0x47,0xb6,0xd6,0xe8,0x85,0x3b,0x78,0x7f,0x81,0x7b,0xdd,0xbb,0x77,0x4f,0xe8,
+  0xd,0xe4,0xd5,0xa1,0xb4,0x9,0xb0,0x2c,0xf6,0x2,0xac,0xed,0x24,0xc1,0x4,0xfe,
+  0xdd,0x4f,0x6e,0x7d,0xaf,0x6b,0xf4,0x22,0xf,0x37,0x96,0x62,0xb4,0xde,0xb4,0x9,
+  0xd0,0x4a,0x9d,0xc,0x9f,0xd5,0xd5,0x55,0x12,0xe0,0x61,0x35,0xe9,0x27,0xb7,0xbe,
+  0xd7,0xf,0xc,0x41,0x1a,0xa4,0xda,0x3a,0xd3,0x26,0xc0,0x90,0x9,0xf0,0x61,0x86,
+  0xf,0xad,0xcf,0xa1,0x95,0x6d,0x10,0x58,0xe6,0x1e,0x2c,0x8,0xa8,0x40,0x1c,0xa,
+  0xd2,0x23,0x50,0xff,0x71,0x3d,0x84,0xd8,0x76,0x62,0xf,0x5f,0xce,0x1b,0x45,0x0,
+  0xc9,0xc7,0xc4,0xdb,0x2e,0x81,0x6d,0xef,0x91,0xd9,0xe,0x1,0x1e,0x42,0xdb,0x6d,
+  0x3c,0x91,0x7d,0x6b,0xb0,0x7,0xfc,0xc7,0x53,0xda,0x23,0x7d,0x2,0x8c,0xdf,0x6d,
+  0x36,0xee,0xf1,0xd4,0x12,0x60,0xe,0x30,0xc,0xd3,0xff,0x83,0xe6,0xc7,0xaf,0xdf,
+  0x71,0x2f,0xbd,0xe6,0xa4,0x38,0xdd,0x2d,0x8b,0xc5,0x66,0xdc,0x5d,0x22,0x9e,0x1,
+  0x1e,0x15,0x95,0x25,0xf6,0xeb,0x20,0xce,0xb1,0xdc,0x12,0xbc,0x2e,0x40,0xe1,0xbc,
+  0xe4,0xf2,0x39,0x55,0x3c,0x8b,0x3e,0x25,0xd,0x41,0x14,0x9a,0x72,0xd2,0xdd,0xd7,
+  0x25,0xd9,0x67,0x9c,0x5c,0x99,0xf8,0x59,0x8e,0xbf,0x37,0x66,0x76,0x2c,0x89,0x6d,
+  0x26,0x94,0x67,0xf7,0xff,0x26,0xdd,0x1d,0x7f,0xca,0xc6,0x52,0x28,0xeb,0xeb,0x4d,
+  0xb8,0x7,0x65,0x65,0x63,0xc3,0x0,0x56,0x36,0x36,0x45,0x4a,0x81,0x91,0x4d,0xeb,
+  0xa4,0xa4,0x88,0x25,0xb,0x80,0x0,0x94,0x34,0x92,0x27,0xf2,0x84,0x95,0x2,0x1c,
+  0x97,0x2f,0x20,0x81,0x5b,0x9c,0x34,0x17,0x80,0xf6,0xb2,0x74,0xf4,0x64,0xa5,0xe9,
+  0xb9,0xd7,0xc5,0xb4,0x3d,0x2f,0xc5,0xb9,0x62,0x7a,0x55,0xc8,0x18,0x7,0x65,0x8a,
+  0x92,0x33,0xeb,0x52,0xce,0xc4,0xb2,0x89,0x1d,0xd6,0x4c,0x20,0xad,0x90,0x65,0x44,
+  0x43,0x58,0xe0,0x15,0x81,0xb0,0x12,0x58,0x86,0x1a,0xde,0x81,0xcc,0x6,0xec,0x43,
+  0xe2,0x1d,0x95,0x58,0x97,0x6b,0x1,0x89,0x56,0x10,0x6c,0xc5,0x73,0x4b,0x9f,0x2e,
+  0xc4,0x9b,0xc,0xad,0x74,0x8,0x50,0xa9,0x28,0x22,0x2,0x71,0x84,0x33,0x12,0x39,
+  0xc6,0x32,0x89,0x19,0x82,0x4a,0x60,0xdc,0xa2,0xaf,0x74,0x1,0x84,0x90,0xce,0x13,
+  0xb1,0x44,0x92,0xc1,0x12,0x23,0xb1,0xe5,0xd7,0x1d,0xd6,0xc6,0x80,0xc3,0x1c,0xde,
+  0xe1,0x46,0x0,0xae,0x16,0xe9,0x10,0xb0,0x96,0xd6,0x73,0x30,0x25,0x3e,0x8a,0x8f,
+  0x84,0xb4,0x96,0xe8,0x4c,0x95,0x0,0x3e,0xc,0x38,0x6b,0x34,0x74,0x38,0x19,0x83,
+  0x44,0x88,0xe1,0x80,0xd6,0xd5,0x57,0x23,0x90,0xc7,0x32,0x40,0x42,0xc,0x68,0x1d,
+  0xa8,0x0,0xbc,0xd9,0x2,0xd6,0xa6,0xe4,0x1,0xdf,0x9c,0xc4,0x80,0x8b,0x61,0xb5,
+  0xc0,0xd1,0x60,0x0,0x65,0xa4,0x16,0x57,0xc3,0x1a,0xc7,0x2e,0x43,0x88,0xc4,0x54,
+  0x5a,0x8c,0x5,0xec,0x63,0x5c,0x3,0x5,0x2f,0x3a,0x1a,0xc2,0x71,0x4d,0x6,0x32,
+  0x20,0x68,0x98,0xd4,0x3c,0xe0,0xc3,0xa8,0xea,0x7f,0xc8,0x90,0xa,0x78,0x44,0x40,
+  0x88,0xb9,0x58,0x17,0x92,0x26,0x63,0x5f,0x9f,0xc4,0xa8,0x53,0xac,0x5f,0x6b,0xa2,
+  0x8,0x88,0x51,0x9d,0x1c,0x40,0x19,0x81,0x19,0x90,0xb6,0x7,0x18,0x46,0x21,0xc3,
+  0xc4,0x44,0x4c,0x68,0x40,0x3c,0xb2,0x81,0xc6,0x35,0x74,0xd7,0xf0,0xf1,0x49,0x5c,
+  0xcd,0x1,0xed,0x5b,0x63,0x28,0x81,0x98,0xde,0x21,0x4f,0xcd,0x29,0xb,0x18,0x1a,
+  0x26,0x5d,0xf,0xf8,0xd0,0x96,0xd8,0x51,0x51,0x42,0x95,0xa8,0xc2,0xe8,0x58,0x54,
+  0x55,0xc0,0xe9,0xba,0x2c,0x3d,0xa2,0x4a,0x87,0x21,0xc3,0xc9,0xe1,0x3c,0x88,0xa1,
+  0xb0,0xd3,0x67,0x74,0x7d,0x75,0x13,0xd1,0x87,0x74,0x3d,0x60,0x4c,0x2d,0x8c,0xa2,
+  0x36,0x3f,0xf8,0x64,0xf9,0xaf,0x4a,0x5a,0x3f,0xe4,0x70,0xd5,0x3,0xde,0x2b,0x55,
+  0x90,0x8c,0x46,0x8d,0x42,0x14,0xb6,0x31,0xb7,0x51,0x63,0x34,0x79,0x21,0x1d,0xa4,
+  0xa9,0x8b,0x71,0x6d,0xec,0x13,0x31,0xd7,0xea,0x9c,0xe,0x26,0x9c,0xd,0xbc,0x80,
+  0xb9,0x10,0x79,0x0,0xaf,0xd9,0xf4,0xaf,0xd3,0xac,0xd1,0x55,0xe8,0x79,0x60,0x7c,
+  0x8,0x51,0xb9,0x84,0x84,0xe6,0x8a,0xf7,0x54,0xc6,0x5b,0xd9,0x2b,0xf,0x19,0xd5,
+  0x78,0x42,0x47,0xf0,0x9e,0x6e,0x90,0x26,0x81,0x58,0x15,0x73,0x80,0x9,0x20,0x81,
+  0x87,0xa,0xc4,0x80,0xf,0x5,0xd1,0x40,0xaa,0x3b,0xc1,0xf9,0x2e,0xc7,0x95,0x84,
+  0xca,0x8,0x48,0xc8,0x89,0x21,0x4c,0x63,0x42,0x28,0x49,0x5c,0xab,0x32,0xf1,0x2,
+  0x51,0x1b,0x2a,0xc6,0xaf,0xe7,0x69,0x9b,0x9,0x9c,0x5f,0x1f,0x86,0x56,0x72,0x2e,
+  0xd9,0x47,0x20,0xd1,0x69,0xc,0x1,0x6b,0x1f,0x22,0xae,0xb9,0x4a,0xd4,0x12,0x20,
+  0xa1,0xc4,0xb,0xc9,0x5a,0x2d,0xa3,0x94,0x80,0xf8,0xbc,0xa8,0xae,0xda,0xb5,0x9f,
+  0x98,0x18,0xbf,0x80,0xd4,0x82,0x25,0x93,0xe3,0xfe,0x0,0xa4,0x7,0x24,0x88,0x94,
+  0x48,0x12,0xff,0x9,0x39,0x51,0xd8,0xc6,0x11,0x88,0x63,0x8f,0x5a,0x2b,0x7a,0xa5,
+  0xd9,0xa2,0x88,0xb7,0x21,0xab,0xa7,0xad,0x88,0xc1,0xb3,0x55,0xeb,0x4b,0x5,0x28,
+  0x63,0x75,0xe,0xa3,0x15,0xbd,0x5e,0x35,0xa2,0xa,0xd1,0xca,0xa,0xad,0x3e,0xf8,
+  0x6c,0xd,0x91,0xa0,0x2e,0x17,0xd0,0x83,0xe2,0x3c,0x7d,0x35,0x79,0x6b,0xae,0x14,
+  0x9a,0xd0,0x3c,0x3,0x38,0xaf,0x30,0x9c,0x48,0x9f,0x0,0x13,0x53,0xc1,0xaa,0xe1,
+  0xe3,0x9f,0xa,0xb8,0x38,0xa2,0xf2,0xe8,0xf8,0x3c,0xd4,0x6b,0x83,0xf5,0x57,0x8a,
+  0x8,0x10,0x26,0x31,0x43,0x9,0xf0,0x21,0x87,0x7e,0xc,0xb8,0xdd,0xfc,0x99,0xd5,
+  0xd7,0x7f,0xf,0x25,0x61,0xab,0xca,0x9,0x9,0xb0,0x2f,0xc9,0x19,0x91,0x24,0x7d,
+  0x42,0x64,0xb7,0x8,0x38,0x47,0xc4,0x2a,0x13,0xab,0xd6,0xa2,0x76,0x6d,0x1d,0x59,
+  0xc0,0xed,0x2e,0x1,0x7f,0x18,0x29,0x1e,0x55,0x6a,0x3d,0x89,0xda,0xd2,0x5b,0x87,
+  0x54,0xff,0x5b,0x25,0xfd,0xf6,0x14,0x12,0x48,0xe1,0x97,0x7a,0x5f,0xce,0x32,0x40,
+  0xf0,0x18,0x58,0x2f,0x13,0x18,0x2f,0x89,0xfa,0xe6,0xaa,0x88,0xbd,0x4c,0x10,0x3d,
+  0x94,0x8f,0x41,0x48,0x9d,0x6b,0x9,0x50,0xe9,0xa0,0xaa,0x74,0x96,0x72,0x87,0x61,
+  0xab,0x8a,0x85,0x3b,0x88,0xa,0x50,0x66,0xff,0xbf,0x3c,0x60,0xeb,0x91,0x58,0xfd,
+  0x31,0xb0,0x89,0xe2,0xa,0xa9,0xb3,0xb4,0x87,0x7f,0xe,0xeb,0x3d,0x50,0xef,0x1d,
+  0xc2,0xfd,0x4b,0xe1,0x7f,0x0,0xd8,0x6e,0xc6,0xdd,0x5d,0xd6,0xb,0x18,0x0,0x0,
+  0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82,
+  
+};
+
+static const unsigned char qt_resource_name[] = {
+  // document-encrypt.png
+  0x0,0x14,
+  0x8,0xbf,0x25,0x67,
+  0x0,0x64,
+  0x0,0x6f,0x0,0x63,0x0,0x75,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x2d,0x0,0x65,0x0,0x6e,0x0,0x63,0x0,0x72,0x0,0x79,0x0,0x70,0x0,0x74,0x0,0x2e,
+  0x0,0x70,0x0,0x6e,0x0,0x67,
+  
+};
+
+static const unsigned char qt_resource_struct[] = {
+  // :
+  0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,
+  // :/document-encrypt.png
+  0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,
+
+};
+
+QT_BEGIN_NAMESPACE
+
+extern bool qRegisterResourceData
+    (int, const unsigned char *, const unsigned char *, const unsigned char *);
+
+extern bool qUnregisterResourceData
+    (int, const unsigned char *, const unsigned char *, const unsigned char *);
+
+QT_END_NAMESPACE
+
+
+int QT_MANGLE_NAMESPACE(qInitResources_pinentry)()
+{
+    QT_PREPEND_NAMESPACE(qRegisterResourceData)
+        (0x01, qt_resource_struct, qt_resource_name, qt_resource_data);
+    return 1;
+}
+
+Q_CONSTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qInitResources_pinentry))
+
+int QT_MANGLE_NAMESPACE(qCleanupResources_pinentry)()
+{
+    QT_PREPEND_NAMESPACE(qUnregisterResourceData)
+       (0x01, qt_resource_struct, qt_resource_name, qt_resource_data);
+    return 1;
+}
+
+Q_DESTRUCTOR_FUNCTION(QT_MANGLE_NAMESPACE(qCleanupResources_pinentry))
+
diff --git a/secmem-util.c b/secmem-util.c
new file mode 100644 (file)
index 0000000..7f616f2
--- /dev/null
@@ -0,0 +1,155 @@
+/* Quintuple Agent
+ * Copyright (C) 1999 Robert Bihlmeyer <robbe@orcus.priv.at>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE 1
+
+#ifndef HAVE_W32CE_SYSTEM
+# include <unistd.h>
+# include <errno.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "secmem-util.h"
+
+#ifndef HAVE_DOSISH_SYSTEM
+static int uid_set = 0;
+static uid_t real_uid, file_uid;
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+/* Write DATA of size BYTES to FD, until all is written or an error
+   occurs.  */
+ssize_t 
+xwrite(int fd, const void *data, size_t bytes)
+{
+#ifdef HAVE_W32CE_SYSTEM
+  // FIXME: Disabled xwrite on WinCE
+  return 0;
+#else
+  char *ptr;
+  size_t todo;
+  ssize_t written = 0;
+
+  for (ptr = (char *)data, todo = bytes; todo; ptr += written, todo -= written)
+    {
+      do
+        written = write (fd, ptr, todo);
+      while (
+#ifdef HAVE_W32CE_SYSTEM
+             0
+#else
+             written == -1 && errno == EINTR
+#endif
+             );
+      if (written < 0)
+        break;
+    }
+  return written;
+#endif
+}
+
+#if 0
+extern int debug;
+
+int 
+debugmsg(const char *fmt, ...)
+{
+  va_list va;
+  int ret;
+
+  if (debug) {
+    va_start(va, fmt);
+    fprintf(stderr, "\e[4m");
+    ret = vfprintf(stderr, fmt, va);
+    fprintf(stderr, "\e[24m");
+    va_end(va);
+    return ret;
+  } else
+    return 0;
+}
+#endif
+
+/* initialize uid variables */
+#ifndef HAVE_DOSISH_SYSTEM
+static void 
+init_uids(void)
+{
+  real_uid = getuid();
+  file_uid = geteuid();
+  uid_set = 1;
+}
+#endif
+
+
+#if 0 /* Not used. */
+/* lower privileges to the real user's */
+void 
+lower_privs()
+{
+  if (!uid_set)
+    init_uids();
+  if (real_uid != file_uid) {
+#ifdef HAVE_SETEUID
+    if (seteuid(real_uid) < 0) {
+      perror("lowering privileges failed");
+      exit(EXIT_FAILURE);
+    }
+#else
+    fprintf(stderr, _("Warning: running q-agent setuid on this system is dangerous\n"));
+#endif /* HAVE_SETEUID */
+  }
+}
+#endif /* if 0 */
+
+#if 0 /* Not used. */
+/* raise privileges to the effective user's */
+void 
+raise_privs()
+{
+  assert(real_uid >= 0);       /* lower_privs() must be called before this */
+#ifdef HAVE_SETEUID
+  if (real_uid != file_uid && seteuid(file_uid) < 0) {
+   perror("Warning: raising privileges failed");
+  }
+#endif /* HAVE_SETEUID */
+}
+#endif /* if 0 */
+
+/* drop all additional privileges */
+void 
+drop_privs()
+{
+#ifndef HAVE_DOSISH_SYSTEM
+  if (!uid_set)
+    init_uids();
+  if (real_uid != file_uid) {
+    if (setuid(real_uid) < 0) {
+      perror("dropping privileges failed");
+      exit(EXIT_FAILURE);
+    }
+    file_uid = real_uid;
+  }
+#endif
+}
diff --git a/secmem-util.h b/secmem-util.h
new file mode 100644 (file)
index 0000000..c6850ba
--- /dev/null
@@ -0,0 +1,70 @@
+/* Quintuple Agent utilities
+ * Copyright (C) 1999 Robert Bihlmeyer <robbe@orcus.priv.at>
+ * Copyright (C) 2003 g10 Code GmbH
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#ifndef HAVE_W32CE_SYSTEM
+# include <sys/types.h>
+#else
+typedef long ssize_t;
+#endif
+
+#ifndef HAVE_BYTE_TYPEDEF
+# undef byte      
+# ifdef __riscos__
+    /* Norcroft treats char == unsigned char but char* != unsigned char*  */
+    typedef char byte;
+# else 
+    typedef unsigned char byte;
+# endif 
+# define HAVE_BYTE_TYPEDEF
+#endif
+
+#ifndef HAVE_ULONG_TYPEDEF
+# undef ulong     
+  typedef unsigned long ulong;
+# define HAVE_ULONG_TYPEDEF
+#endif
+
+
+ssize_t xwrite(int, const void *, size_t); /* write until finished */
+int debugmsg(const char *, ...); /* output a debug message if debugging==on */
+void drop_privs(void);         /* finally drop privileges */
+
+
+/* To avoid that a compiler optimizes certain memset calls away, these
+   macros may be used instead. */
+#define wipememory2(_ptr,_set,_len) do { \
+              volatile char *_vptr=(volatile char *)(_ptr); \
+              size_t _vlen=(_len); \
+              while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
+                  } while(0)
+#define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
+#define wipe(_ptr,_len)       wipememory2(_ptr,0,_len)
+
+
+
+
+#define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
+                     *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+
+
+#endif
diff --git a/secmem.c b/secmem.c
new file mode 100644 (file)
index 0000000..1c6a742
--- /dev/null
+++ b/secmem.c
@@ -0,0 +1,458 @@
+/* secmem.c  - memory allocation from a secure heap
+ *     Copyright (C) 1998, 1999, 2003 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef HAVE_W32CE_SYSTEM
+#include <unistd.h>
+#include <errno.h>
+#endif
+#include <stdarg.h>
+#if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
+# include <sys/mman.h>
+# include <sys/types.h>
+# include <fcntl.h>
+# ifdef USE_CAPABILITIES
+#  include <sys/capability.h>
+# endif
+#endif
+#include <string.h>
+
+#include "memory.h"
+
+#ifdef ORIGINAL_GPG_VERSION
+#include "types.h"
+#include "util.h"
+#else /* ORIGINAL_GPG_VERSION */
+
+#include "secmem-util.h"
+
+typedef union {
+    int a;
+    short b;
+    char c[1];
+    long d;
+#ifdef HAVE_U64_TYPEDEF
+    u64 e;
+#endif
+    float f;
+    double g;
+} PROPERLY_ALIGNED_TYPE;
+
+#define log_error log_info
+#define log_bug log_fatal
+
+void 
+log_info(char *template, ...)
+{
+  va_list args;
+  
+  va_start(args, template);
+  vfprintf(stderr, template, args);
+  va_end(args);
+}
+
+void 
+log_fatal(char *template, ...)
+{
+  va_list args;
+  
+  va_start(args, template);
+  vfprintf(stderr, template, args);
+  va_end(args);
+  exit(EXIT_FAILURE);
+}
+
+#endif /* ORIGINAL_GPG_VERSION */
+
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#  define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#define DEFAULT_POOLSIZE 16384
+
+typedef struct memblock_struct MEMBLOCK;
+struct memblock_struct {
+    unsigned size;
+    union {
+       MEMBLOCK *next;
+       PROPERLY_ALIGNED_TYPE aligned;
+    } u;
+};
+
+
+
+static void  *pool;
+static volatile int pool_okay; /* may be checked in an atexit function */
+static int   pool_is_mmapped;
+static size_t poolsize; /* allocated length */
+static size_t poollen; /* used length */
+static MEMBLOCK *unused_blocks;
+static unsigned max_alloced;
+static unsigned cur_alloced;
+static unsigned max_blocks;
+static unsigned cur_blocks;
+static int disable_secmem;
+static int show_warning;
+static int no_warning;
+static int suspend_warning;
+
+
+static void
+print_warn(void)
+{
+    if( !no_warning )
+       log_info("Warning: using insecure memory!\n");
+}
+
+
+static void
+lock_pool( void *p, size_t n )
+{
+#if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
+    int err;
+
+    cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
+    err = mlock( p, n );
+    if( err && errno )
+       err = errno;
+    cap_set_proc( cap_from_text("cap_ipc_lock+p") );
+
+    if( err ) {
+       if( errno != EPERM
+         #ifdef EAGAIN  /* OpenBSD returns this */
+           && errno != EAGAIN
+         #endif
+         )
+           log_error("can't lock memory: %s\n", strerror(err));
+       show_warning = 1;
+    }
+
+#elif defined(HAVE_MLOCK)
+    uid_t uid;
+    int err;
+
+    uid = getuid();
+
+#ifdef HAVE_BROKEN_MLOCK
+    if( uid ) {
+       errno = EPERM;
+       err = errno;
+    }
+    else {
+       err = mlock( p, n );
+       if( err && errno )
+           err = errno;
+    }
+#else
+    err = mlock( p, n );
+    if( err && errno )
+       err = errno;
+#endif
+
+    if( uid && !geteuid() ) {
+       if( setuid( uid ) || getuid() != geteuid()  )
+           log_fatal("failed to reset uid: %s\n", strerror(errno));
+    }
+
+    if( err ) {
+       if( errno != EPERM
+#ifdef EAGAIN  /* OpenBSD returns this */
+           && errno != EAGAIN
+#endif
+         )
+           log_error("can't lock memory: %s\n", strerror(err));
+       show_warning = 1;
+    }
+
+#else
+    log_info("Please note that you don't have secure memory on this system\n");
+#endif
+}
+
+
+static void
+init_pool( size_t n)
+{
+    size_t pgsize;
+
+    poolsize = n;
+
+    if( disable_secmem )
+       log_bug("secure memory is disabled");
+
+#ifdef HAVE_GETPAGESIZE
+    pgsize = getpagesize();
+#else
+    pgsize = 4096;
+#endif
+
+#if HAVE_MMAP
+    poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
+# ifdef MAP_ANONYMOUS
+       pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
+                                MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+# else /* map /dev/zero instead */
+    {  int fd;
+
+       fd = open("/dev/zero", O_RDWR);
+       if( fd == -1 ) {
+           log_error("can't open /dev/zero: %s\n", strerror(errno) );
+           pool = (void*)-1;
+       }
+       else {
+           pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
+                                     MAP_PRIVATE, fd, 0);
+           close (fd);
+       }
+    }
+# endif
+    if( pool == (void*)-1 )
+       log_info("can't mmap pool of %u bytes: %s - using malloc\n",
+                           (unsigned)poolsize, strerror(errno));
+    else {
+       pool_is_mmapped = 1;
+       pool_okay = 1;
+    }
+
+#endif
+    if( !pool_okay ) {
+       pool = malloc( poolsize );
+       if( !pool )
+           log_fatal("can't allocate memory pool of %u bytes\n",
+                                                      (unsigned)poolsize);
+       else
+           pool_okay = 1;
+    }
+    lock_pool( pool, poolsize );
+    poollen = 0;
+}
+
+
+/* concatenate unused blocks */
+static void
+compress_pool(void)
+{
+    /* fixme: we really should do this */
+}
+
+void
+secmem_set_flags( unsigned flags )
+{
+    int was_susp = suspend_warning;
+
+    no_warning = flags & 1;
+    suspend_warning = flags & 2;
+
+    /* and now issue the warning if it is not longer suspended */
+    if( was_susp && !suspend_warning && show_warning ) {
+       show_warning = 0;
+       print_warn();
+    }
+}
+
+unsigned
+secmem_get_flags(void)
+{
+    unsigned flags;
+
+    flags  = no_warning      ? 1:0;
+    flags |= suspend_warning ? 2:0;
+    return flags;
+}
+
+void
+secmem_init( size_t n )
+{
+    if( !n ) {
+#ifdef USE_CAPABILITIES
+       /* drop all capabilities */
+       cap_set_proc( cap_from_text("all-eip") );
+
+#elif !defined(HAVE_DOSISH_SYSTEM)
+       uid_t uid;
+
+       disable_secmem=1;
+       uid = getuid();
+       if( uid != geteuid() ) {
+           if( setuid( uid ) || getuid() != geteuid() )
+               log_fatal("failed to drop setuid\n" );
+       }
+#endif
+    }
+    else {
+       if( n < DEFAULT_POOLSIZE )
+           n = DEFAULT_POOLSIZE;
+       if( !pool_okay )
+           init_pool(n);
+       else
+           log_error("Oops, secure memory pool already initialized\n");
+    }
+}
+
+
+void *
+secmem_malloc( size_t size )
+{
+    MEMBLOCK *mb, *mb2;
+    int compressed=0;
+
+    if( !pool_okay ) {
+       log_info(
+       "operation is not possible without initialized secure memory\n");
+       log_info("(you may have used the wrong program for this task)\n");
+       exit(2);
+    }
+    if( show_warning && !suspend_warning ) {
+       show_warning = 0;
+       print_warn();
+    }
+
+    /* blocks are always a multiple of 32 */
+    size += sizeof(MEMBLOCK);
+    size = ((size + 31) / 32) * 32;
+
+  retry:
+    /* try to get it from the used blocks */
+    for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
+       if( mb->size >= size ) {
+           if( mb2 )
+               mb2->u.next = mb->u.next;
+           else
+               unused_blocks = mb->u.next;
+           goto leave;
+       }
+    /* allocate a new block */
+    if( (poollen + size <= poolsize) ) {
+       mb = (void*)((char*)pool + poollen);
+       poollen += size;
+       mb->size = size;
+    }
+    else if( !compressed ) {
+       compressed=1;
+       compress_pool();
+       goto retry;
+    }
+    else
+       return NULL;
+
+  leave:
+    cur_alloced += mb->size;
+    cur_blocks++;
+    if( cur_alloced > max_alloced )
+       max_alloced = cur_alloced;
+    if( cur_blocks > max_blocks )
+       max_blocks = cur_blocks;
+
+    return &mb->u.aligned.c;
+}
+
+
+void *
+secmem_realloc( void *p, size_t newsize )
+{
+    MEMBLOCK *mb;
+    size_t size;
+    void *a;
+
+    mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
+    size = mb->size;
+    if( newsize < size )
+       return p; /* it is easier not to shrink the memory */
+    a = secmem_malloc( newsize );
+    memcpy(a, p, size);
+    memset((char*)a+size, 0, newsize-size);
+    secmem_free(p);
+    return a;
+}
+
+
+void
+secmem_free( void *a )
+{
+    MEMBLOCK *mb;
+    size_t size;
+
+    if( !a )
+       return;
+
+    mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
+    size = mb->size;
+    /* This does not make much sense: probably this memory is held in the
+     * cache. We do it anyway: */
+    wipememory2(mb, 0xff, size );
+    wipememory2(mb, 0xaa, size );
+    wipememory2(mb, 0x55, size );
+    wipememory2(mb, 0x00, size );
+    mb->size = size;
+    mb->u.next = unused_blocks;
+    unused_blocks = mb;
+    cur_blocks--;
+    cur_alloced -= size;
+}
+
+int
+m_is_secure( const void *p )
+{
+    return p >= pool && p < (void*)((char*)pool+poolsize);
+}
+
+void
+secmem_term()
+{
+    if( !pool_okay )
+       return;
+
+    wipememory2( pool, 0xff, poolsize);
+    wipememory2( pool, 0xaa, poolsize);
+    wipememory2( pool, 0x55, poolsize);
+    wipememory2( pool, 0x00, poolsize);
+#if HAVE_MMAP
+    if( pool_is_mmapped )
+       munmap( pool, poolsize );
+#endif
+    pool = NULL;
+    pool_okay = 0;
+    poolsize=0;
+    poollen=0;
+    unused_blocks=NULL;
+}
+
+
+void
+secmem_dump_stats()
+{
+    if( disable_secmem )
+       return;
+    fprintf(stderr,
+               "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
+               cur_alloced, max_alloced, cur_blocks, max_blocks,
+               (ulong)poollen, (ulong)poolsize );
+}
+
+
+size_t 
+secmem_get_max_size (void)
+{
+  return poolsize;
+}