Import kldap_16.04.2.orig.tar.xz
authorMaximiliano Curia <maxy@debian.org>
Sun, 19 Jun 2016 07:43:12 +0000 (08:43 +0100)
committerMaximiliano Curia <maxy@debian.org>
Sun, 19 Jun 2016 07:43:12 +0000 (08:43 +0100)
[dgit import orig kldap_16.04.2.orig.tar.xz]

52 files changed:
.arcconfig [new file with mode: 0644]
.reviewboardrc [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
COPYING.LIB [new file with mode: 0644]
KF5LdapConfig.cmake.in [new file with mode: 0644]
Mainpage.dox [new file with mode: 0644]
autotests/CMakeLists.txt [new file with mode: 0644]
autotests/testkldap.cpp [new file with mode: 0644]
autotests/testkldap.h [new file with mode: 0644]
autotests/testurl.txt.tmpl [new file with mode: 0644]
cmake/CMakeLists.txt [new file with mode: 0644]
cmake/COPYING-CMAKE-SCRIPTS [new file with mode: 0644]
cmake/FindLdap.cmake [new file with mode: 0644]
cmake/FindSasl2.cmake [new file with mode: 0644]
metainfo.yaml [new file with mode: 0644]
src/CMakeLists.txt [new file with mode: 0644]
src/Messages.sh [new file with mode: 0644]
src/ber.cpp [new file with mode: 0644]
src/ber.h [new file with mode: 0644]
src/kldap_config.h.cmake [new file with mode: 0644]
src/ldapattributeproxymodel.cpp [new file with mode: 0644]
src/ldapattributeproxymodel.h [new file with mode: 0644]
src/ldapconfigwidget.cpp [new file with mode: 0644]
src/ldapconfigwidget.h [new file with mode: 0644]
src/ldapconnection.cpp [new file with mode: 0644]
src/ldapconnection.h [new file with mode: 0644]
src/ldapcontrol.cpp [new file with mode: 0644]
src/ldapcontrol.h [new file with mode: 0644]
src/ldapdefs.h [new file with mode: 0644]
src/ldapdn.cpp [new file with mode: 0644]
src/ldapdn.h [new file with mode: 0644]
src/ldapmodel.cpp [new file with mode: 0644]
src/ldapmodel.h [new file with mode: 0644]
src/ldapmodel_p.cpp [new file with mode: 0644]
src/ldapmodel_p.h [new file with mode: 0644]
src/ldapmodelnode_p.cpp [new file with mode: 0644]
src/ldapmodelnode_p.h [new file with mode: 0644]
src/ldapobject.cpp [new file with mode: 0644]
src/ldapobject.h [new file with mode: 0644]
src/ldapoperation.cpp [new file with mode: 0644]
src/ldapoperation.h [new file with mode: 0644]
src/ldapsearch.cpp [new file with mode: 0644]
src/ldapsearch.h [new file with mode: 0644]
src/ldapserver.cpp [new file with mode: 0644]
src/ldapserver.h [new file with mode: 0644]
src/ldapstructureproxymodel.cpp [new file with mode: 0644]
src/ldapstructureproxymodel.h [new file with mode: 0644]
src/ldapurl.cpp [new file with mode: 0644]
src/ldapurl.h [new file with mode: 0644]
src/ldif.cpp [new file with mode: 0644]
src/ldif.h [new file with mode: 0644]
src/w32-ldap-help.h [new file with mode: 0644]

diff --git a/.arcconfig b/.arcconfig
new file mode 100644 (file)
index 0000000..20d53ee
--- /dev/null
@@ -0,0 +1,4 @@
+{
+  "phabricator.uri" : "https://phabricator.kde.org/project/profile/34/",
+  "history.immutable" : true
+}
diff --git a/.reviewboardrc b/.reviewboardrc
new file mode 100644 (file)
index 0000000..6bbbd89
--- /dev/null
@@ -0,0 +1,5 @@
+REVIEWBOARD_URL = "https://git.reviewboard.kde.org"
+REPOSITORY = "git://anongit.kde.org/kldap"
+BRANCH = "master"
+TARGET_GROUPS = "kdepimlibs"
+TARGET_PEOPLE = "mlaurent"
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0cfd988
--- /dev/null
@@ -0,0 +1,87 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(KLdap)
+
+# ECM setup
+find_package(ECM 5.19.0 CONFIG REQUIRED)
+set(CMAKE_MODULE_PATH ${KLdap_SOURCE_DIR}/cmake ${ECM_MODULE_PATH})
+
+include(GenerateExportHeader)
+include(ECMGenerateHeaders)
+include(ECMGeneratePriFile)
+include(ECMPackageConfigHelpers)
+include(ECMSetupVersion)
+include(FeatureSummary)
+include(KDEInstallDirs)
+include(KDECMakeSettings)
+include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
+include(ECMQtDeclareLoggingCategory)
+
+set(KF5_VERSION "5.19.0")
+set(KLDAP_LIB_VERSION "5.2.2")
+
+ecm_setup_version(${KLDAP_LIB_VERSION} VARIABLE_PREFIX KLDAP
+                        VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kldap_version.h"
+                        PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5LdapConfigVersion.cmake"
+                        SOVERSION 5
+)
+
+########### Find packages ###########
+find_package(KF5Completion ${KF5_VERSION} CONFIG REQUIRED)
+find_package(KF5WidgetsAddons ${KF5_VERSION} CONFIG REQUIRED)
+find_package(KF5I18n ${KF5_VERSION} CONFIG REQUIRED)
+
+
+find_package(Ldap)
+set_package_properties(Ldap PROPERTIES
+  TYPE RECOMMENDED
+  PURPOSE "Needed to provide LDAP functionality in KDE"
+)
+
+find_package(Sasl2)
+set_package_properties(Sasl2 PROPERTIES TYPE OPTIONAL)
+
+if (Ldap_FOUND)
+   set(LDAP_FOUND 1)
+endif()
+
+if (Sasl2_FOUND)
+   set(SASL2_FOUND 1)
+endif()
+
+add_definitions("-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII")
+add_definitions(-DTRANSLATION_DOMAIN=\"libkldap5\")
+
+########### CMake Config Files ###########
+set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5Ldap")
+
+ecm_configure_package_config_file(
+  "${CMAKE_CURRENT_SOURCE_DIR}/KF5LdapConfig.cmake.in"
+  "${CMAKE_CURRENT_BINARY_DIR}/KF5LdapConfig.cmake"
+  INSTALL_DESTINATION  ${CMAKECONFIG_INSTALL_DIR}
+)
+
+install(FILES
+  "${CMAKE_CURRENT_BINARY_DIR}/KF5LdapConfig.cmake"
+  "${CMAKE_CURRENT_BINARY_DIR}/KF5LdapConfigVersion.cmake"
+  DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
+  COMPONENT Devel
+)
+
+install(EXPORT KF5LdapTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KF5LdapTargets.cmake NAMESPACE KF5::)
+
+install(FILES
+   ${CMAKE_CURRENT_BINARY_DIR}/kldap_version.h
+   DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}
+   COMPONENT Devel
+)
+
+########### Targets ###########
+add_subdirectory(cmake)
+add_subdirectory(src)
+
+if(BUILD_TESTING)
+    add_subdirectory(autotests)
+endif()
+
+feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/COPYING.LIB b/COPYING.LIB
new file mode 100644 (file)
index 0000000..2d2d780
--- /dev/null
@@ -0,0 +1,510 @@
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+  When we speak of free software, we are referring to freedom of use,
+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 and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard.  To achieve this, non-free programs must
+be allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, 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 library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete 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 distribute a copy of this License along with the
+Library.
+
+  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.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, 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) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+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 Library, 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 Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you 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.
+
+  If distribution of 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 satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at least
+    three years, to give the same user the materials specified in
+    Subsection 6a, above, for a charge no more than the cost of
+    performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be 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.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library 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.
+
+  9. 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 Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+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 with
+this License.
+\f
+  11. 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 Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library 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 Library.
+
+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.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library 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.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+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 Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+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
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. 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 LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This 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.
+
+    This 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 this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or
+your school, if any, to sign a "copyright disclaimer" for the library,
+if necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James
+  Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/KF5LdapConfig.cmake.in b/KF5LdapConfig.cmake.in
new file mode 100644 (file)
index 0000000..057d7f6
--- /dev/null
@@ -0,0 +1,21 @@
+@PACKAGE_INIT@
+
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_MODULE_PATH})
+
+find_dependency(Ldap)
+find_dependency(Sasl2)
+
+include(FeatureSummary)
+
+set_package_properties(Ldap PROPERTIES
+  DESCRIPTION "LDAP (Lightweight Directory Access Protocol) libraries"
+  URL "http://www.openldap.org"
+  PURPOSE "Needed to provide LDAP functionality in KDE"
+)
+
+set_package_properties(Sasl2 PROPERTIES
+  DESCRIPTION "The Cyrus-sasl library"
+  URL "http://www.cyrussasl.org"
+)
+
+include("${CMAKE_CURRENT_LIST_DIR}/KF5LdapTargets.cmake")
diff --git a/Mainpage.dox b/Mainpage.dox
new file mode 100644 (file)
index 0000000..1de92ec
--- /dev/null
@@ -0,0 +1,22 @@
+/*!
+ * @mainpage kldap - an LDAP access API for KDE.
+ *
+ * @section purpose Purpose
+ * 
+ * LIBKLDAP 
+ *
+ * @section desc Description
+ *
+ * Allows LDAP accessing with a convenient Qt style C++ API.
+ *
+ * @authors György Szombathelyi \<gyurco@freemail.hu\>
+ *
+ * @maintainers György Szombathelyi \<gyurco@freemail.hu\>
+ *
+ * @licenses
+ * @lgpl
+ */
+
+// DOXYGEN_PROJECTNAME=KLDAP Library
+// DOXYGEN_REFERENCES = kdecore kdeui
+// DOXYGEN_EXCLUDE = scripts
diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1ac6183
--- /dev/null
@@ -0,0 +1,7 @@
+include(ECMAddTests)
+
+find_package(Qt5Test CONFIG REQUIRED)
+
+if(Ldap_FOUND)
+  ecm_add_tests(testkldap.cpp NAME_PREFIX "kldap-" LINK_LIBRARIES KF5::Ldap Qt5::Test)
+endif()
diff --git a/autotests/testkldap.cpp b/autotests/testkldap.cpp
new file mode 100644 (file)
index 0000000..3fa2230
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+  This file is part of libkdepim.
+
+  Copyright (c) 2004 Tobias Koenig <tokoe@kde.org>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "testkldap.h"
+
+#include "ldif.h"
+#include "ldapdn.h"
+#include "ldapurl.h"
+#include "ldapserver.h"
+#include "ldapconnection.h"
+#include "ldapmodel.h"
+#include "ldapoperation.h"
+#include "ldapsearch.h"
+#include "ber.h"
+
+#include <qdebug.h>
+#include <qtest.h>
+#include <QFile>
+QTEST_MAIN(KLdapTest)
+
+void KLdapTest::initTestCase()
+{
+    /*
+      Read in the connection details of an LDAP server to use for testing.
+      You should copy the file testurl.txt.tmpl to testurl.txt and specify a url in this file.
+      The specified server should not be a production server in case we break anything here.
+      You have been warned!
+    */
+    m_search = 0;
+    m_model = 0;
+
+    QString filename(QStringLiteral("testurl.txt"));
+    QFile file(filename);
+    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+        QTextStream stream(&file);
+        stream >> m_url;
+        file.close();
+    }
+//    else
+//        QCOMPARE( 0, 1 );
+
+    m_search = new LdapSearch;
+
+    /* Let's also create an LdapModel object */
+    m_model = new LdapModel(this);
+}
+
+void KLdapTest::testBer()
+{
+    Ber ber1, ber2, ber3, ber4, ber5, ber6, ber7;
+    Ber bber;
+    QByteArray flat;
+
+    int ainteger;
+    QByteArray aoctetString1, aoctetString2, aoctetString3;
+    QList<QByteArray> alist1, alist2;
+
+    int binteger;
+    QByteArray boctetString1, boctetString2, boctetString3;
+    QList<QByteArray> blist1, blist2;
+
+    aoctetString1 = "KDE";
+    aoctetString2 = "the";
+    aoctetString3 = "next generation";
+
+    alist1.append(aoctetString1);
+    alist1.append(aoctetString2);
+
+    alist2.append(aoctetString2);
+    alist2.append(aoctetString3);
+    alist2.append(aoctetString1);
+
+    ainteger = 23543;
+
+    ber1.printf(QStringLiteral("i"), ainteger);
+    ber2.printf(QStringLiteral("o"), &aoctetString1);
+    ber3.printf(QStringLiteral("O"), &aoctetString2);
+    ber4.printf(QStringLiteral("s"), &aoctetString3);
+    ber5.printf(QStringLiteral("{v}"), &alist1);
+    ber6.printf(QStringLiteral("{V}"), &alist2);
+    ber7.printf(QStringLiteral("oi{v}O"), &aoctetString1, ainteger, &alist2, &aoctetString2);
+
+    //test integer:
+    bber = ber1;
+    bber.scanf(QStringLiteral("i"), &binteger);
+    QCOMPARE(ainteger, binteger);
+
+    //test octet strings:
+    bber = ber2;
+    bber.scanf(QStringLiteral("o"), &boctetString1);
+    QCOMPARE(aoctetString1, boctetString1);
+    bber = ber3;
+    bber.scanf(QStringLiteral("o"), &boctetString2);
+    QCOMPARE(aoctetString2, boctetString2);
+    bber = ber4;
+    bber.scanf(QStringLiteral("o"), &boctetString3);
+    QCOMPARE(aoctetString3, boctetString3);
+
+    //test sequence of octet strings:
+    bber = ber5;
+    bber.scanf(QStringLiteral("v"), &blist1);
+    QCOMPARE(alist1, blist1);
+
+    bber = ber6;
+    bber.scanf(QStringLiteral("v"), &blist2);
+    QCOMPARE(alist2, blist2);
+
+    //complex tests
+    boctetString1 = boctetString2 = boctetString3 = QByteArray();
+    binteger = 0;
+    blist1.clear();
+    blist2.clear();
+
+    bber = ber7;
+    bber.scanf(QStringLiteral("oivO"), &boctetString1, &binteger, &blist2, &boctetString2);
+    QCOMPARE(aoctetString1, boctetString1);
+    QCOMPARE(aoctetString2, boctetString2);
+    QCOMPARE(alist2, blist2);
+    QCOMPARE(ainteger, binteger);
+}
+
+void KLdapTest::cleanupTestCase()
+{
+    delete m_search;
+    delete m_model;
+}
+
+void KLdapTest::testLdapUrl()
+{
+    // Test LdapUrl using some hardwired values so that we know what to compare to
+    LdapUrl url;
+    bool critical;
+
+    url.setUrl(QStringLiteral("ldap://cn=manager,dc=kde,dc=org:password@localhost:3999/"
+                             "dc=kde,dc=org?cn,mail?sub?(objectClass=*)?x-dir=base"));
+    url.parseQuery();
+
+    QCOMPARE(url.userName(), QString::fromLatin1("cn=manager,dc=kde,dc=org"));
+    QCOMPARE(url.password(), QString::fromLatin1("password"));
+    QCOMPARE(url.dn(), LdapDN(QStringLiteral("dc=kde,dc=org")));
+    QCOMPARE(url.scope(), LdapUrl::Sub);
+    QCOMPARE(url.attributes().at(0), QString::fromLatin1("cn"));
+    QCOMPARE(url.attributes().at(1), QString::fromLatin1("mail"));
+    QCOMPARE(url.filter(), QString::fromLatin1("(objectClass=*)"));
+    QCOMPARE(url.extension(QString::fromLatin1("x-dir"), critical),
+             QString::fromLatin1("base"));
+}
+
+void KLdapTest::testLdapConnection()
+{
+    // Try to connect using an LdapUrl (read in from testurl.txt).
+    LdapUrl url;
+    url.setUrl(m_url);
+
+    LdapConnection conn;
+    conn.setUrl(url);
+    int ret;
+    if ((ret = conn.connect())) {
+        qDebug() << "Could not connect to LDAP server. Error was:" << conn.connectionError();
+    }
+    QCOMPARE(ret, 0);
+
+    LdapOperation op(conn);
+    // Now attempt to bind
+    if ((ret = op.bind_s())) {
+        qDebug() << "Could not bind to server. Error was:" << conn.ldapErrorString();
+    }
+    QEXPECT_FAIL("", "Will fail since no server is available for testing", Abort);
+    QCOMPARE(ret, 0);
+}
+
+void KLdapTest::testLdapSearch()
+{
+    // Lets try a search using the specified url
+    LdapUrl url;
+    url.setUrl(m_url);
+    url.parseQuery();
+    connect(m_search, SIGNAL(result(KLDAP::LdapSearch*)),
+            this, SLOT(searchResult(KLDAP::LdapSearch*)));
+    connect(m_search, SIGNAL(data(KLDAP::LdapSearch*,KLDAP::LdapObject)),
+            this, SLOT(searchData(KLDAP::LdapSearch*,KLDAP::LdapObject)));
+    bool success = m_search->search(url);
+    while (QCoreApplication::hasPendingEvents()) {
+        qApp->processEvents();
+    }
+
+    QEXPECT_FAIL("", "Will fail since no server is available for testing", Abort);
+    QCOMPARE(success, true);
+
+    qDebug() << "Search found" << m_objects.size() << "matching entries";
+}
+
+void KLdapTest::searchResult(KLDAP::LdapSearch *search)
+{
+    qDebug();
+    int err = search->error();
+    if (err) {
+        qDebug() << "Search returned the following error:" << search->errorString();
+    }
+    QCOMPARE(err, 0);
+}
+
+void KLdapTest::searchData(KLDAP::LdapSearch *search, const KLDAP::LdapObject &obj)
+{
+    Q_UNUSED(search);
+    //qDebug();
+    //qDebug() << "Object:";
+    //qDebug() << obj.toString();
+    m_objects.append(obj);
+}
+
+void KLdapTest::testLdapDN()
+{
+    QString strDN(QStringLiteral("uid=Test\\+Person+ou=accounts\\,outgoing,dc=kde,dc=org"));
+    LdapDN dn(strDN);
+    QCOMPARE(dn.isValid(), true);
+    QCOMPARE(dn.rdnString(), QStringLiteral("uid=Test\\+Person+ou=accounts\\,outgoing"));
+}
+
+void KLdapTest::testLdapModel()
+{
+    // Use the user-supplied testing url
+    LdapUrl url;
+    url.setUrl(m_url);
+
+    // Create a connection to use and bind with it
+    LdapConnection conn;
+    conn.setUrl(url);
+    int ret;
+    if ((ret = conn.connect())) {
+        qDebug() << "Could not connect to LDAP server. Error was:" << conn.connectionError();
+    }
+    QCOMPARE(ret, 0);
+
+    LdapOperation op(conn);
+    if ((ret = op.bind_s())) {
+        qDebug() << "Could not bind to server. Error was:" << conn.ldapErrorString();
+    }
+    QEXPECT_FAIL("", "Will fail since no server is available for testing", Abort);
+    QCOMPARE(ret, 0);
+
+    // Let's use this connection with the model
+    m_model->setConnection(conn);
+
+    while (QCoreApplication::hasPendingEvents()) {
+        qApp->processEvents();
+    }
+
+    QModelIndex rootIndex = QModelIndex();
+    QVariant data = m_model->data(rootIndex, Qt::DisplayRole);
+    qDebug() << "Root Item Distinguished Name =" << data.toString();
+
+    QVERIFY(m_model->hasChildren(rootIndex) == true);
+    QVERIFY(m_model->canFetchMore(rootIndex) == false);
+}
+
+/*
+  void KLdapTest::testKLdap()
+  {
+  LdapUrl url;
+  bool critical;
+
+  url.setUrl("ldap://cn=manager,dc=kde,dc=org:password@localhost:3999"
+             "/dc=kde,dc=org?cn,mail?sub?(objectClass=*)?x-dir=base");
+  url.parseQuery();
+
+  QCOMPARE( url.user(), QString::fromLatin1("cn=manager,dc=kde,dc=org") );
+  QCOMPARE( url.password(), QString::fromLatin1("password") );
+  QCOMPARE( url.dn(), QString::fromLatin1("dc=kde,dc=org") );
+  QCOMPARE( url.scope(), LdapUrl::Sub );
+  QCOMPARE( url.attributes().at(0), QString::fromLatin1("cn") );
+  QCOMPARE( url.attributes().at(1), QString::fromLatin1("mail") );
+  QCOMPARE( url.filter(), QString::fromLatin1("(objectClass=*)") );
+  QCOMPARE( url.extension(QString::fromLatin1("x-dir"), critical), QString::fromLatin1("base") );
+
+  url.setDn("ou=People,dc=kde,dc=org");
+  QCOMPARE( url.dn(), QString::fromLatin1("ou=People,dc=kde,dc=org") );
+  url.setDn("/ou=People,dc=kde,dc=org");
+  QCOMPARE( url.dn(), QString::fromLatin1("ou=People,dc=kde,dc=org") );
+
+  LdapServer server;
+//  url.setUrl("ldaps://cn=manager,dc=kde,dc=org:passwor@localhost:3999/"
+               "dc=kde,dc=org????x-timelimt=5,x-sizelimit=6,x=pagesize=7,binddn=cn=apple,ou=berry");
+url.setUrl("ldaps://cn=manager,dc=kde,dc=org:password@localhost:3999/"
+           "dc=kde,dc=org??base??x-timelimit=5");
+url.parseQuery();
+server.setUrl( url );
+QCOMPARE( url.query(), QString::fromLatin1("??base??x-timelimit=5") );
+QCOMPARE( url.url(), server.url().url() );
+
+LdapControl c1;
+c1.setControl( QString::fromLatin1("1.2.3.4.5.6"), QByteArray("abcdefg"), true );
+//test copy constructor
+LdapControl c2(c1);
+QCOMPARE( c2.oid(), QString::fromLatin1("1.2.3.4.5.6") );
+QCOMPARE( c2.value(), QByteArray("abcdefg") );
+QCOMPARE( c2.critical(), true );
+//test assignment operator
+LdapControl c3;
+c3 = c1;
+QCOMPARE( c3.oid(), QString::fromLatin1("1.2.3.4.5.6") );
+QCOMPARE( c3.value(), QByteArray("abcdefg") );
+QCOMPARE( c3.critical(), true );
+*/
+//test Ber functions
+/*
+  QByteArray left1("bertest"), right1;
+  int left2 = 0, right2;
+  int left3 = 1, right3;
+  int left4 = 2, right4;
+  int left5 = 3, right5;
+  int left6 = 1, right6;
+  QList<QByteArray> left7, right7;
+  left7.append( "abcdefghij" );
+  left7.append( "123456789" );
+  left7.append( "1234\0\0\056789" );
+
+  Ber ber;
+  ber.printf("{seeiib}", &left1, left2, left3, left4, left5, left6 );
+
+//  ber.printf("{ioOi{i}}", left3, &left1, &left2, left4, left4 );
+Ber ber2 = ber;
+
+unsigned int a;
+int b;
+a = ber2.skipTag( b );
+qDebug() << "next tag:" << a << "size:" << b;
+a = ber2.skipTag( b );
+qDebug() << "next tag:" << a << "size:" << b;
+a = ber2.skipTag( b );
+qDebug() << "next tag:" << a << "size:" << b;
+a = ber2.skipTag( b );
+qDebug() << "next tag:" << a << "size:" << b;
+a = ber2.skipTag( b );
+qDebug() << "next tag:" << a << "size:" << b;
+a = ber2.skipTag( b );
+qDebug() << "next tag:" << a << "size:" << b;
+a = ber2.skipTag( b );
+qDebug() << "next tag:" << a << "size:" << b;
+a = ber2.skipTag( b );
+qDebug() << "next tag:" << a << "size:" << b;
+
+BerElement *_ber, *_ber2;
+_ber = ber_alloc_t( LBER_USE_DER );
+
+ber_len_t bl;
+ber_printf( _ber, "{i}", 5 );
+qDebug() << "native";
+_ber2 = ber_dup( _ber );
+a = ber_skip_tag( _ber2, &bl );
+qDebug() << "next tag:" << a << "size:" << bl;
+//  ber_dump( _ber, 0 );
+
+//  ber2.scanf("{v}", &right5 );
+
+//  ber2.scanf("{inoOi{v}}", &right3, &right1, &right2, &right4, &right5 );
+
+//  QCOMPARE( left1, right1 );
+//  QCOMPARE( left2, right2 );
+//  QCOMPARE( left3, right3 );
+//  QCOMPARE( left4, right4 );
+//  QCOMPARE( left5, right5 );
+*/
+/*
+  url.setUrl("ldap://localhost/dc=gyurco,dc=localdomain");
+  url.parseQuery();
+  server.setUrl( url );
+  LdapConnection conn( server );
+  int result = conn.connect();
+  qDebug() << "connect result" << result << conn.errorString();
+
+  LdapOperation op( conn );
+  int msgid = op.search( "ou=People,dc=gyurco,dc=localdomain", LdapUrl::One, "", QStringList() );
+  qDebug() << "search msgid" << msgid;
+  result = op.result( msgid );
+  qDebug() << "error code" << conn.ldapErrorCode() << "str:" << conn.ldapErrorString();
+  while ( result == LdapOperation::RES_SEARCH_ENTRY ) {
+  qDebug() << op.object().toString();
+  result = op.result( msgid );
+  }
+  qDebug() << "error code" << conn.ldapErrorCode() << "str:" << conn.ldapErrorString();
+
+  msgid = op.del( "ou=People,dc=gyurco,dc=localdomain" );
+  qDebug() << "search msgid" << msgid;
+  result = op.result( msgid );
+  qDebug() << "error code" << conn.ldapErrorCode() << "str:" << conn.ldapErrorString();
+
+  msgid = op.compare( "ou=People,dc=gyurco,dc=localdomain", "objectClass", QByteArray("top") );
+  qDebug() << "search msgid" << msgid;
+  result = op.result( msgid );
+  qDebug() << "error code" << conn.ldapErrorCode() << "str:" << conn.ldapErrorString();
+
+  msgid = op.compare( "ou=People,dc=gyurco,dc=localdomain", "objectClass",
+                      QByteArray("inetOrgPerson") );
+  qDebug() << "search msgid" << msgid;
+  result = op.result( msgid );
+  qDebug() << "error code" << conn.ldapErrorCode() << "str:" << conn.ldapErrorString();
+
+  msgid = op.exop( "1.2.3.4.5.6.7.8", QByteArray("inetOrgPerson") );
+  qDebug() << "search msgid" << msgid;
+  result = op.result( msgid );
+  qDebug() << "error code" << conn.ldapErrorCode() << "str:" << conn.ldapErrorString();
+*/
+/*
+  }
+*/
diff --git a/autotests/testkldap.h b/autotests/testkldap.h
new file mode 100644 (file)
index 0000000..944e20c
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+  Copyright (c) 2006 Volker Krause <vkrause@kde.org>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef TESTKLDAP_H
+#define TESTKLDAP_H
+
+#include <QtCore/QObject>
+#include <ldapmodel.h>
+#include <ldapobject.h>
+#include <ldapsearch.h>
+
+using namespace KLDAP;
+
+class KLdapTest : public QObject
+{
+    Q_OBJECT
+private Q_SLOTS:
+    //void testKLdap();
+
+    void initTestCase();
+    void cleanupTestCase();
+
+    void testLdapUrl();
+    void testBer();
+    void testLdapConnection();
+    void testLdapSearch();
+    void testLdapDN();
+    void testLdapModel();
+
+public Q_SLOTS:
+    void searchResult(KLDAP::LdapSearch *search);
+    void searchData(KLDAP::LdapSearch *search, const KLDAP::LdapObject &obj);
+
+private:
+    QString m_url;
+    LdapSearch *m_search;
+    LdapObjects m_objects;
+    LdapModel *m_model;
+};
+
+#endif
diff --git a/autotests/testurl.txt.tmpl b/autotests/testurl.txt.tmpl
new file mode 100644 (file)
index 0000000..2cdc6a8
--- /dev/null
@@ -0,0 +1 @@
+ldap://cn=admin,dc=kde,dc=org:password@ldap.kde.org:389/ou=people,dc=kde,dc=org?cn,mail,loginShell?sub?(uid=*)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
new file mode 100644 (file)
index 0000000..55201c6
--- /dev/null
@@ -0,0 +1,5 @@
+install(FILES
+    FindLdap.cmake
+    FindSasl2.cmake
+    DESTINATION ${CMAKECONFIG_INSTALL_DIR}
+)
diff --git a/cmake/COPYING-CMAKE-SCRIPTS b/cmake/COPYING-CMAKE-SCRIPTS
new file mode 100644 (file)
index 0000000..4b41776
--- /dev/null
@@ -0,0 +1,22 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products 
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/cmake/FindLdap.cmake b/cmake/FindLdap.cmake
new file mode 100644 (file)
index 0000000..7f8ef04
--- /dev/null
@@ -0,0 +1,114 @@
+#.rst:
+# FindLdap
+# --------
+#
+# Try to find the LDAP client libraries.
+#
+# This will define the following variables:
+#
+# ``Ldap_FOUND``
+#     True if libldap is available.
+#
+# ``Ldap_VERSION``
+#     The version of libldap
+#
+# ``Ldap_INCLUDE_DIRS``
+#     This should be passed to target_include_directories() if
+#     the target is not used for linking
+#
+# ``Ldap_LIBRARIES``
+#     The LDAP libraries (libldap + liblber if available)
+#     This can be passed to target_link_libraries() instead of
+#     the ``Ldap::Ldap`` target
+#
+# If ``Ldap_FOUND`` is TRUE, the following imported target
+# will be available:
+#
+# ``Ldap::Ldap``
+#     The LDAP library
+#
+# Since pre-5.0.0.
+#
+# Imported target since 5.1.41
+#
+#=============================================================================
+# Copyright 2006 Szombathelyi György <gyurco@freemail.hu>
+# Copyright 2007-2016 Laurent Montel <montel@kde.org>
+#
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+#    derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#=============================================================================
+
+find_path(Ldap_INCLUDE_DIRS NAMES ldap.h)
+
+if(APPLE)
+   find_library(Ldap_LIBRARIES NAMES LDAP
+      PATHS
+      /System/Library/Frameworks
+      /Library/Frameworks
+   )
+else()
+   find_library(Ldap_LIBRARIES NAMES ldap)
+   find_library(Lber_LIBRARIES NAMES lber)
+endif()
+
+if(Ldap_LIBRARIES AND Lber_LIBRARIES)
+  set(Ldap_LIBRARIES ${Ldap_LIBRARIES} ${Lber_LIBRARIES})
+endif()
+
+if(EXISTS ${Ldap_INCLUDE_DIRS}/ldap_features.h)
+  file(READ ${Ldap_INCLUDE_DIRS}/ldap_features.h LDAP_FEATURES_H_CONTENT)
+  string(REGEX MATCH "#define LDAP_VENDOR_VERSION_MAJOR[ ]+[0-9]+" _LDAP_VERSION_MAJOR_MATCH ${LDAP_FEATURES_H_CONTENT})
+  string(REGEX MATCH "#define LDAP_VENDOR_VERSION_MINOR[ ]+[0-9]+" _LDAP_VERSION_MINOR_MATCH ${LDAP_FEATURES_H_CONTENT})
+  string(REGEX MATCH "#define LDAP_VENDOR_VERSION_PATCH[ ]+[0-9]+" _LDAP_VERSION_PATCH_MATCH ${LDAP_FEATURES_H_CONTENT})
+
+  string(REGEX REPLACE ".*_MAJOR[ ]+(.*)" "\\1" LDAP_VERSION_MAJOR ${_LDAP_VERSION_MAJOR_MATCH})
+  string(REGEX REPLACE ".*_MINOR[ ]+(.*)" "\\1" LDAP_VERSION_MINOR ${_LDAP_VERSION_MINOR_MATCH})
+  string(REGEX REPLACE ".*_PATCH[ ]+(.*)" "\\1" LDAP_VERSION_PATCH ${_LDAP_VERSION_PATCH_MATCH})
+
+  set(Ldap_VERSION "${LDAP_VERSION_MAJOR}.${LDAP_VERSION_MINOR}.${LDAP_VERSION_PATCH}")
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(Ldap
+    FOUND_VAR Ldap_FOUND
+    REQUIRED_VARS Ldap_LIBRARIES Ldap_INCLUDE_DIRS
+    VERSION_VAR Ldap_VERSION
+)
+
+if(Ldap_FOUND AND NOT TARGET Ldap::Ldap)
+  add_library(Ldap::Ldap UNKNOWN IMPORTED)
+  set_target_properties(Ldap::Ldap PROPERTIES
+  IMPORTED_LOCATION "${Ldap_LIBRARIES}"
+  INTERFACE_INCLUDE_DIRECTORIES "${Ldap_INCLUDE_DIRS}")
+endif()
+
+mark_as_advanced(Ldap_INCLUDE_DIRS Ldap_LIBRARIES Lber_LIBRARIES Ldap_VERSION)
+
+include(FeatureSummary)
+set_package_properties(Ldap PROPERTIES
+  URL "http://www.openldap.org/"
+  DESCRIPTION "LDAP (Lightweight Directory Access Protocol) libraries."
+)
diff --git a/cmake/FindSasl2.cmake b/cmake/FindSasl2.cmake
new file mode 100644 (file)
index 0000000..47b13a5
--- /dev/null
@@ -0,0 +1,113 @@
+#.rst:
+# FindSasl2
+# ---------
+#
+# Try to find the SASL2 library.
+#
+# This will define the following variables:
+#
+# ``Sasl2_FOUND``
+#     System has SASL2.
+#
+# ``Sasl2_VERSION``
+#     The version of SASL2.
+#
+# ``Sasl2_INCLUDE_DIRS``
+#     This should be passed to target_include_directories() if
+#     the target is not used for linking.
+#
+# ``Sasl2_LIBRARIES``
+#     The SASL2 library.
+#     This can be passed to target_link_libraries() instead of
+#     the ``Sasl2::Sasl2`` target
+#
+# If ``Sasl2_FOUND`` is TRUE, the following imported target
+# will be available:
+#
+# ``Sasl2::Sasl2``
+#     The SASL2 library
+#
+# Since pre-5.0.0.
+#
+# Imported target since 5.1.41
+#
+#=============================================================================
+# Copyright 2006, 2007 Laurent Montel <montel@kde.org>
+#
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+#    derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#=============================================================================
+
+# NOTE: libsasl2.pc doesn't export the include dir.
+find_package(PkgConfig QUIET)
+pkg_check_modules(PC_Sasl2 libsasl2)
+
+find_path(Sasl2_INCLUDE_DIRS NAMES sasl/sasl.h)
+
+# libsasl2 add for windows, because the windows package of cyrus-sasl2
+# contains a libsasl2 also for msvc which is not standard conform
+find_library(Sasl2_LIBRARIES
+  NAMES sasl2 libsasl2
+  HINTS ${PC_Sasl2_LIBRARY_DIRS}
+)
+
+set(Sasl2_VERSION ${PC_Sasl2_VERSION})
+
+if(NOT Sasl2_VERSION)
+  if(EXISTS ${Sasl2_INCLUDE_DIRS}/sasl/sasl.h)
+    file(READ ${Sasl2_INCLUDE_DIRS}/sasl/sasl.h SASL2_H_CONTENT)
+    string(REGEX MATCH "#define SASL_VERSION_MAJOR[ ]+[0-9]+" SASL2_VERSION_MAJOR_MATCH ${SASL2_H_CONTENT})
+    string(REGEX MATCH "#define SASL_VERSION_MINOR[ ]+[0-9]+" SASL2_VERSION_MINOR_MATCH ${SASL2_H_CONTENT})
+    string(REGEX MATCH "#define SASL_VERSION_STEP[ ]+[0-9]+" SASL2_VERSION_STEP_MATCH ${SASL2_H_CONTENT})
+
+    string(REGEX REPLACE ".*_MAJOR[ ]+(.*)" "\\1" SASL2_VERSION_MAJOR ${SASL2_VERSION_MAJOR_MATCH})
+    string(REGEX REPLACE ".*_MINOR[ ]+(.*)" "\\1" SASL2_VERSION_MINOR ${SASL2_VERSION_MINOR_MATCH})
+    string(REGEX REPLACE ".*_STEP[ ]+(.*)" "\\1"  SASL2_VERSION_STEP  ${SASL2_VERSION_STEP_MATCH})
+
+    set(Sasl2_VERSION "${SASL2_VERSION_MAJOR}.${SASL2_VERSION_MINOR}.${SASL2_VERSION_STEP}")
+  endif()
+endif()
+
+include(FindPackageHandleStandardArgs)
+
+find_package_handle_standard_args(Sasl2
+    FOUND_VAR Sasl2_FOUND
+    REQUIRED_VARS Sasl2_LIBRARIES Sasl2_INCLUDE_DIRS
+    VERSION_VAR Sasl2_VERSION
+)
+if(Sasl2_FOUND AND NOT TARGET Sasl2::Sasl2)
+  add_library(Sasl2::Sasl2 UNKNOWN IMPORTED)
+  set_target_properties(Sasl2::Sasl2 PROPERTIES
+  IMPORTED_LOCATION "${Sasl2_LIBRARIES}"
+  INTERFACE_INCLUDE_DIRECTORIES "${Sasl2_INCLUDE_DIRS}")
+endif()
+
+mark_as_advanced(Sasl2_LIBRARIES Sasl2_INCLUDE_DIRS Sasl2_VERSION)
+
+include(FeatureSummary)
+set_package_properties(Sasl2 PROPERTIES
+  URL "http://www.cyrussasl.org/"
+  DESCRIPTION "The Cyrus-sasl library."
+)
+
diff --git a/metainfo.yaml b/metainfo.yaml
new file mode 100644 (file)
index 0000000..d5022dd
--- /dev/null
@@ -0,0 +1,14 @@
+maintainer: mlaurent
+description: LDap support library
+tier: 3
+type: functional
+platforms:
+    - name: All
+portingAid: false
+deprecated: false
+release: false
+libraries:
+ - qmake: Ldap 
+   cmake: "KF5::Ldap"
+cmakename: KF5Ldap
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ad81162
--- /dev/null
@@ -0,0 +1,128 @@
+include(CheckFunctionExists)
+include(CheckIncludeFiles)
+include(CheckSymbolExists)
+
+# Reactivate it
+remove_definitions(-DQT_NO_CAST_FROM_BYTEARRAY)
+
+check_include_files(sys/time.h HAVE_SYS_TIME_H)
+
+set(kldap_EXTRA_LIBS)
+
+if(Ldap_FOUND)
+  set(kldap_EXTRA_LIBS ${Ldap_LIBRARIES})
+  if(WIN32)
+    set(kldap_EXTRA_LIBS ${kldap_EXTRA_LIBS} ws2_32)
+  endif()
+  set(HAVE_LDAP_H)
+  set(CMAKE_REQUIRED_INCLUDES lber.h ldap.h)
+  set(CMAKE_REQUIRED_LIBRARIES ${Ldap_LIBRARIES})
+  check_function_exists(ldap_start_tls_s HAVE_LDAP_START_TLS_S)
+  check_function_exists(ldap_initialize HAVE_LDAP_INITIALIZE)
+  check_function_exists(ber_memfree HAVE_BER_MEMFREE)
+  check_function_exists(ldap_unbind_ext HAVE_LDAP_UNBIND_EXT)
+  check_function_exists(ldap_extended_operation HAVE_LDAP_EXTENDED_OPERATION)
+  check_function_exists(ldap_extended_operation_s HAVE_LDAP_EXTENDED_OPERATION_S)
+  check_symbol_exists(ldap_extended_operation ldap.h HAVE_LDAP_EXTENDED_OPERATION_PROTOTYPE)
+  check_symbol_exists(ldap_extended_operation_s ldap.h HAVE_LDAP_EXTENDED_OPERATION_S_PROTOTYPE)
+endif()
+
+if(Sasl2_FOUND)
+  set(kldap_EXTRA_LIBS ${kldap_EXTRA_LIBS} ${Sasl2_LIBRARIES})
+endif()
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/kldap_config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/kldap_config.h)
+
+########### next target ###############
+
+set(kldap_LIB_SRCS
+  ber.cpp
+  ldif.cpp
+  ldapurl.cpp
+  ldapserver.cpp
+  ldapobject.cpp
+  ldapconnection.cpp
+  ldapoperation.cpp
+  ldapcontrol.cpp
+  ldapsearch.cpp
+  ldapconfigwidget.cpp
+  ldapdn.cpp
+  ldapmodelnode_p.cpp
+  ldapmodel.cpp
+  ldapmodel_p.cpp
+  ldapstructureproxymodel.cpp
+  ldapattributeproxymodel.cpp
+)
+ecm_qt_declare_logging_category(kldap_LIB_SRCS HEADER ldap_debug.h IDENTIFIER LDAP_LOG CATEGORY_NAME log_ldap)
+
+add_library(KF5Ldap ${kldap_LIB_SRCS})
+
+generate_export_header(KF5Ldap BASE_NAME kldap)
+
+add_library(KF5::Ldap ALIAS KF5Ldap)
+
+target_link_libraries(KF5Ldap
+PRIVATE
+  KF5::Completion
+  Qt5::Widgets
+  KF5::I18n
+  KF5::WidgetsAddons
+  ${kldap_EXTRA_LIBS}
+)
+
+target_include_directories(KF5Ldap INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF5}/KLDAP;${Ldap_INCLUDE_DIRS}>")
+target_include_directories(KF5Ldap PUBLIC "$<BUILD_INTERFACE:${KLdap_SOURCE_DIR}/src;${KLdap_BINARY_DIR}/src;${Ldap_INCLUDE_DIRS}>")
+
+if(Sasl2_FOUND)
+    target_include_directories(KF5Ldap INTERFACE "$<INSTALL_INTERFACE:${Sasl2_INCLUDE_DIRS}>")
+    target_include_directories(KF5Ldap PUBLIC "$<BUILD_INTERFACE:${Sasl2_INCLUDE_DIRS}>")
+endif()
+
+set_target_properties(KF5Ldap PROPERTIES
+    VERSION ${KLDAP_VERSION_STRING}
+    SOVERSION ${KLDAP_SOVERSION}
+    EXPORT_NAME Ldap
+)
+
+
+install(TARGETS KF5Ldap EXPORT KF5LdapTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS})
+
+########### install files ###############
+
+ecm_generate_headers(KLdap_CamelCase_HEADERS
+  HEADER_NAMES
+  Ber
+  LdapAttributeProxyModel
+  LdapConfigWidget
+  LdapConnection
+  LdapControl
+  LdapDN
+  LdapModel
+  LdapObject
+  LdapOperation
+  LdapSearch
+  LdapServer
+  LdapDefs
+  LdapStructureProxyModel
+  LdapUrl
+  Ldif
+  PREFIX KLDAP
+  REQUIRED_HEADERS KLdap_HEADERS
+)
+
+install(FILES
+    ${CMAKE_CURRENT_BINARY_DIR}/kldap_export.h
+    ${KLdap_HEADERS}
+    DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KLDAP/kldap
+    COMPONENT Devel
+)
+
+install(FILES
+    ${KLdap_CamelCase_HEADERS}
+    DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KLDAP/KLDAP/
+    COMPONENT Devel
+)
+
+ecm_generate_pri_file(BASE_NAME Ldap LIB_NAME KF5Ldap FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KLDAP/)
+install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
+
diff --git a/src/Messages.sh b/src/Messages.sh
new file mode 100644 (file)
index 0000000..18480f6
--- /dev/null
@@ -0,0 +1,3 @@
+#! /bin/sh
+$XGETTEXT *.cpp -o $podir/libkldap5.pot
+
diff --git a/src/ber.cpp b/src/ber.cpp
new file mode 100644 (file)
index 0000000..2af6b96
--- /dev/null
@@ -0,0 +1,451 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ber.h"
+#include "kldap_config.h"
+
+#include "ldap_debug.h"
+
+#include <QtCore/QList>
+#include <qvarlengtharray.h>
+
+#include <cstdarg>
+
+#ifdef LDAP_FOUND
+
+#ifdef Q_OS_SOLARIS //krazy:exclude=cpp
+#define BC31 1
+#endif
+
+#ifndef HAVE_WINLDAP_H
+#include <lber.h>
+#include <ldap.h>
+#else
+#include <w32-ldap-help.h>
+#endif
+
+#ifndef LBER_USE_DER
+#define LBER_USE_DER 1
+#endif
+
+#ifndef HAVE_BER_MEMFREE
+# ifndef HAVE_WINLDAP_H
+#  define ber_memfree(x) ldap_memfree(x)
+# else
+#  define ber_memfree(x) win_ldap_memfree(x)
+# endif
+#endif
+
+#endif
+
+using namespace KLDAP;
+
+class Q_DECL_HIDDEN Ber::BerPrivate
+{
+public:
+#ifdef LDAP_FOUND
+    BerElement *mBer;
+#endif
+};
+
+#ifdef LDAP_FOUND
+Ber::Ber()
+    : d(new BerPrivate)
+{
+    d->mBer = ber_alloc_t(LBER_USE_DER);
+    Q_ASSERT(d->mBer);
+}
+
+Ber::Ber(const QByteArray &value)
+    : d(new BerPrivate)
+{
+    struct berval bv;
+    bv.bv_val = (char *) value.data();
+    bv.bv_len = value.size();
+    d->mBer = ber_init(&bv);
+    Q_ASSERT(d->mBer);
+}
+
+Ber::~Ber()
+{
+    ber_free(d->mBer, 1);
+    delete d;
+}
+
+Ber::Ber(const Ber &that)
+    : d(new BerPrivate)
+{
+    struct berval *bv;
+    if (ber_flatten(that.d->mBer, &bv) == 0) {
+        d->mBer = ber_init(bv);
+        ber_bvfree(bv);
+    }
+}
+
+Ber &Ber::operator=(const Ber &that)
+{
+    if (this == &that) {
+        return *this;
+    }
+
+    struct berval *bv;
+    if (ber_flatten(that.d->mBer, &bv) == 0) {
+        d->mBer = ber_init(bv);
+        ber_bvfree(bv);
+    }
+    return *this;
+}
+
+QByteArray Ber::flatten() const
+{
+    QByteArray ret;
+    struct berval *bv;
+    if (ber_flatten(d->mBer, &bv) == 0) {
+        ret = QByteArray(bv->bv_val, bv->bv_len);
+        ber_bvfree(bv);
+    }
+    return ret;
+}
+
+int Ber::printf(QString format, ...)
+{
+    char fmt[2];
+    va_list args;
+    va_start(args, format);
+    fmt[1] = '\0';
+
+    int i = 0, ret = 0;
+    while (i < format.length()) {
+        fmt[0] = format[i].toLatin1();
+        i++;
+        switch (fmt[0]) {
+        case 'b':
+        case 'e':
+        case 'i': {
+            ber_int_t v = va_arg(args, int);
+            ret = ber_printf(d->mBer, fmt, v);
+            break;
+        }
+        case 'B': {
+            //FIXME: QBitArray vould be logical, but how to access the bits?
+            QByteArray *B = va_arg(args, QByteArray *);
+            int Bc = va_arg(args, int);
+            ret = ber_printf(d->mBer, fmt, B->data(), Bc);
+            break;
+        }
+        case 'o': {
+            QByteArray *o = va_arg(args, QByteArray *);
+            ret = ber_printf(d->mBer, fmt, o->data(), o->size());
+            break;
+        }
+        case 'O': {
+            QByteArray *O = va_arg(args, QByteArray *);
+            struct berval bv;
+            bv.bv_val = (char *) O->data();
+            bv.bv_len = O->size();
+            ret = ber_printf(d->mBer, fmt, &bv);
+            break;
+        }
+        break;
+        case 's': {
+            QByteArray *s = va_arg(args, QByteArray *);
+            ret = ber_printf(d->mBer, fmt, s->data());
+            break;
+        }
+        break;
+        case 't': {
+            unsigned int t = va_arg(args, unsigned int);
+            ret = ber_printf(d->mBer, fmt, t);
+            break;
+        }
+        break;
+        case 'v': {
+            QList<QByteArray> *v = va_arg(args, QList<QByteArray> *);
+            QVarLengthArray<const char *> l(v->count() + 1);
+            int j;
+            for (j = 0; j < v->count(); j++) {
+                l[j] = v->at(j).data();
+            }
+            l[j] = Q_NULLPTR;
+            ret = ber_printf(d->mBer, fmt, l.data());
+            break;
+        }
+        case 'V': {
+            QList<QByteArray> *V = va_arg(args, QList<QByteArray> *);
+            QVarLengthArray<struct berval *> bv(V->count() + 1);
+            QVarLengthArray<struct berval> bvs(V->count());
+            int j;
+            for (j = 0; j < V->count(); j++) {
+                bvs[j].bv_val = (char *) V->at(j).data();
+                bvs[j].bv_len = V->at(j).size();
+                bv[j] = &bvs[j];
+            }
+            bv[V->count()] = Q_NULLPTR;
+            ret = ber_printf(d->mBer, fmt, bv.data());
+            break;
+        }
+        case 'n':
+        case '{':
+        case '}':
+        case '[':
+        case ']':
+            ret = ber_printf(d->mBer, fmt);
+            break;
+        default:
+            qCWarning(LDAP_LOG) << "Invalid BER format parameter: '" << fmt << "'";
+            ret = -1;
+        }
+        qCDebug(LDAP_LOG) << "ber_printf format:" << fmt << "ret:" << ret;
+        if (ret == -1) {
+            break;
+        }
+    }
+    va_end(args);
+    return ret;
+}
+
+int Ber::scanf(QString format, ...)
+{
+    char fmt[2];
+    va_list args;
+    va_start(args, format);
+    fmt[1] = '\0';
+
+    int i = 0, ret = 0;
+    while (i < format.length()) {
+        fmt[0] = format[i].toLatin1();
+        i++;
+        switch (fmt[0]) {
+        case 'l':
+        case 'b':
+        case 'e':
+        case 'i': {
+            int *v = va_arg(args, int *);
+            ret = ber_scanf(d->mBer, fmt, v);
+            break;
+        }
+        case 'B': {
+            //FIXME: QBitArray vould be logical, but how to access the bits?
+            QByteArray *B = va_arg(args, QByteArray *);
+            int *Bc = va_arg(args, int *);
+            char *c;
+            ret = ber_scanf(d->mBer, fmt, &c, Bc);
+            if (ret != -1) {
+                *B = QByteArray(c, (*Bc + 7) / 8);
+                ber_memfree(c);
+            }
+            break;
+        }
+        case 'o': {
+            QByteArray *o = va_arg(args, QByteArray *);
+            struct berval bv;
+            ret = ber_scanf(d->mBer, fmt, &bv);
+            if (ret != -1) {
+                *o = QByteArray(bv.bv_val, bv.bv_len);
+                ber_memfree(bv.bv_val);
+            }
+            break;
+        }
+        case 'O': {
+            QByteArray *O = va_arg(args, QByteArray *);
+            struct berval *bv;
+            ret = ber_scanf(d->mBer, fmt, &bv);
+            if (ret != -1) {
+                *O = QByteArray(bv->bv_val, bv->bv_len);
+                ber_bvfree(bv);
+            }
+            break;
+        }
+        break;
+        case 'm': { //the same as 'O', just *bv should not be freed.
+            QByteArray *m = va_arg(args, QByteArray *);
+            struct berval *bv;
+            ret = ber_scanf(d->mBer, fmt, &bv);
+            if (ret != -1) {
+                *m = QByteArray(bv->bv_val, bv->bv_len);
+            }
+            break;
+        }
+        case 'a': {
+            QByteArray *a = va_arg(args, QByteArray *);
+            char *c;
+            ret = ber_scanf(d->mBer, fmt, &c);
+            if (ret != -1) {
+                *a = QByteArray(c);
+                ber_memfree(c);
+            }
+            break;
+        }
+
+        case 's': {
+            QByteArray *s = va_arg(args, QByteArray *);
+            char buf[255];
+            ber_len_t l = sizeof(buf);
+            ret = ber_scanf(d->mBer, fmt, &buf, &l);
+            if (ret != -1) {
+                *s = QByteArray(buf, l);
+            }
+            break;
+        }
+        case 't':
+        case 'T': {
+            unsigned int *t = va_arg(args, unsigned int *);
+            ret = ber_scanf(d->mBer, fmt, t);
+            break;
+        }
+        break;
+        case 'v': {
+            QList<QByteArray> *v = va_arg(args, QList<QByteArray> *);
+            char **c, **c2;
+            ret = ber_scanf(d->mBer, fmt, &c);
+            if (ret != -1 && c) {
+                c2 = c;
+                while (*c) {
+                    v->append(QByteArray(*c));
+                    ber_memfree(*c);
+                    c++;
+                }
+                ber_memfree((char *) c2);
+            }
+            break;
+        }
+        case 'V': {
+            QList<QByteArray> *v = va_arg(args, QList<QByteArray> *);
+            struct berval **bv, **bv2;
+            ret = ber_scanf(d->mBer, fmt, &bv);
+            if (ret != -1 && bv) {
+                bv2 = bv;
+                while (*bv) {
+                    v->append(QByteArray((*bv)->bv_val, (*bv)->bv_len));
+                    bv++;
+                }
+                ber_bvecfree(bv2);
+            }
+            break;
+        }
+        case 'x':
+        case 'n':
+        case '{':
+        case '}':
+        case '[':
+        case ']':
+            ret = ber_scanf(d->mBer, fmt);
+            break;
+        default:
+            qCWarning(LDAP_LOG) << "Invalid BER format parameter: '" << fmt << "'";
+            ret = -1;
+        }
+
+        qCDebug(LDAP_LOG) << "ber_scanf format:" << fmt << "ret:" << ret;
+        if (ret == -1) {
+            break;
+        }
+
+    }
+    va_end(args);
+    return ret;
+}
+
+unsigned int Ber::peekTag(int &size)
+{
+    unsigned int ret;
+    ber_len_t len;
+    ret = ber_peek_tag(d->mBer, &len);
+    size = len;
+    return ret;
+}
+
+unsigned int Ber::skipTag(int &size)
+{
+    unsigned int ret;
+    ber_len_t len;
+    ret = ber_skip_tag(d->mBer, &len);
+    size = len;
+    return ret;
+}
+#else
+
+Ber::Ber()
+    : d(new BerPrivate)
+{
+    qCritical() << "LDAP support not compiled";
+}
+
+Ber::Ber(const QByteArray &)
+    : d(new BerPrivate)
+{
+    qCritical() << "LDAP support not compiled";
+}
+
+Ber::~Ber()
+{
+    delete d;
+}
+
+Ber::Ber(const Ber &)
+    : d(new BerPrivate)
+{
+    qCritical() << "LDAP support not compiled";
+}
+
+Ber &Ber::operator=(const Ber &that)
+{
+    if (this == &that) {
+        return *this;
+    }
+    qCritical() << "LDAP support not compiled";
+    return *this;
+}
+
+QByteArray Ber::flatten() const
+{
+    qCritical() << "LDAP support not compiled";
+    return QByteArray();
+}
+
+int Ber::printf(const QString &format, ...)
+{
+    Q_UNUSED(format);
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int Ber::scanf(const QString &format, ...)
+{
+    Q_UNUSED(format);
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+unsigned int Ber::peekTag(int &size)
+{
+    Q_UNUSED(size);
+    qCritical() << "LDAP support not compiled";
+    return 0;
+}
+
+unsigned int Ber::skipTag(int &size)
+{
+    Q_UNUSED(size);
+    qCritical() << "LDAP support not compiled";
+    return 0;
+}
+
+#endif
diff --git a/src/ber.h b/src/ber.h
new file mode 100644 (file)
index 0000000..62acb2a
--- /dev/null
+++ b/src/ber.h
@@ -0,0 +1,129 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_BER_H
+#define KLDAP_BER_H
+
+#include <QtCore/QByteArray>
+
+#include "kldap_export.h"
+
+namespace KLDAP
+{
+
+/**
+ * This class allows encoding and decoding Qt structures using Basic
+ * Encoding Rules.
+ */
+class KLDAP_EXPORT Ber
+{
+public:
+    /**
+     * Constructs a Ber object.
+     */
+    Ber();
+    /**
+     * Constructs a Ber object from the value.
+     */
+    explicit Ber(const QByteArray &value);
+    /**
+     * Destroys the Ber object.
+     */
+    virtual ~Ber();
+
+    Ber(const Ber &that);
+    Ber &operator=(const Ber &that);
+
+    /**
+     * Returns the Ber object as a flat QByteArray.
+     */
+    QByteArray flatten() const;
+
+    /**
+     * Appends the data with the specified format to the Ber object.
+     * This function works like printf, except that it's appending the
+     * parameters, not replacing them. The allowed format characters and
+     * the expected parameter types are:
+     * <ul>
+     *   <li>
+     *     b  Boolean.  An int parameter should be supplied.
+     *     A boolean element is output.
+     *   </li>
+     *   <li>
+     *     e  Enumeration.  An int parameter should be supplied.
+     *     An  enumeration  element is output.
+     *   </li>
+     *   <li>
+     *     i  Integer.   An int parameter should be supplied.
+     *     An integer element is output.
+     *   </li>
+     *   <li>
+     *     B  Bitstring.  A pointer to a QByteArray which contains the
+     *     bitstring is supplied, followed by the number of bits in the
+     *     bitstring.  A bitstring element is output.
+     *   </li>
+     *   <li>
+     *     n  Null.  No parameter is required. A null element is output.
+     *   </li>
+     *   <li>
+     *     O,o,s  Octet  string.  A QByteArray * is supplied.
+     *     An octet string element is output.
+     *         Due to versatility of Qt's QByteArray, these three format
+     *         strings are all accepts the same parameter, but using the 's'
+     *         format the string will be encoded only to the first zero
+     *         character (a null terminated string)!
+     *   </li>
+     *   <li>
+     *     t  Tag.  An int specifying the tag to give the next element
+     *     is provided. This works across calls.
+     *   </li>
+     *   <li>
+     *     v,V  Several octet strings. A QList<QByteArray>* is supplied.
+     *     Note that a construct like ’{v}’ is required to get an actual
+     *     SEQUENCE OF octet strings. Also note that the 'v' format recognizes
+     *     the QByteArray only to the first zero character, so it's not
+     *     appropriate for binary data, just only for null terminated strings!
+     *   </li>
+     *   <li>
+     *     {  Begin sequence. No parameter is required.
+     *   </li>
+     *   <li>
+     *     }  End sequence.  No parameter is required.
+     *   </li>
+     *   <li>
+     *     [  Begin set.  No parameter is required.
+     *   </li>
+     *   <li>
+     *     ]  End set.  No parameter is required.
+     *   </li>
+     * </ul>
+     */
+    int printf(QString format, ...); // Passing by-value since it's used by va_start
+    int scanf(QString format, ...);
+    unsigned int peekTag(int &size);
+    unsigned int skipTag(int &size);
+
+private:
+    class BerPrivate;
+    BerPrivate *const d;
+};
+
+}
+#endif
diff --git a/src/kldap_config.h.cmake b/src/kldap_config.h.cmake
new file mode 100644 (file)
index 0000000..8abd3fa
--- /dev/null
@@ -0,0 +1,13 @@
+#cmakedefine LDAP_FOUND
+#cmakedefine SASL2_FOUND
+#cmakedefine HAVE_WINLDAP_H
+#cmakedefine HAVE_LDAP_H
+#cmakedefine HAVE_SYS_TIME_H
+#cmakedefine HAVE_LDAP_START_TLS_S
+#cmakedefine HAVE_LDAP_INITIALIZE
+#cmakedefine HAVE_BER_MEMFREE
+#cmakedefine HAVE_LDAP_UNBIND_EXT
+#cmakedefine HAVE_LDAP_EXTENDED_OPERATION
+#cmakedefine HAVE_LDAP_EXTENDED_OPERATION_S
+#cmakedefine HAVE_LDAP_EXTENDED_OPERATION_PROTOTYPE
+#cmakedefine HAVE_LDAP_EXTENDED_OPERATION_S_PROTOTYPE
diff --git a/src/ldapattributeproxymodel.cpp b/src/ldapattributeproxymodel.cpp
new file mode 100644 (file)
index 0000000..4b27bcd
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapattributeproxymodel.h"
+#include "ldapmodel.h"
+#include "ldapmodelnode_p.h"
+
+#include "ldap_debug.h"
+#include <klocalizedstring.h>
+
+using namespace KLDAP;
+
+class Q_DECL_HIDDEN LdapAttributeProxyModel::LdapAttributeProxyModelPrivate
+{
+public:
+    LdapAttributeProxyModelPrivate();
+
+};
+
+LdapAttributeProxyModel::LdapAttributeProxyModelPrivate::LdapAttributeProxyModelPrivate()
+{
+
+}
+
+LdapAttributeProxyModel::LdapAttributeProxyModel(QObject *parent)
+    : QSortFilterProxyModel(parent),
+      m_d(new LdapAttributeProxyModelPrivate())
+{
+
+}
+
+LdapAttributeProxyModel::~LdapAttributeProxyModel()
+{
+    delete m_d;
+}
+
+QVariant LdapAttributeProxyModel::data(const QModelIndex &index,
+                                       int role) const
+{
+    // Included just in case we decide to do any special presentation of the data
+    // at some other point throughout the 4.x series.
+    return sourceModel()->data(mapToSource(index), role);
+}
+
+bool LdapAttributeProxyModel::setData(const QModelIndex &index,
+                                      const QVariant &value,
+                                      int role)
+{
+    Q_UNUSED(index);
+    Q_UNUSED(value);
+    Q_UNUSED(role);
+    return false;
+}
+
+bool LdapAttributeProxyModel::filterAcceptsRow(int sourceRow,
+        const QModelIndex &sourceParent) const
+{
+    QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent);
+    LdapModelNode::NodeType nodeType =
+        static_cast<LdapModelNode::NodeType>(
+            sourceModel()->data(idx, LdapModel::NodeTypeRole).toUInt());
+    return nodeType == LdapModelNode::Attr;
+}
+
+QVariant LdapAttributeProxyModel::headerData(int section,
+        Qt::Orientation orientation,
+        int role) const
+{
+    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+        if (section == 0) {
+            return QVariant(i18n("Attribute"));
+        } else if (section == 1) {
+            return QVariant(i18n("Value"));
+        }
+    }
+
+    return QVariant();
+}
+
+int LdapAttributeProxyModel::columnCount(const QModelIndex &/*parent*/) const
+{
+    return 2;
+}
+
+Qt::ItemFlags LdapAttributeProxyModel::flags(const QModelIndex &index) const
+{
+    // Included so as not to break BC in case we wish to use this later in 4.x
+    return sourceModel()->flags(mapToSource(index));
+}
+
+bool LdapAttributeProxyModel::hasChildren(const QModelIndex &parent) const
+{
+    // We need to handle this carefully bacause of the filtering out of attributes
+    // and the lazy population approach.
+    LdapModel *model = static_cast<LdapModel *>(sourceModel());
+    return model->hasChildrenOfType(mapToSource(parent), LdapModel::Attribute);
+}
+
+QModelIndex LdapAttributeProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+    return QSortFilterProxyModel::mapFromSource(sourceIndex);
+}
+
+QModelIndex LdapAttributeProxyModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+    return QSortFilterProxyModel::mapToSource(proxyIndex);
+}
+
+bool LdapAttributeProxyModel::insertRows(int row, int count,
+        const QModelIndex &parent)
+{
+    Q_UNUSED(row);
+    Q_UNUSED(count);
+    Q_UNUSED(parent);
+    return false;
+}
+
+bool LdapAttributeProxyModel::removeRows(int row, int count,
+        const QModelIndex &parent)
+{
+    Q_UNUSED(row);
+    Q_UNUSED(count);
+    Q_UNUSED(parent);
+    return false;
+}
+
+void LdapAttributeProxyModel::sort(int column, Qt::SortOrder order)
+{
+    Q_UNUSED(column);
+    Q_UNUSED(order);
+}
+
+Qt::DropActions LdapAttributeProxyModel::supportedDropActions() const
+{
+    return Qt::MoveAction;
+}
+
+QMimeData *LdapAttributeProxyModel::mimeData(const QModelIndexList &indexes) const
+{
+    Q_UNUSED(indexes);
+    return Q_NULLPTR;
+}
+
+bool LdapAttributeProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
+        int row, int column, const QModelIndex &parent)
+{
+    /** \todo Implement drag and drop for LdapModel */
+    Q_UNUSED(data);
+    Q_UNUSED(action);
+    Q_UNUSED(row);
+    Q_UNUSED(column);
+    Q_UNUSED(parent);
+    return false;
+}
+
diff --git a/src/ldapattributeproxymodel.h b/src/ldapattributeproxymodel.h
new file mode 100644 (file)
index 0000000..8a10d72
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPATTRIBUTEPROXYMODEL_H
+#define KLDAP_LDAPATTRIBUTEPROXYMODEL_H
+
+#include <QSortFilterProxyModel>
+
+#include "kldap_export.h"
+
+namespace KLDAP
+{
+
+class KLDAP_EXPORT LdapAttributeProxyModel : public QSortFilterProxyModel
+{
+    Q_OBJECT
+public:
+    explicit LdapAttributeProxyModel(QObject *parent = Q_NULLPTR);
+    ~LdapAttributeProxyModel();
+
+    QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::setData(). This is a placeholder for when
+     * LdapAttributeProxyModel beomes writeable and always returns false.
+     */
+    bool setData(const QModelIndex &index,
+                 const QVariant &value,
+                 int role = Qt::EditRole) Q_DECL_OVERRIDE;
+    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE;
+    QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE;
+    int columnCount(const QModelIndex &parent) const Q_DECL_OVERRIDE;
+    Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
+    bool hasChildren(const QModelIndex &parent) const Q_DECL_OVERRIDE;
+
+    QModelIndex mapFromSource(const QModelIndex &sourceIndex) const Q_DECL_OVERRIDE;
+    QModelIndex mapToSource(const QModelIndex &proxyIndex) const Q_DECL_OVERRIDE;
+
+    /**
+     * Reimplemented from QAbstractItemModel::insertRows(). This is a placeholder for when
+     * LdapAttributeProxyModel beomes writeable and always returns false.
+     */
+    virtual bool insertRows(int row, int count,
+                            const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::removeRows(). This is a placeholder for when
+     * LdapAttributeProxyModel beomes writeable and always returns false.
+     */
+    virtual bool removeRows(int row, int count,
+                            const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::removeRows(). The default implementation
+     * does nothing.
+     */
+    void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) Q_DECL_OVERRIDE;
+
+    //
+    // Drag and drop support
+    //
+    /**
+     * Reimplemented from QAbstractItemModel::supportedDropActions(). The default
+     * implementation returns Qt::MoveAction.
+     */
+    Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::mimedata(). This is a placeholder for when
+     * LdapAttributeProxyModel beomes writeable and always returns 0.
+     */
+    QMimeData *mimeData(const QModelIndexList &indexes) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::dropMimedata(). This is a placeholder for when
+     * LdapAttributeProxyModel beomes writeable and always returns false.
+     */
+    virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action,
+                              int row, int column, const QModelIndex &parent) Q_DECL_OVERRIDE;
+
+private:
+    class LdapAttributeProxyModelPrivate;
+    LdapAttributeProxyModelPrivate *const m_d;
+};
+
+}
+#endif
diff --git a/src/ldapconfigwidget.cpp b/src/ldapconfigwidget.cpp
new file mode 100644 (file)
index 0000000..02a1555
--- /dev/null
@@ -0,0 +1,894 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapconfigwidget.h"
+#include "ldapsearch.h"
+
+#include <qprogressdialog.h>
+#include <kcombobox.h>
+#include "ldap_debug.h"
+#include <klocalizedstring.h>
+#include <klineedit.h>
+#include <kmessagebox.h>
+
+#include <QtCore/QObject>
+#include <QCheckBox>
+#include <QGroupBox>
+#include <QLabel>
+#include <QPushButton>
+#include <QRadioButton>
+#include <QSpinBox>
+#include <QGridLayout>
+
+using namespace KLDAP;
+
+class Q_DECL_HIDDEN LdapConfigWidget::Private
+{
+public:
+    Private(LdapConfigWidget *parent)
+        : mParent(parent), mFeatures(W_ALL), mProg(Q_NULLPTR)
+    {
+        mainLayout = new QGridLayout(mParent);
+        mainLayout->setMargin(0);
+    }
+
+    void setLDAPPort();
+    void setLDAPSPort();
+    void setAnonymous(bool on);
+    void setSimple(bool on);
+    void setSASL(bool on);
+    void queryDNClicked();
+    void queryMechClicked();
+    void loadData(LdapSearch *search, const LdapObject &object);
+    void loadResult(LdapSearch *search);
+    void sendQuery();
+    void initWidget();
+
+    LdapConfigWidget *mParent;
+    WinFlags mFeatures;
+    QStringList mQResult;
+    QString mAttr;
+
+    QLineEdit *mUser;
+    QLineEdit *mPassword;
+    QLineEdit *mHost;
+    QSpinBox  *mPort, *mVersion, *mSizeLimit, *mTimeLimit, *mPageSize;
+    QLineEdit *mDn, *mBindDn, *mRealm;
+    QLineEdit *mFilter;
+    QRadioButton *mAnonymous, *mSimple, *mSASL;
+    QCheckBox *mSubTree;
+    QPushButton *mEditButton;
+    QPushButton *mQueryMech;
+    QRadioButton *mSecNo, *mSecTLS, *mSecSSL;
+    KComboBox *mMech;
+
+    bool mCancelled;
+    QProgressDialog *mProg;
+
+    QGridLayout *mainLayout;
+};
+
+void LdapConfigWidget::Private::initWidget()
+{
+    QLabel *label;
+
+    mUser = mPassword = mHost = mDn = mBindDn = mRealm = mFilter = Q_NULLPTR;
+    mPort = mVersion = mTimeLimit = mSizeLimit = Q_NULLPTR;
+    mAnonymous = mSimple = mSASL = mSecNo = mSecTLS = mSecSSL = Q_NULLPTR;
+    mEditButton =  mQueryMech = Q_NULLPTR;
+    mPageSize = Q_NULLPTR;
+    mMech = Q_NULLPTR;
+    int row = 0;
+    int col;
+
+    if (mFeatures & W_USER) {
+        label = new QLabel(i18n("User:"), mParent);
+        mUser = new QLineEdit(mParent);
+        mUser->setObjectName(QStringLiteral("kcfg_ldapuser"));
+
+        mainLayout->addWidget(label, row, 0);
+        mainLayout->addWidget(mUser, row, 1, 1, 3);
+        row++;
+    }
+
+    if (mFeatures & W_BINDDN) {
+        label = new QLabel(i18n("Bind DN:"), mParent);
+        mBindDn = new QLineEdit(mParent);
+        mBindDn->setObjectName(QStringLiteral("kcfg_ldapbinddn"));
+
+        mainLayout->addWidget(label, row, 0);
+        mainLayout->addWidget(mBindDn, row, 1, 1, 3);
+        row++;
+    }
+
+    if (mFeatures & W_REALM) {
+        label = new QLabel(i18n("Realm:"), mParent);
+        mRealm = new QLineEdit(mParent);
+        mRealm->setObjectName(QStringLiteral("kcfg_ldaprealm"));
+
+        mainLayout->addWidget(label, row, 0);
+        mainLayout->addWidget(mRealm, row, 1, 1, 3);
+        row++;
+    }
+
+    if (mFeatures & W_PASS) {
+        label = new QLabel(i18n("Password:"), mParent);
+        mPassword = new QLineEdit(mParent);
+        mPassword->setObjectName(QStringLiteral("kcfg_ldappassword"));
+        mPassword->setEchoMode(QLineEdit::Password);
+
+        mainLayout->addWidget(label, row, 0);
+        mainLayout->addWidget(mPassword, row, 1, 1, 3);
+        row++;
+    }
+
+    if (mFeatures & W_HOST) {
+        label = new QLabel(i18n("Host:"), mParent);
+        mHost = new QLineEdit(mParent);
+        mHost->setObjectName(QStringLiteral("kcfg_ldaphost"));
+        mParent->connect(mHost, &QLineEdit::textChanged, mParent, &LdapConfigWidget::hostNameChanged);
+        mainLayout->addWidget(label, row, 0);
+        mainLayout->addWidget(mHost, row, 1, 1, 3);
+        row++;
+    }
+
+    col = 0;
+    if (mFeatures & W_PORT) {
+        label = new QLabel(i18n("Port:"), mParent);
+        mPort = new QSpinBox(mParent);
+        mPort->setRange(0, 65535);
+        mPort->setObjectName(QStringLiteral("kcfg_ldapport"));
+        mPort->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred));
+        mPort->setValue(389);
+
+        mainLayout->addWidget(label, row, col);
+        mainLayout->addWidget(mPort, row, col + 1);
+        col += 2;
+    }
+
+    if (mFeatures & W_VER) {
+        label = new QLabel(i18n("LDAP version:"), mParent);
+        mVersion = new QSpinBox(mParent);
+        mVersion->setRange(2, 3);
+        mVersion->setObjectName(QStringLiteral("kcfg_ldapver"));
+        mVersion->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred));
+        mVersion->setValue(3);
+        mainLayout->addWidget(label, row, col);
+        mainLayout->addWidget(mVersion, row, col + 1);
+    }
+    if (mFeatures & (W_PORT | W_VER)) {
+        row++;
+    }
+
+    col = 0;
+    if (mFeatures & W_SIZELIMIT) {
+        label = new QLabel(i18n("Size limit:"), mParent);
+        mSizeLimit = new QSpinBox(mParent);
+        mSizeLimit->setRange(0, 9999999);
+        mSizeLimit->setObjectName(QStringLiteral("kcfg_ldapsizelimit"));
+        mSizeLimit->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred));
+        mSizeLimit->setValue(0);
+        mSizeLimit->setSpecialValueText(i18nc("default ldap size limit", "Default"));
+        mainLayout->addWidget(label, row, col);
+        mainLayout->addWidget(mSizeLimit, row, col + 1);
+        col += 2;
+    }
+
+    if (mFeatures & W_TIMELIMIT) {
+        label = new QLabel(i18n("Time limit:"), mParent);
+        mTimeLimit = new QSpinBox(mParent);
+        mTimeLimit->setRange(0, 9999999);
+        mTimeLimit->setObjectName(QStringLiteral("kcfg_ldaptimelimit"));
+        mTimeLimit->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred));
+        mTimeLimit->setValue(0);
+        mTimeLimit->setSuffix(i18n(" sec"));
+        mTimeLimit->setSpecialValueText(i18nc("default ldap time limit", "Default"));
+        mainLayout->addWidget(label, row, col);
+        mainLayout->addWidget(mTimeLimit, row, col + 1);
+    }
+    if (mFeatures & (W_SIZELIMIT | W_TIMELIMIT)) {
+        row++;
+    }
+
+    if (mFeatures & W_PAGESIZE) {
+        label = new QLabel(i18n("Page size:"), mParent);
+        mPageSize = new QSpinBox(mParent);
+        mPageSize->setRange(0, 9999999);
+        mPageSize->setObjectName(QStringLiteral("kcfg_ldappagesize"));
+        mPageSize->setSizePolicy(QSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred));
+        mPageSize->setValue(0);
+        mPageSize->setSpecialValueText(i18n("No paging"));
+        mainLayout->addWidget(label, row, 0);
+        mainLayout->addWidget(mPageSize, row++, 1);
+    }
+
+    if (mFeatures & W_DN) {
+        label = new QLabel(i18nc("Distinguished Name", "DN:"), mParent);
+        mDn = new QLineEdit(mParent);
+        mDn->setObjectName(QStringLiteral("kcfg_ldapdn"));
+
+        mainLayout->addWidget(label, row, 0);
+        mainLayout->addWidget(mDn, row, 1, 1, 1);
+        //without host query doesn't make sense
+        if (mHost) {
+            QPushButton *dnquery = new QPushButton(i18n("Query Server"), mParent);
+            connect(dnquery, SIGNAL(clicked()), mParent, SLOT(queryDNClicked()));
+            mainLayout->addWidget(dnquery, row, 2, 1, 1);
+        }
+        row++;
+    }
+
+    if (mFeatures & W_FILTER) {
+        label = new QLabel(i18n("Filter:"), mParent);
+        mFilter = new QLineEdit(mParent);
+        mFilter->setObjectName(QStringLiteral("kcfg_ldapfilter"));
+
+        mainLayout->addWidget(label, row, 0);
+        mainLayout->addWidget(mFilter, row, 1, 1, 3);
+        row++;
+    }
+
+    if (mFeatures & W_SECBOX) {
+        QGroupBox *btgroup = new QGroupBox(i18n("Security"), mParent);
+        QHBoxLayout *hbox = new QHBoxLayout;
+        btgroup->setLayout(hbox);
+        mSecNo = new QRadioButton(i18nc("@option:radio set no security", "No"), btgroup);
+        mSecNo->setObjectName(QStringLiteral("kcfg_ldapnosec"));
+        hbox->addWidget(mSecNo);
+        mSecTLS = new QRadioButton(i18nc("@option:radio use TLS security", "TLS"), btgroup);
+        mSecTLS->setObjectName(QStringLiteral("kcfg_ldaptls"));
+        hbox->addWidget(mSecTLS);
+        mSecSSL = new QRadioButton(i18nc("@option:radio use SSL security", "SSL"), btgroup);
+        mSecSSL->setObjectName(QStringLiteral("kcfg_ldapssl"));
+        hbox->addWidget(mSecSSL);
+        mainLayout->addWidget(btgroup, row, 0, 1, 4);
+
+        connect(mSecNo, SIGNAL(clicked()), mParent, SLOT(setLDAPPort()));
+        connect(mSecTLS, SIGNAL(clicked()), mParent, SLOT(setLDAPPort()));
+        connect(mSecSSL, SIGNAL(clicked()), mParent, SLOT(setLDAPSPort()));
+
+        mSecNo->setChecked(true);
+        row++;
+    }
+
+    if (mFeatures & W_AUTHBOX) {
+
+        QGroupBox *authbox =
+            new QGroupBox(i18n("Authentication"), mParent);
+        QVBoxLayout *vbox = new QVBoxLayout;
+        authbox->setLayout(vbox);
+        QHBoxLayout *hbox = new QHBoxLayout;
+        vbox->addLayout(hbox);
+
+        mAnonymous =
+            new QRadioButton(i18nc("@option:radio anonymous authentication", "Anonymous"), authbox);
+        mAnonymous->setObjectName(QStringLiteral("kcfg_ldapanon"));
+        hbox->addWidget(mAnonymous);
+        mSimple =
+            new QRadioButton(i18nc("@option:radio simple authentication", "Simple"), authbox);
+        mSimple->setObjectName(QStringLiteral("kcfg_ldapsimple"));
+        hbox->addWidget(mSimple);
+        mSASL =
+            new QRadioButton(i18nc("@option:radio SASL authentication", "SASL"), authbox);
+        mSASL->setObjectName(QStringLiteral("kcfg_ldapsasl"));
+        hbox->addWidget(mSASL);
+
+        hbox = new QHBoxLayout;
+        vbox->addLayout(hbox);
+        label = new QLabel(i18n("SASL mechanism:"), authbox);
+        hbox->addWidget(label);
+        mMech = new KComboBox(false, authbox);
+        mMech->setObjectName(QStringLiteral("kcfg_ldapsaslmech"));
+        mMech->setEditable(true);
+        mMech->addItem(QStringLiteral("DIGEST-MD5"));
+        mMech->addItem(QStringLiteral("GSSAPI"));
+        mMech->addItem(QStringLiteral("PLAIN"));
+        hbox->addWidget(mMech);
+
+        //without host query doesn't make sense
+        if (mHost) {
+            mQueryMech = new QPushButton(i18n("Query Server"), authbox);
+            hbox->addWidget(mQueryMech);
+            connect(mQueryMech, SIGNAL(clicked()), mParent, SLOT(queryMechClicked()));
+        }
+
+        mainLayout->addWidget(authbox, row, 0, 2, 4);
+
+        connect(mAnonymous, SIGNAL(toggled(bool)), mParent, SLOT(setAnonymous(bool)));
+        connect(mSimple, SIGNAL(toggled(bool)), mParent, SLOT(setSimple(bool)));
+        connect(mSASL, SIGNAL(toggled(bool)), mParent, SLOT(setSASL(bool)));
+
+        mAnonymous->setChecked(true);
+    }
+}
+
+void LdapConfigWidget::Private::sendQuery()
+{
+    LdapServer _server(mParent->server());
+
+    mQResult.clear();
+    mCancelled = true;
+
+    if (mAttr == QLatin1String("supportedsaslmechanisms")) {
+        _server.setAuth(LdapServer::Anonymous);
+    }
+
+    LdapUrl _url(_server.url());
+
+    _url.setDn(LdapDN(QStringLiteral("")));
+    _url.setAttributes(QStringList(mAttr));
+    _url.setScope(LdapUrl::Base);
+
+    qCDebug(LDAP_LOG) << "sendQuery url:" << _url.toDisplayString();
+
+    LdapSearch search;
+    connect(&search, SIGNAL(data(KLDAP::LdapSearch*,KLDAP::LdapObject)),
+            mParent, SLOT(loadData(KLDAP::LdapSearch*,KLDAP::LdapObject)));
+    connect(&search, SIGNAL(result(KLDAP::LdapSearch*)),
+            mParent, SLOT(loadResult(KLDAP::LdapSearch*)));
+
+    if (!search.search(_url)) {
+        KMessageBox::error(mParent, search.errorString());
+        return;
+    }
+
+    if (mProg == Q_NULLPTR) {
+        mProg = new QProgressDialog(mParent);
+        mProg->setWindowTitle(i18n("LDAP Query"));
+        mProg->setModal(true);
+    }
+    mProg->setLabelText(_url.toDisplayString());
+    mProg->setMaximum(1);
+    mProg->setMinimum(0);
+    mProg->setValue(0);
+    mProg->exec();
+    if (mCancelled) {
+        qCDebug(LDAP_LOG) << "query canceled!";
+        search.abandon();
+    } else {
+        if (search.error()) {
+            if (search.errorString().isEmpty()) {
+                KMessageBox::error(mParent, i18nc("%1 is a url to ldap server", "Unknown error connecting %1", _url.toDisplayString()));
+            } else {
+                KMessageBox::error(mParent, search.errorString());
+            }
+        }
+    }
+}
+
+void LdapConfigWidget::Private::queryMechClicked()
+{
+    mAttr = QStringLiteral("supportedsaslmechanisms");
+    sendQuery();
+    if (!mQResult.isEmpty()) {
+        mQResult.sort();
+        mMech->clear();
+        mMech->addItems(mQResult);
+    }
+}
+
+void LdapConfigWidget::Private::queryDNClicked()
+{
+    mAttr = QStringLiteral("namingcontexts");
+    sendQuery();
+    if (!mQResult.isEmpty()) {
+        mDn->setText(mQResult.first());
+    }
+}
+
+void LdapConfigWidget::Private::loadData(LdapSearch *, const LdapObject &object)
+{
+    qCDebug(LDAP_LOG) << "object:" << object.toString();
+    mProg->setValue(mProg->value() + 1);
+    LdapAttrMap::ConstIterator end(object.attributes().constEnd());
+    for (LdapAttrMap::ConstIterator it = object.attributes().constBegin();
+            it != end; ++it) {
+        LdapAttrValue::ConstIterator end2((*it).constEnd());
+        for (LdapAttrValue::ConstIterator it2 = (*it).constBegin();
+                it2 != end2; ++it2) {
+            mQResult.push_back(QString::fromUtf8(*it2));
+        }
+    }
+}
+
+void LdapConfigWidget::Private::loadResult(LdapSearch *search)
+{
+    Q_UNUSED(search);
+    mCancelled = false;
+    mProg->close();
+}
+
+void LdapConfigWidget::Private::setAnonymous(bool on)
+{
+    if (!on) {
+        return;
+    }
+    if (mUser) {
+        mUser->setEnabled(false);
+    }
+    if (mPassword) {
+        mPassword->setEnabled(false);
+    }
+    if (mBindDn) {
+        mBindDn->setEnabled(false);
+    }
+    if (mRealm) {
+        mRealm->setEnabled(false);
+    }
+    if (mMech) {
+        mMech->setEnabled(false);
+    }
+    if (mQueryMech) {
+        mQueryMech->setEnabled(false);
+    }
+}
+
+void LdapConfigWidget::Private::setSimple(bool on)
+{
+    if (!on) {
+        return;
+    }
+    if (mUser) {
+        mUser->setEnabled(false);
+    }
+    if (mPassword) {
+        mPassword->setEnabled(true);
+    }
+    if (mBindDn) {
+        mBindDn->setEnabled(true);
+    }
+    if (mRealm) {
+        mRealm->setEnabled(false);
+    }
+    if (mMech) {
+        mMech->setEnabled(false);
+    }
+    if (mQueryMech) {
+        mQueryMech->setEnabled(false);
+    }
+}
+
+void LdapConfigWidget::Private::setSASL(bool on)
+{
+    if (!on) {
+        return;
+    }
+    if (mUser) {
+        mUser->setEnabled(true);
+    }
+    if (mPassword) {
+        mPassword->setEnabled(true);
+    }
+    if (mBindDn) {
+        mBindDn->setEnabled(true);
+    }
+    if (mRealm) {
+        mRealm->setEnabled(true);
+    }
+    if (mMech) {
+        mMech->setEnabled(true);
+    }
+    if (mQueryMech) {
+        mQueryMech->setEnabled(true);
+    }
+}
+
+void LdapConfigWidget::Private::setLDAPPort()
+{
+    if (mPort) {
+        mPort->setValue(389);
+    }
+}
+
+void LdapConfigWidget::Private::setLDAPSPort()
+{
+    if (mPort) {
+        mPort->setValue(636);
+    }
+}
+
+LdapConfigWidget::LdapConfigWidget(QWidget *parent, Qt::WindowFlags fl)
+    : QWidget(parent, fl), d(new Private(this))
+{
+}
+
+LdapConfigWidget::LdapConfigWidget(LdapConfigWidget::WinFlags flags,
+                                   QWidget *parent, Qt::WindowFlags fl)
+    : QWidget(parent, fl), d(new Private(this))
+{
+    d->mFeatures = flags;
+
+    d->initWidget();
+}
+
+LdapConfigWidget::~LdapConfigWidget()
+{
+    delete d;
+}
+
+LdapUrl LdapConfigWidget::url() const
+{
+    return server().url();
+}
+
+void LdapConfigWidget::setUrl(const LdapUrl &url)
+{
+    LdapServer _server;
+    _server.setUrl(url);
+    setServer(_server);
+}
+
+LdapServer LdapConfigWidget::server() const
+{
+    LdapServer _server;
+    if (d->mSecSSL && d->mSecSSL->isChecked()) {
+        _server.setSecurity(LdapServer::SSL);
+    } else if (d->mSecTLS && d->mSecTLS->isChecked()) {
+        _server.setSecurity(LdapServer::TLS);
+    } else {
+        _server.setSecurity(LdapServer::None);
+    }
+
+    if (d->mUser) {
+        _server.setUser(d->mUser->text());
+    }
+    if (d->mBindDn) {
+        _server.setBindDn(d->mBindDn->text());
+    }
+    if (d->mPassword) {
+        _server.setPassword(d->mPassword->text());
+    }
+    if (d->mRealm) {
+        _server.setRealm(d->mRealm->text());
+    }
+    if (d->mHost) {
+        _server.setHost(d->mHost->text());
+    }
+    if (d->mPort) {
+        _server.setPort(d->mPort->value());
+    }
+    if (d->mDn) {
+        _server.setBaseDn(LdapDN(d->mDn->text()));
+    }
+    if (d->mFilter) {
+        _server.setFilter(d->mFilter->text());
+    }
+    if (d->mVersion) {
+        _server.setVersion(d->mVersion->value());
+    }
+    if (d->mSizeLimit && d->mSizeLimit->value() != 0) {
+        _server.setSizeLimit(d->mSizeLimit->value());
+    }
+    if (d->mTimeLimit && d->mTimeLimit->value() != 0) {
+        _server.setTimeLimit(d->mTimeLimit->value());
+    }
+    if (d->mPageSize && d->mPageSize->value() != 0) {
+        _server.setPageSize(d->mPageSize->value());
+    }
+    if (d->mAnonymous && d->mAnonymous->isChecked()) {
+        _server.setAuth(LdapServer::Anonymous);
+    } else if (d->mSimple && d->mSimple->isChecked()) {
+        _server.setAuth(LdapServer::Simple);
+    } else if (d->mSASL && d->mSASL->isChecked()) {
+        _server.setAuth(LdapServer::SASL);
+        _server.setMech(d->mMech->currentText());
+    }
+    return _server;
+}
+
+void LdapConfigWidget::setServer(const LdapServer &server)
+{
+    switch (server.security()) {
+    case LdapServer::SSL:
+        if (d->mSecSSL) {
+            d->mSecSSL->setChecked(true);
+        }
+        break;
+    case LdapServer::TLS:
+        if (d->mSecTLS) {
+            d->mSecTLS->setChecked(true);
+        }
+        break;
+    case LdapServer::None:
+        if (d->mSecNo) {
+            d->mSecNo->setChecked(true);
+        }
+        break;
+    }
+
+    switch (server.auth()) {
+    case LdapServer::Anonymous:
+        if (d->mAnonymous) {
+            d->mAnonymous->setChecked(true);
+        }
+        break;
+    case LdapServer::Simple:
+        if (d->mSimple) {
+            d->mSimple->setChecked(true);
+        }
+        break;
+    case LdapServer::SASL:
+        if (d->mSASL) {
+            d->mSASL->setChecked(true);
+        }
+        break;
+    }
+
+    setUser(server.user());
+    setBindDn(server.bindDn());
+    setPassword(server.password());
+    setRealm(server.realm());
+    setHost(server.host());
+    setPort(server.port());
+    setFilter(server.filter());
+    setDn(server.baseDn());
+    setVersion(server.version());
+    setSizeLimit(server.sizeLimit());
+    setTimeLimit(server.timeLimit());
+    setPageSize(server.pageSize());
+    setMech(server.mech());
+}
+
+void LdapConfigWidget::setUser(const QString &user)
+{
+    if (d->mUser) {
+        d->mUser->setText(user);
+    }
+}
+
+QString LdapConfigWidget::user() const
+{
+    return d->mUser ? d->mUser->text() : QString();
+}
+
+void LdapConfigWidget::setPassword(const QString &password)
+{
+    if (d->mPassword) {
+        d->mPassword->setText(password);
+    }
+}
+
+QString LdapConfigWidget::password() const
+{
+    return d->mPassword ? d->mPassword->text() : QString();
+}
+
+void LdapConfigWidget::setBindDn(const QString &binddn)
+{
+    if (d->mBindDn) {
+        d->mBindDn->setText(binddn);
+    }
+}
+
+QString LdapConfigWidget::bindDn() const
+{
+    return d->mBindDn ? d->mBindDn->text() : QString();
+}
+
+void LdapConfigWidget::setRealm(const QString &realm)
+{
+    if (d->mRealm) {
+        d->mRealm->setText(realm);
+    }
+}
+
+QString LdapConfigWidget::realm() const
+{
+    return d->mRealm ? d->mRealm->text() : QString();
+}
+
+void LdapConfigWidget::setHost(const QString &host)
+{
+    if (d->mHost) {
+        d->mHost->setText(host);
+    }
+}
+
+QString LdapConfigWidget::host() const
+{
+    return d->mHost ? d->mHost->text() : QString();
+}
+
+void LdapConfigWidget::setPort(int port)
+{
+    if (d->mPort) {
+        d->mPort->setValue(port);
+    }
+}
+
+int LdapConfigWidget::port() const
+{
+    return d->mPort ? d->mPort->value() : 389;
+}
+
+void LdapConfigWidget::setVersion(int version)
+{
+    if (d->mVersion) {
+        d->mVersion->setValue(version);
+    }
+}
+
+int LdapConfigWidget::version() const
+{
+    return d->mVersion ? d->mVersion->value() : 3;
+}
+
+void LdapConfigWidget::setDn(const LdapDN &dn)
+{
+    if (d->mDn) {
+        d->mDn->setText(dn.toString());
+    }
+}
+
+LdapDN LdapConfigWidget::dn() const
+{
+    return d->mDn ? LdapDN(d->mDn->text()) : LdapDN();
+}
+
+void LdapConfigWidget::setFilter(const QString &filter)
+{
+    if (d->mFilter) {
+        d->mFilter->setText(filter);
+    }
+}
+
+QString LdapConfigWidget::filter() const
+{
+    return d->mFilter ? d->mFilter->text() : QString();
+}
+
+void LdapConfigWidget::setMech(const QString &mech)
+{
+    if (d->mMech == Q_NULLPTR) {
+        return;
+    }
+    if (!mech.isEmpty()) {
+        int i = 0;
+        while (i < d->mMech->count()) {
+            if (d->mMech->itemText(i) == mech) {
+                break;
+            }
+            i++;
+        }
+        if (i == d->mMech->count()) {
+            d->mMech->addItem(mech);
+        }
+        d->mMech->setCurrentIndex(i);
+    }
+}
+
+QString LdapConfigWidget::mech() const
+{
+    return d->mMech ? d->mMech->currentText() : QString();
+}
+
+void LdapConfigWidget::setSecurity(Security security)
+{
+    switch (security) {
+    case None:
+        d->mSecNo->setChecked(true);
+        break;
+    case SSL:
+        d->mSecSSL->setChecked(true);
+        break;
+    case TLS:
+        d->mSecTLS->setChecked(true);
+        break;
+    }
+}
+
+LdapConfigWidget::Security LdapConfigWidget::security() const
+{
+    if (d->mSecTLS->isChecked()) {
+        return TLS;
+    }
+    if (d->mSecSSL->isChecked()) {
+        return SSL;
+    }
+    return None;
+}
+
+void LdapConfigWidget::setAuth(Auth auth)
+{
+    switch (auth) {
+    case Anonymous:
+        d->mAnonymous->setChecked(true);
+        break;
+    case Simple:
+        d->mSimple->setChecked(true);
+        break;
+    case SASL:
+        d->mSASL->setChecked(true);
+        break;
+    }
+}
+
+LdapConfigWidget::Auth LdapConfigWidget::auth() const
+{
+    if (d->mSimple->isChecked()) {
+        return Simple;
+    }
+    if (d->mSASL->isChecked()) {
+        return SASL;
+    }
+    return Anonymous;
+}
+
+void LdapConfigWidget::setSizeLimit(int sizelimit)
+{
+    if (d->mSizeLimit) {
+        d->mSizeLimit->setValue(sizelimit);
+    }
+}
+
+int LdapConfigWidget::sizeLimit() const
+{
+    return d->mSizeLimit ? d->mSizeLimit->value() : 0;
+}
+
+void LdapConfigWidget::setTimeLimit(int timelimit)
+{
+    if (d->mTimeLimit) {
+        d->mTimeLimit->setValue(timelimit);
+    }
+}
+
+int LdapConfigWidget::timeLimit() const
+{
+    return d->mTimeLimit ? d->mTimeLimit->value() : 0;
+}
+
+void LdapConfigWidget::setPageSize(int pagesize)
+{
+    if (d->mPageSize) {
+        d->mPageSize->setValue(pagesize);
+    }
+}
+
+int LdapConfigWidget::pageSize() const
+{
+    return d->mPageSize ? d->mPageSize->value() : 0;
+}
+
+LdapConfigWidget::WinFlags LdapConfigWidget::features() const
+{
+    return d->mFeatures;
+}
+
+void LdapConfigWidget::setFeatures(LdapConfigWidget::WinFlags features)
+{
+    d->mFeatures = features;
+
+    // First delete all the child widgets.
+    // FIXME: I hope it's correct
+    QList<QObject *> ch = children();
+    const int numberOfChild(ch.count());
+    for (int i = 0; i < numberOfChild; ++i) {
+        QWidget *widget = dynamic_cast<QWidget *>(ch[ i ]);
+        if (widget && widget->parent() == this) {
+            delete(widget);
+        }
+    }
+
+    // Re-create child widgets according to the new flags
+    d->initWidget();
+}
+
+#include "moc_ldapconfigwidget.cpp"
diff --git a/src/ldapconfigwidget.h b/src/ldapconfigwidget.h
new file mode 100644 (file)
index 0000000..19ce35f
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPCONFIGWIDGET_H
+#define KLDAP_LDAPCONFIGWIDGET_H
+
+#include <QtCore/QString>
+#include <QWidget>
+
+#include "ldapdn.h"
+#include "kldap_export.h"
+#include "ldapobject.h"
+#include "ldapserver.h"
+#include "ldapurl.h"
+
+namespace KLDAP
+{
+
+class LdapSearch;
+
+/**
+  @brief LDAP Configuration widget
+
+  This class can be used to query the user for LDAP connection parameters.
+  It's KConfigXT compatible, using widget names starting with kcfg_
+*/
+
+class KLDAP_EXPORT LdapConfigWidget : public QWidget
+{
+    Q_OBJECT
+    Q_FLAGS(WinFlags)
+    Q_ENUMS(Security)
+    Q_ENUMS(Auth)
+    Q_PROPERTY(WinFlags features READ features WRITE setFeatures)
+    Q_PROPERTY(QString user READ user WRITE setUser)
+    Q_PROPERTY(QString bindDn READ bindDn WRITE setBindDn)
+    Q_PROPERTY(QString realm READ realm WRITE setRealm)
+    Q_PROPERTY(QString password READ password WRITE setPassword)
+    Q_PROPERTY(QString host READ host WRITE setHost)
+    Q_PROPERTY(int port READ port WRITE setPort)
+    Q_PROPERTY(int version READ version WRITE setVersion)
+    Q_PROPERTY(LdapDN dn READ dn WRITE setDn)
+    Q_PROPERTY(QString filter READ filter WRITE setFilter)
+    Q_PROPERTY(QString mech READ mech WRITE setMech)
+    Q_PROPERTY(Security security READ security WRITE setSecurity)
+    Q_PROPERTY(Auth auth READ auth WRITE setAuth)
+    Q_PROPERTY(int sizeLimit READ sizeLimit WRITE setSizeLimit)
+    Q_PROPERTY(int timeLimit READ timeLimit WRITE setTimeLimit)
+    Q_PROPERTY(int pageSize READ pageSize WRITE setPageSize)
+
+public:
+
+    enum WinFlag {
+        W_USER = 0x1,
+        W_BINDDN = 0x2,
+        W_REALM = 0x4,
+        W_PASS = 0x8,
+        W_HOST = 0x10,
+        W_PORT = 0x20,
+        W_VER = 0x40,
+        W_DN = 0x80,
+        W_FILTER = 0x100,
+        W_SECBOX = 0x200,
+        W_AUTHBOX = 0x400,
+        W_TIMELIMIT = 0x800,
+        W_SIZELIMIT = 0x1000,
+        W_PAGESIZE = 0x2000,
+        W_ALL = 0x2fff
+    };
+
+    typedef enum {
+        None, SSL, TLS
+    } Security;
+    typedef enum {
+        Anonymous, Simple, SASL
+    } Auth;
+
+    Q_DECLARE_FLAGS(WinFlags, WinFlag)
+
+    /** Constructs an empty configuration widget.
+     * You need to call setFlags() after this.
+     * @param parent the QWidget parent
+     * @param fl the window flags to set
+     */
+    explicit LdapConfigWidget(QWidget *parent = Q_NULLPTR, Qt::WindowFlags fl = 0);
+    /** Constructs a configuration widget */
+    explicit LdapConfigWidget(WinFlags flags, QWidget *parent = Q_NULLPTR,
+                              Qt::WindowFlags fl = 0);
+    /** Destructs a configuration widget */
+    virtual ~LdapConfigWidget();
+
+    /** Sets the user name. Kconfig widget name: kcfg_ldapuser
+     *  @param user the user name to set
+     */
+    void setUser(const QString &user);
+    /** Gets the user name. Kconfig widget name: kcfg_ldapuser */
+    QString user() const;
+
+    /** Sets the password. Kconfig widget name: kcfg_ldappassword
+     *  @param password the password to set
+     */
+    void setPassword(const QString &password);
+    /** Gets the password. Kconfig widget name: kcfg_ldappassword */
+    QString password() const;
+
+    /**
+     * Sets the bind dn.
+     * Kconfig widget name: kcfg_ldapbinddn
+     * @param binddn the LDAP Bind DN to set
+     */
+    void setBindDn(const QString &binddn);
+    /** Gets the bind dn. Kconfig widget name: kcfg_ldapbinddn*/
+    QString bindDn() const;
+
+    /** Sets the SASL realm. Kconfig widget name: kcfg_ldaprealm
+     *  @param realm the SASL realm to set
+     */
+    void setRealm(const QString &realm);
+    /** Gets the SASL realm. Kconfig widget name: kcfg_ldaprealm */
+    QString realm() const;
+
+    /** Sets the host name. Kconfig widget name: kcfg_ldaphost
+     *  @param host the LDAP host to set
+     */
+    void setHost(const QString &host);
+    /** Gets the host name. Kconfig widget name: kcfg_ldaphost */
+    QString host() const;
+
+    /** Sets the LDAP port. Kconfig widget name: kcfg_ldapport
+     *  @param port the LDAP port to set
+     */
+    void setPort(int port);
+    /** Gets the LDAP port. Kconfig widget name: kcfg_ldapport */
+    int port() const;
+
+    /** Sets the LDAP protocol version. Kconfig widget name: kcfg_ldapver
+     *  @param version the LDAP protocol version to set
+     */
+    void setVersion(int version);
+    /** Gets the LDAP protocol version. Kconfig widget name: kcfg_ldapver */
+    int version() const;
+
+    /** Sets the LDAP Base DN. Kconfig widget name: kcfg_ldapdn
+     *  @param dn the LDAP Base DN to set
+     */
+    void setDn(const LdapDN &dn);
+    /** Gets the LDAP Base DN. Kconfig widget name: kcfg_ldapdn */
+    LdapDN dn() const;
+
+    /** Sets the LDAP Filter. Kconfig widget name: kcfg_ldapfilter
+     *  @param filter the LDAP Filter to set
+     */
+    void setFilter(const QString &filter);
+    /** Gets the LDAP Filter. Kconfig widget name: kcfg_ldapfilter */
+    QString filter() const;
+
+    /** Sets the SASL Mechanism. Kconfig widget name: kcfg_ldapsaslmech
+     *  @param mech the SASL Mechanism to set
+     */
+    void setMech(const QString &mech);
+    /** Gets the SASL Mechanism. Kconfig widget name: kcfg_ldapsaslmech */
+    QString mech() const;
+
+    /**
+     * Sets the security type (None, SSL, TLS).
+     * Kconfig widget names: kcfg_ldapnosec, kcfg_ldaptls, kcfg_ldapssl
+     * @param security the security type to set
+     */
+    void setSecurity(Security security);
+    /**
+     * Returns the security type.
+     * Kconfig widget names: kcfg_ldapnosec, kcfg_ldaptls, kcfg_ldapssl
+     * @param security the security type to set
+     */
+    Security security() const;
+
+    /**
+     * Sets the authentication type (Anonymous, Simple, SASL).
+     * Kconfig widget names: kcfg_ldapanon, kcfg_ldapsimple, kcfg_ldapsasl
+     * @param auth the authentication type to set
+     */
+    void setAuth(Auth auth);
+    /**
+     * Returns the authentication type.
+     * Kconfig widget names: kcfg_ldapanon, kcfg_ldapsimple, kcfg_ldapsasl
+     * @param auth the authentication type to set
+     */
+    Auth auth() const;
+
+    /**
+     * Sets the size limit.
+     * KConfig widget name: kcfg_ldapsizelimit
+     * @param sizelimit the size limit to set
+     */
+    void setSizeLimit(int sizelimit);
+    /**
+     * Returns the size limit.
+     * KConfig widget name: kcfg_ldapsizelimit
+     */
+    int sizeLimit() const;
+
+    /**
+     * Sets the time limit.
+     * KConfig widget name: kcfg_ldaptimelimit
+     * @param timelimit the time limit to set
+     */
+    void setTimeLimit(int timelimit);
+    /**
+     * Returns the time limit.
+     * KConfig widget name: kcfg_ldaptimelimit
+     */
+    int timeLimit() const;
+
+    /**
+     * Sets the page size.
+     * KConfig widget name: kcfg_ldappagesize
+     * @param pagesize the page size to set
+     */
+    void setPageSize(int pagesize);
+    /**
+     * Returns the page size.
+     * KConfig widget name: kcfg_ldappagesize
+     */
+    int pageSize() const;
+
+    WinFlags features() const;
+    void setFeatures(WinFlags features);
+
+    /**
+     * Returns a LDAP Url constructed from the settings given.
+     * Extensions are filled for use in the LDAP ioslave
+     */
+    LdapUrl url() const;
+    /**
+     * Set up the widget via an LDAP Url.
+     * @param url the LDAP Url to set
+     */
+    void setUrl(const LdapUrl &url);
+
+    /**
+     * Returns an LdapServer object constructed from the settings given.
+     */
+    LdapServer server() const;
+    /**
+     * Set up the widget via an LdapServer object.
+     * @param server the LdapServer object to set
+     */
+    void setServer(const LdapServer &server);
+
+Q_SIGNALS:
+    /**
+     * @since 4.13
+     */
+    void hostNameChanged(const QString &);
+
+private:
+    class Private;
+    Private *const d;
+
+    Q_PRIVATE_SLOT(d, void setLDAPPort())
+    Q_PRIVATE_SLOT(d, void setLDAPSPort())
+    Q_PRIVATE_SLOT(d, void setAnonymous(bool))
+    Q_PRIVATE_SLOT(d, void setSimple(bool))
+    Q_PRIVATE_SLOT(d, void setSASL(bool))
+    Q_PRIVATE_SLOT(d, void queryDNClicked())
+    Q_PRIVATE_SLOT(d, void queryMechClicked())
+    Q_PRIVATE_SLOT(d, void loadData(KLDAP::LdapSearch *, const KLDAP::LdapObject &))
+    Q_PRIVATE_SLOT(d, void loadResult(KLDAP::LdapSearch *))
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(LdapConfigWidget::WinFlags)
+
+}
+
+#endif
diff --git a/src/ldapconnection.cpp b/src/ldapconnection.cpp
new file mode 100644 (file)
index 0000000..86de3d1
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapconnection.h"
+#include "ldapdefs.h"
+#include "kldap_config.h" // SASL2_FOUND, LDAP_FOUND
+
+#include <stdlib.h>
+#include <klocalizedstring.h>
+#include "ldap_debug.h"
+
+#ifdef SASL2_FOUND
+#include <sasl/sasl.h>
+static const sasl_callback_t callbacks[] = {
+    { SASL_CB_ECHOPROMPT, Q_NULLPTR, Q_NULLPTR },
+    { SASL_CB_NOECHOPROMPT, Q_NULLPTR, Q_NULLPTR },
+    { SASL_CB_GETREALM, Q_NULLPTR, Q_NULLPTR },
+    { SASL_CB_USER, Q_NULLPTR, Q_NULLPTR },
+    { SASL_CB_AUTHNAME, Q_NULLPTR, Q_NULLPTR },
+    { SASL_CB_PASS, Q_NULLPTR, Q_NULLPTR },
+    { SASL_CB_CANON_USER, Q_NULLPTR, Q_NULLPTR },
+    { SASL_CB_LIST_END, Q_NULLPTR, Q_NULLPTR }
+};
+
+static bool ldapoperation_sasl_initialized = false;
+#endif
+
+#ifdef LDAP_FOUND
+# ifndef HAVE_WINLDAP_H
+#  include <lber.h>
+#  include <ldap.h>
+#else
+# include <w32-ldap-help.h>
+#endif // HAVE_WINLDAP_H
+
+#ifndef LDAP_OPT_SUCCESS
+#define LDAP_OPT_SUCCESS 0
+#endif
+
+#endif
+
+using namespace KLDAP;
+
+class Q_DECL_HIDDEN LdapConnection::LdapConnectionPrivate
+{
+public:
+    LdapConnectionPrivate();
+    LdapServer mServer;
+    QString mConnectionError;
+
+#ifdef LDAP_FOUND
+    LDAP *mLDAP;
+#else
+    void *mLDAP;
+#endif
+#ifdef SASL2_FOUND
+    sasl_conn_t *mSASLconn;
+#else
+    void *mSASLconn;
+#endif
+
+};
+
+LdapConnection::LdapConnectionPrivate::LdapConnectionPrivate()
+{
+    mSASLconn = Q_NULLPTR;
+#ifdef SASL2_FOUND
+    if (!ldapoperation_sasl_initialized) {
+        sasl_client_init(Q_NULLPTR);
+        ldapoperation_sasl_initialized = true;
+    }
+#endif
+}
+
+LdapConnection::LdapConnection()
+    : d(new LdapConnectionPrivate)
+{
+    d->mLDAP = Q_NULLPTR;
+}
+
+LdapConnection::LdapConnection(const LdapUrl &url)
+    : d(new LdapConnectionPrivate)
+{
+    d->mLDAP = Q_NULLPTR;
+    setUrl(url);
+}
+
+LdapConnection::LdapConnection(const LdapServer &server)
+    : d(new LdapConnectionPrivate)
+{
+    d->mLDAP = Q_NULLPTR;
+    setServer(server);
+}
+
+LdapConnection::~LdapConnection()
+{
+    close();
+    delete d;
+}
+
+void LdapConnection::setUrl(const LdapUrl &url)
+{
+    d->mServer.setUrl(url);
+}
+
+void LdapConnection::setServer(const LdapServer &server)
+{
+    d->mServer = server;
+}
+
+const LdapServer &LdapConnection::server() const
+{
+    return d->mServer;
+}
+
+void *LdapConnection::handle() const
+{
+    return (void *)d->mLDAP;
+}
+
+void *LdapConnection::saslHandle() const
+{
+    return (void *)d->mSASLconn;
+}
+
+QString LdapConnection::errorString(int code)
+{
+    //No translated error messages yet
+#ifdef LDAP_FOUND
+    return QString::fromUtf8(ldap_err2string(code));
+#else
+    return i18n("No LDAP Support...");
+#endif
+}
+
+QString LdapConnection::saslErrorString() const
+{
+#ifdef SASL2_FOUND
+    const char *str;
+    str = sasl_errdetail(d->mSASLconn);
+    return QString::fromLocal8Bit(str);
+#else
+    return i18n("SASL support is not available. Please recompile libkldap with the "
+                "Cyrus-SASL (or compatible) client libraries, or complain to your "
+                "distribution packagers.");
+#endif
+}
+
+QString LdapConnection::connectionError() const
+{
+    return d->mConnectionError;
+}
+
+#ifdef LDAP_FOUND
+int LdapConnection::getOption(int option, void *value) const
+{
+    Q_ASSERT(d->mLDAP);
+    return ldap_get_option(d->mLDAP, option, value);
+}
+
+int LdapConnection::setOption(int option, void *value)
+{
+    Q_ASSERT(d->mLDAP);
+    return ldap_set_option(d->mLDAP, option, value);
+}
+
+int LdapConnection::ldapErrorCode() const
+{
+    Q_ASSERT(d->mLDAP);
+    int err;
+    ldap_get_option(d->mLDAP, LDAP_OPT_ERROR_NUMBER, &err);
+    return err;
+}
+
+QString LdapConnection::ldapErrorString() const
+{
+    Q_ASSERT(d->mLDAP);
+    char *errmsg;
+    ldap_get_option(d->mLDAP, LDAP_OPT_ERROR_STRING, &errmsg);
+    QString msg = QString::fromLocal8Bit(errmsg);
+    free(errmsg);
+    return msg;
+}
+
+bool LdapConnection::setSizeLimit(int sizelimit)
+{
+    Q_ASSERT(d->mLDAP);
+    qCDebug(LDAP_LOG) << "sizelimit:" << sizelimit;
+    if (setOption(LDAP_OPT_SIZELIMIT, &sizelimit) != LDAP_OPT_SUCCESS) {
+        return false;
+    }
+    return true;
+}
+
+int LdapConnection::sizeLimit() const
+{
+    Q_ASSERT(d->mLDAP);
+    int sizelimit;
+    if (getOption(LDAP_OPT_SIZELIMIT, &sizelimit) != LDAP_OPT_SUCCESS) {
+        return -1;
+    }
+    return sizelimit;
+}
+
+bool LdapConnection::setTimeLimit(int timelimit)
+{
+    Q_ASSERT(d->mLDAP);
+    qCDebug(LDAP_LOG) << "timelimit:" << timelimit;
+    if (setOption(LDAP_OPT_TIMELIMIT, &timelimit) != LDAP_OPT_SUCCESS) {
+        return false;
+    }
+    return true;
+}
+
+int LdapConnection::timeLimit() const
+{
+    Q_ASSERT(d->mLDAP);
+    int timelimit;
+    if (getOption(LDAP_OPT_TIMELIMIT, &timelimit) != LDAP_OPT_SUCCESS) {
+        return -1;
+    }
+    return timelimit;
+}
+
+int LdapConnection::connect()
+{
+    int ret;
+    QString url;
+    if (d->mLDAP) {
+        close();
+    }
+
+    int version = d->mServer.version();
+    int timeout = d->mServer.timeout();
+
+    url = d->mServer.security() == LdapServer::SSL ? QStringLiteral("ldaps") : QStringLiteral("ldap");
+    url += QLatin1String("://");
+    url += d->mServer.host();
+    url += QLatin1Char(':');
+    url += QString::number(d->mServer.port());
+    qCDebug(LDAP_LOG) << "ldap url:" << url;
+#ifdef HAVE_LDAP_INITIALIZE
+    ret = ldap_initialize(&d->mLDAP, url.toLatin1().constData());
+#else
+    d->mLDAP = ldap_init(d->mServer.host().toLatin1().data(), d->mServer.port());
+    if (d->mLDAP == 0) {
+        ret = -1;
+    } else {
+        ret = LDAP_SUCCESS;
+    }
+#endif
+    if (ret != LDAP_SUCCESS) {
+        d->mConnectionError = i18n("An error occurred during the connection initialization phase.");
+        return ret;
+    }
+
+    qCDebug(LDAP_LOG) << "setting version to:" << version;
+    if (setOption(LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS) {
+        ret = ldapErrorCode();
+        d->mConnectionError = i18n("Cannot set protocol version to %1.", version);
+        close();
+        return ret;
+    }
+
+#if defined(LDAP_OPT_TIMEOUT)
+    qCDebug(LDAP_LOG) << "setting timeout to:" << timeout;
+
+    if (timeout) {
+        if (setOption(LDAP_OPT_TIMEOUT, &timeout) != LDAP_OPT_SUCCESS) {
+            ret = ldapErrorCode();
+            d->mConnectionError = i18np("Cannot set timeout to %1 second.",
+                                        "Cannot set timeout to %1 seconds.",
+                                        timeout);
+            close();
+            return ret;
+        }
+    }
+#endif
+
+    //FIXME: accessing to certificate handling would be good
+    qCDebug(LDAP_LOG) << "setting security to:" << d->mServer.security();
+    if (d->mServer.security() == LdapServer::TLS) {
+        qCDebug(LDAP_LOG) << "start TLS";
+#ifdef HAVE_LDAP_START_TLS_S
+        if ((ret = ldap_start_tls_s(d->mLDAP, Q_NULLPTR, Q_NULLPTR)) != LDAP_SUCCESS) {
+            d->mConnectionError = ldapErrorString();
+            close();
+            return ret;
+        }
+#else
+        close();
+        d->mConnectionError = i18n("TLS support not available in the LDAP client libraries.");
+        return -1;
+#endif
+    }
+
+    qCDebug(LDAP_LOG) << "setting sizelimit to:" << d->mServer.sizeLimit();
+    if (d->mServer.sizeLimit()) {
+        if (!setSizeLimit(d->mServer.sizeLimit())) {
+            ret = ldapErrorCode();
+            close();
+            d->mConnectionError = i18n("Cannot set size limit.");
+            return ret;
+        }
+    }
+
+    qCDebug(LDAP_LOG) << "setting timelimit to:" << d->mServer.timeLimit();
+    if (d->mServer.timeLimit()) {
+        if (!setTimeLimit(d->mServer.timeLimit())) {
+            ret = ldapErrorCode();
+            close();
+            d->mConnectionError = i18n("Cannot set time limit.");
+            return ret;
+        }
+    }
+
+#ifdef SASL2_FOUND
+    qCDebug(LDAP_LOG) << "initializing SASL client";
+    int saslresult = sasl_client_new("ldap", d->mServer.host().toLatin1(),
+                                     Q_NULLPTR, Q_NULLPTR, callbacks, 0, &d->mSASLconn);
+    if (saslresult != SASL_OK) {
+        d->mConnectionError = i18n("Cannot initialize the SASL client.");
+        return KLDAP_SASL_ERROR;
+    }
+#endif
+
+    return 0;
+}
+
+void LdapConnection::close()
+{
+    if (d->mLDAP) {
+#ifdef HAVE_LDAP_UNBIND_EXT
+        ldap_unbind_ext(d->mLDAP, Q_NULLPTR, Q_NULLPTR);
+#else
+        ldap_unbind(d->mLDAP);
+#endif
+    }
+    d->mLDAP = Q_NULLPTR;
+#ifdef SASL2_FOUND
+    if (d->mSASLconn) {
+        sasl_dispose(&d->mSASLconn);
+        d->mSASLconn = Q_NULLPTR;
+    }
+#endif
+    qCDebug(LDAP_LOG) << "connection closed!";
+}
+#else //LDAP_FOUND
+
+int LdapConnection::getOption(int option, void *value) const
+{
+    qCritical() << "No LDAP support...";
+    return -1;
+}
+
+int LdapConnection::setOption(int option, void *value)
+{
+    qCritical() << "No LDAP support...";
+    return -1;
+}
+
+int LdapConnection::ldapErrorCode() const
+{
+    qCritical() << "No LDAP support...";
+    return -1;
+}
+
+QString LdapConnection::ldapErrorString() const
+{
+    qCritical() << "No LDAP support...";
+    return QString();
+}
+
+bool LdapConnection::setSizeLimit(int sizelimit)
+{
+    qCritical() << "No LDAP support...";
+    return false;
+}
+
+int LdapConnection::sizeLimit() const
+{
+    qCritical() << "No LDAP support...";
+    return -1;
+}
+
+bool LdapConnection::setTimeLimit(int timelimit)
+{
+    qCritical() << "No LDAP support...";
+    return false;
+}
+
+int LdapConnection::timeLimit() const
+{
+    qCritical() << "No LDAP support...";
+    return -1;
+}
+
+int LdapConnection::connect()
+{
+    d->mConnectionError =
+        i18n("LDAP support not compiled in. Please recompile libkldap with the "
+             "OpenLDAP (or compatible) client libraries, or complain to your "
+             "distribution packagers.");
+    qCritical() << "No LDAP support...";
+    return -1;
+}
+
+void LdapConnection::close()
+{
+    qCritical() << "No LDAP support...";
+}
+
+#endif
diff --git a/src/ldapconnection.h b/src/ldapconnection.h
new file mode 100644 (file)
index 0000000..5562ccf
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPCONNECTION_H
+#define KLDAP_LDAPCONNECTION_H
+
+#include <QtCore/QString>
+
+#include "ldapurl.h"
+#include "ldapserver.h"
+#include "kldap_export.h"
+
+namespace KLDAP
+{
+
+/**
+ * @brief
+ * This class represents a connection to an LDAP server.
+ */
+class KLDAP_EXPORT LdapConnection
+{
+public:
+
+    enum SASL_Fields {
+        SASL_Authname = 0x1,
+        SASL_Authzid = 0x2,
+        SASL_Realm = 0x4,
+        SASL_Password = 0x8
+    };
+
+    /** Constructs an LdapConnection object */
+    LdapConnection();
+    /** Constructs an LdapConnection with the parameters given in url */
+    explicit LdapConnection(const LdapUrl &url);
+    /** Constructs an LdapConnection with the parameters given in server */
+    explicit LdapConnection(const LdapServer &server);
+
+    virtual ~LdapConnection();
+
+    /**
+     * Sets the connection parameters via the specified url. After this,
+     * you need to call connect() to connect with the new parameters.
+     * @param url the URL containing the connection parameters
+     */
+    void setUrl(const LdapUrl &url);
+    /**
+     * Returns the connection parameters which was specified with an LDAP Url
+     * or a LdapServer structure.
+     */
+    const LdapServer &server() const;
+    /**
+     * Sets the connection parameters via the specified server structure. After
+     * this, you need to call connect() to connect with the new parameters.
+     * @param server the server object containing the connection parameters
+     */
+    void setServer(const LdapServer &server);
+
+    /**
+     * Sets up the connection parameters with creating a handle to the LDAP server.
+     * Also sets sizelimit and timelimit and starts TLS if it is requested.
+     * Returns 0 if successful, else returns an LDAP error code, and an error
+     * string which is available via connectionError().
+     */
+    int connect();
+    /**
+     * Returns a translated error string if connect() failed.
+     */
+    QString connectionError() const;
+    /**
+     *  Closes the LDAP connection.
+     */
+    void close();
+
+    /** Sets the size limit for the connection.
+     *  @param sizelimit the connection size limit to set
+     */
+    bool setSizeLimit(int sizelimit);
+    /** Returns the current size limit. */
+    int sizeLimit() const;
+
+    /** Sets the time limit for the connection.
+     *  @param timelimit the connection time limit to set
+     */
+    bool setTimeLimit(int timelimit);
+    /** Returns the current time limit. */
+    int timeLimit() const;
+
+    /** Gets an option from the connection. The option value can be client
+      * library specific, so avoid this function if possible
+      * @param option the connection option to return
+      * @param value the value of option to get
+      */
+    int getOption(int option, void *value) const;
+    /** Sets an option in the connection. The option value can be client
+      * library specific, so avoid this function if possible */
+    int setOption(int option, void *value);
+
+    /** Returns the LDAP error code from the last operation */
+    int ldapErrorCode() const;
+    /** Returns the LDAP error string from the last operation */
+    QString ldapErrorString() const;
+    /** Returns a translated error message from the specified LDAP error code */
+    static QString errorString(int code);
+
+    /** Returns the SASL error string from the last SASL operation */
+    QString saslErrorString() const;
+
+    /**
+     * Returns the opaqe client-library specific LDAP object.
+     * Avoid its usage if you can.
+     */
+    void *handle() const;
+
+    /**
+     * Returns the opaqe sasl-library specific SASL object.
+     * Avoid its usage if you can.
+     */
+    void *saslHandle() const;
+
+private:
+    class LdapConnectionPrivate;
+    LdapConnectionPrivate *const d;
+
+    Q_DISABLE_COPY(LdapConnection)
+};
+
+}
+
+#endif
diff --git a/src/ldapcontrol.cpp b/src/ldapcontrol.cpp
new file mode 100644 (file)
index 0000000..4af0f2b
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapcontrol.h"
+#include "ber.h"
+
+#include <QtCore/QSharedData>
+
+using namespace KLDAP;
+
+class LdapControlPrivate : public QSharedData
+{
+public:
+    LdapControlPrivate()
+    {
+        mCritical = false;
+    }
+
+    LdapControlPrivate(const LdapControlPrivate &other)
+        : QSharedData(other)
+    {
+        mOid = other.mOid;
+        mValue = other.mValue;
+        mCritical = other.mCritical;
+    }
+
+    QString mOid;
+    QByteArray mValue;
+    bool mCritical;
+};
+
+LdapControl::LdapControl()
+    : d(new LdapControlPrivate)
+{
+    setControl(QString(), QByteArray(), false);
+}
+
+LdapControl::LdapControl(const QString &oid, const QByteArray &value, bool critical)
+    : d(new LdapControlPrivate)
+{
+    setControl(oid, value, critical);
+}
+
+LdapControl::LdapControl(const LdapControl &that)
+    : d(that.d)
+{
+    setControl(that.d->mOid, that.d->mValue, that.d->mCritical);
+}
+
+LdapControl &LdapControl::operator= (const LdapControl &that)
+{
+    if (this != &that) {
+        d = that.d;
+    }
+
+    setControl(that.d->mOid, that.d->mValue, that.d->mCritical);
+
+    return *this;
+}
+
+LdapControl::~LdapControl()
+{
+}
+
+void LdapControl::setControl(const QString &oid, const QByteArray &value, bool critical)
+{
+    d->mOid = oid;
+    d->mValue = value;
+    d->mCritical = critical;
+}
+
+QString LdapControl::oid() const
+{
+    return d->mOid;
+}
+
+QByteArray LdapControl::value() const
+{
+    return d->mValue;
+}
+
+bool LdapControl::critical() const
+{
+    return d->mCritical;
+}
+
+void LdapControl::setOid(const QString &oid)
+{
+    d->mOid = oid;
+}
+
+void LdapControl::setValue(const QByteArray &value)
+{
+    d->mValue = value;
+}
+
+void LdapControl::setCritical(bool critical)
+{
+    d->mCritical = critical;
+}
+
+int LdapControl::parsePageControl(QByteArray &cookie) const
+{
+    if (d->mOid != QLatin1String("1.2.840.113556.1.4.319")) {
+        return -1;
+    }
+
+    Ber ber(d->mValue);
+    int size;
+    if (ber.scanf(QStringLiteral("{iO}"), &size, &cookie) == -1) {
+        return -1;
+    } else {
+        return size;
+    }
+}
+
+LdapControl LdapControl::createPageControl(int pagesize, const QByteArray &cookie)
+{
+    LdapControl control;
+    Ber ber;
+
+    ber.printf(QStringLiteral("{iO}"), pagesize, &cookie);
+    control.setOid(QStringLiteral("1.2.840.113556.1.4.319"));
+    control.setValue(ber.flatten());
+    return control;
+}
+
+void LdapControl::insert(LdapControls &list, const LdapControl &ctrl)
+{
+    LdapControls::iterator it;
+    LdapControls::iterator endit = list.end();
+    const QString oid = ctrl.oid();
+
+    for (it = list.begin(); it != endit; ++it) {
+        if (it->oid() == oid) {
+            *it = ctrl;
+            return;
+        }
+    }
+    list.append(ctrl);
+}
diff --git a/src/ldapcontrol.h b/src/ldapcontrol.h
new file mode 100644 (file)
index 0000000..01a34eb
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPCONTROL_H
+#define KLDAP_LDAPCONTROL_H
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+#include <QtCore/QSharedDataPointer>
+class LdapControlPrivate;
+
+#include "kldap_export.h"
+
+namespace KLDAP
+{
+
+class LdapControl;
+typedef QVector<LdapControl> LdapControls;
+
+/**
+  @brief
+  This class represents an LDAP Control
+*/
+class KLDAP_EXPORT LdapControl
+{
+public:
+    /**
+     * Creates an empty control.
+     */
+    LdapControl();
+    /**
+     * Creates a control with the given OID, value and criticality.
+     */
+    LdapControl(const QString &oid, const QByteArray &value, bool critical = false);
+
+    LdapControl(const LdapControl &that);
+    LdapControl &operator= (const LdapControl &that);
+    /**
+     * Destroys the control object.
+     */
+    virtual ~LdapControl();
+    /**
+     * Sets the control's OID, value and criticality.
+     */
+    void setControl(const QString &oid, const QByteArray &value,
+                    bool critical = false);
+    /**
+     * Sets the control's OID.
+     */
+    void setOid(const QString &oid);
+    /**
+     * Sets the control's value.
+     */
+    void setValue(const QByteArray &value);
+    /**
+     * Sets the control's criticality.
+     */
+    void setCritical(bool critical);
+    /**
+     * Returns the control's OID.
+     */
+    QString oid() const;
+    /**
+     * Returns the control's value.
+     */
+    QByteArray value() const;
+    /**
+     * Returns the control's criticality.
+     */
+    bool critical() const;
+
+    /**
+     * Parses a paging results control, which the server returned.
+     * Puts the server's cookie into @p cookie, and returns the estimated
+     * result set size. If the OID is not the page control's OID, or the
+     * value cannot be decoded, returns -1.
+     * @param cookie the cookie to hold server's cookie
+     */
+    int parsePageControl(QByteArray &cookie) const;
+    /**
+     * Creates a paging search control.
+     */
+    static LdapControl createPageControl(int pagesize, const QByteArray &cookie = QByteArray());
+
+    /**
+     * Inserts a unique control against a list of controls.
+     * If the control already exists in the list is is updated, otherwise
+     * it is appended to the list.
+     * @param list the current list of controls
+     * @param ctrl the control to insert
+     * @since 4.4
+     */
+    static void insert(LdapControls &list, const LdapControl &ctrl);
+
+private:
+    QSharedDataPointer<LdapControlPrivate> d;
+};
+
+}
+
+#endif
diff --git a/src/ldapdefs.h b/src/ldapdefs.h
new file mode 100644 (file)
index 0000000..9a643f9
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_DEFS_H
+#define KLDAP_DEFS_H
+
+/**
+ * LDAP Error codes.
+ * These codes taken from openldap's ldap.h, and prefixed with KLDAP_
+ * instead of LDAP_, just for applications which uses the kldap library
+ * doesn't need to include openldap headers
+ */
+
+#define KLDAP_SUCCESS                    0x00
+
+#define KLDAP_RANGE(n,x,y)       (((x) <= (n)) && ((n) <= (y)))
+
+#define KLDAP_OPERATIONS_ERROR           0x01
+#define KLDAP_PROTOCOL_ERROR             0x02
+#define KLDAP_TIMELIMIT_EXCEEDED         0x03
+#define KLDAP_SIZELIMIT_EXCEEDED         0x04
+#define KLDAP_COMPARE_FALSE              0x05
+#define KLDAP_COMPARE_TRUE               0x06
+#define KLDAP_AUTH_METHOD_NOT_SUPPORTED  0x07
+#define KLDAP_STRONG_AUTH_NOT_SUPPORTED  KLDAP_AUTH_METHOD_NOT_SUPPORTED
+#define KLDAP_STRONG_AUTH_REQUIRED       0x08
+#define KLDAP_STRONGER_AUTH_REQUIRED     KLDAP_STRONG_AUTH_REQUIRED
+#define KLDAP_PARTIAL_RESULTS            0x09    /* LDAPv2+ (not LDAPv3) */
+
+#define KLDAP_REFERRAL                   0x0a /* LDAPv3 */
+#define KLDAP_ADMINLIMIT_EXCEEDED        0x0b /* LDAPv3 */
+#define KLDAP_UNAVAILABLE_CRITICAL_EXTENSION     0x0c /* LDAPv3 */
+#define KLDAP_CONFIDENTIALITY_REQUIRED   0x0d /* LDAPv3 */
+#define KLDAP_SASL_BIND_IN_PROGRESS      0x0e /* LDAPv3 */
+
+#define KLDAP_ATTR_ERROR(n)      KLDAP_RANGE((n),0x10,0x15) /* 16-21 */
+
+#define KLDAP_NO_SUCH_ATTRIBUTE          0x10
+#define KLDAP_UNDEFINED_TYPE             0x11
+#define KLDAP_INAPPROPRIATE_MATCHING     0x12
+#define KLDAP_CONSTRAINT_VIOLATION       0x13
+#define KLDAP_TYPE_OR_VALUE_EXISTS       0x14
+#define KLDAP_INVALID_SYNTAX             0x15
+
+#define KLDAP_NAME_ERROR(n)      KLDAP_RANGE((n),0x20,0x24) /* 32-34,36 */
+
+#define KLDAP_NO_SUCH_OBJECT             0x20
+#define KLDAP_ALIAS_PROBLEM              0x21
+#define KLDAP_INVALID_DN_SYNTAX          0x22
+#define KLDAP_IS_LEAF                    0x23 /* not LDAPv3 */
+#define KLDAP_ALIAS_DEREF_PROBLEM        0x24
+
+#define KLDAP_SECURITY_ERROR(n)  KLDAP_RANGE((n),0x2F,0x32) /* 47-50 */
+
+#define KLDAP_PROXY_AUTHZ_FAILURE        0x2F /* LDAPv3 proxy authorization */
+#define KLDAP_INAPPROPRIATE_AUTH         0x30
+#define KLDAP_INVALID_CREDENTIALS        0x31
+#define KLDAP_INSUFFICIENT_ACCESS        0x32
+
+#define KLDAP_SERVICE_ERROR(n)   KLDAP_RANGE((n),0x33,0x36) /* 51-54 */
+
+#define KLDAP_BUSY                       0x33
+#define KLDAP_UNAVAILABLE                0x34
+#define KLDAP_UNWILLING_TO_PERFORM       0x35
+#define KLDAP_LOOP_DETECT                0x36
+
+#define KLDAP_UPDATE_ERROR(n)    KLDAP_RANGE((n),0x40,0x47) /* 64-69,71 */
+
+#define KLDAP_NAMING_VIOLATION           0x40
+#define KLDAP_OBJECT_CLASS_VIOLATION     0x41
+#define KLDAP_NOT_ALLOWED_ON_NONLEAF     0x42
+#define KLDAP_NOT_ALLOWED_ON_RDN         0x43
+#define KLDAP_ALREADY_EXISTS             0x44
+#define KLDAP_NO_OBJECT_CLASS_MODS       0x45
+#define KLDAP_RESULTS_TOO_LARGE          0x46 /* CLDAP */
+#define KLDAP_AFFECTS_MULTIPLE_DSAS      0x47
+
+#define KLDAP_OTHER                      0x50
+
+/* LCUP operation codes (113-117) - not implemented */
+#define KLDAP_CUP_RESOURCES_EXHAUSTED    0x71
+#define KLDAP_CUP_SECURITY_VIOLATION     0x72
+#define KLDAP_CUP_INVALID_DATA           0x73
+#define KLDAP_CUP_UNSUPPORTED_SCHEME     0x74
+#define KLDAP_CUP_RELOAD_REQUIRED        0x75
+
+/* Cancel operation codes (118-121) */
+#define KLDAP_CANCELLED                  0x76
+#define KLDAP_NO_SUCH_OPERATION          0x77
+#define KLDAP_TOO_LATE                   0x78
+
+#define KLDAP_CANNOT_CANCEL              0x79
+
+/* Assertion control (122) */
+#define KLDAP_ASSERTION_FAILED           0x7A
+
+/* Experimental result codes */
+#define KLDAP_E_ERROR(n) KLDAP_RANGE((n),0x1000,0x3FFF)
+
+/* LDAP Sync (4096) */
+#define KLDAP_SYNC_REFRESH_REQUIRED      0x1000
+
+/* Private Use result codes */
+#define KLDAP_X_ERROR(n) KLDAP_RANGE((n),0x4000,0xFFFF)
+
+#define KLDAP_X_SYNC_REFRESH_REQUIRED    0x4100 /* defunct */
+#define KLDAP_X_ASSERTION_FAILED         0x410f /* defunct */
+
+/* for the LDAP No-Op control */
+#define KLDAP_X_NO_OPERATION             0x410e
+
+/** API Error Codes
+ *
+ * Based on draft-ietf-ldap-c-api-xx
+ * but with new negative code values
+ */
+#define KLDAP_API_ERROR(n)               ((n)<0)
+#define KLDAP_API_RESULT(n)              ((n)<=0)
+
+#define KLDAP_SERVER_DOWN                (-1)
+#define KLDAP_LOCAL_ERROR                (-2)
+#define KLDAP_ENCODING_ERROR             (-3)
+#define KLDAP_DECODING_ERROR             (-4)
+#define KLDAP_TIMEOUT                    (-5)
+#define KLDAP_AUTH_UNKNOWN               (-6)
+#define KLDAP_FILTER_ERROR               (-7)
+#define KLDAP_USER_CANCELLED             (-8)
+#define KLDAP_PARAM_ERROR                (-9)
+#define KLDAP_NO_MEMORY                  (-10)
+#define KLDAP_CONNECT_ERROR              (-11)
+#define KLDAP_NOT_SUPPORTED              (-12)
+#define KLDAP_CONTROL_NOT_FOUND          (-13)
+#define KLDAP_NO_RESULTS_RETURNED        (-14)
+#define KLDAP_MORE_RESULTS_TO_RETURN     (-15)   /* Obsolete */
+#define KLDAP_CLIENT_LOOP                (-16)
+#define KLDAP_REFERRAL_LIMIT_EXCEEDED    (-17)
+
+/*
+ * KLDAP Specific
+ */
+
+#define KLDAP_SASL_ERROR                 -0xff
+
+#endif //KLDAP_DEFS_H
diff --git a/src/ldapdn.cpp b/src/ldapdn.cpp
new file mode 100644 (file)
index 0000000..6bcdf84
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapdn.h"
+
+#include <algorithm>
+
+#include "ldap_debug.h"
+
+using namespace KLDAP;
+
+class Q_DECL_HIDDEN LdapDN::LdapDNPrivate
+{
+public:
+    LdapDNPrivate() : m_dn() {}
+    ~LdapDNPrivate() {}
+
+    bool isValidRDNString(const QString &rdn) const;
+    QStringList splitOnNonEscapedChar(const QString &rdn, QChar ch) const;
+
+    QString m_dn;
+};
+
+bool LdapDN::LdapDNPrivate::isValidRDNString(const QString &rdn) const
+{
+    qCDebug(LDAP_LOG) << "Testing rdn:" << rdn;
+
+    // If it is a muli-valued rdn, split it into its constituent parts
+    const QStringList rdnParts = splitOnNonEscapedChar(rdn, QLatin1Char('+'));
+    const int rdnPartsSize(rdnParts.size());
+    if (rdnPartsSize > 1) {
+        for (int i = 0; i < rdnPartsSize; i++) {
+            if (!isValidRDNString(rdnParts.at(i))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    // Split the rdn into the attribute name and value parts
+    QStringList components = rdn.split(QLatin1Char('='));
+
+    // We should have exactly two parts
+    if (components.size() != 2) {
+        return false;
+    }
+
+    return true;
+}
+
+QStringList LdapDN::LdapDNPrivate::splitOnNonEscapedChar(const QString &str, QChar ch) const
+{
+    QStringList strParts;
+    int index = 0;
+    int searchFrom = 0;
+    int strPartStartIndex = 0;
+    while ((index = str.indexOf(ch, searchFrom)) != -1) {
+        const QChar prev = str[std::max(0, index - 1)];
+        if (prev != QLatin1Char('\\')) {
+            // Found a component of a multi-valued RDN
+            //qCDebug(LDAP_LOG) << "Found" << ch << "at index" << index;
+            QString tmp = str.mid(strPartStartIndex, index - strPartStartIndex);
+            //qCDebug(LDAP_LOG) << "Adding part:" << tmp;
+            strParts.append(tmp);
+            strPartStartIndex = index + 1;
+        }
+
+        searchFrom = index + 1;
+    }
+
+    // Add on the part after the last found delimeter
+    QString tmp = str.mid(strPartStartIndex);
+    //qCDebug(LDAP_LOG) << "Adding part:" << tmp;
+    strParts.append(tmp);
+
+    return strParts;
+}
+
+LdapDN::LdapDN()
+    : d(new LdapDNPrivate)
+{
+
+}
+
+LdapDN::LdapDN(const QString &dn)
+    : d(new LdapDNPrivate)
+{
+    d->m_dn = dn;
+}
+
+LdapDN::LdapDN(const LdapDN &that)
+    : d(new LdapDNPrivate)
+{
+    *d = *that.d;
+}
+
+LdapDN &LdapDN::operator=(const LdapDN &that)
+{
+    if (this == &that) {
+        return *this;
+    }
+
+    *d = *that.d;
+    return *this;
+}
+
+LdapDN::~LdapDN()
+{
+    delete d;
+}
+
+void LdapDN::clear()
+{
+    d->m_dn.clear();
+}
+
+bool LdapDN::isEmpty() const
+{
+    return d->m_dn.isEmpty();
+}
+
+QString LdapDN::toString() const
+{
+    return d->m_dn;
+}
+
+QString LdapDN::toString(int depth) const
+{
+    QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(','));
+    if (depth >= rdns.size()) {
+        return QString();
+    }
+
+    // Construct a DN down to the requested depth
+    QString dn;
+    for (int i = depth; i >= 0; i--) {
+        dn += rdns.at(rdns.size() - 1 - i) + QLatin1Char(',');
+        qCDebug(LDAP_LOG) << "dn =" << dn;
+    }
+    dn = dn.left(dn.length() - 1);   // Strip off the extraneous comma
+
+    return dn;
+}
+
+QString LdapDN::rdnString() const
+{
+    /** \TODO We should move this into the d pointer as we calculate rdns quite a lot */
+    QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(','));
+    return rdns.at(0);
+}
+
+QString LdapDN::rdnString(int depth) const
+{
+    QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(','));
+    if (depth >= rdns.size()) {
+        return QString();
+    }
+    return rdns.at(rdns.size() - 1 - depth);
+}
+
+bool LdapDN::isValid() const
+{
+    qCDebug(LDAP_LOG) << "Testing dn:" << d->m_dn;
+
+    // Break the string into rdn's
+    const QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(','));
+
+    // Test to see if each rdn is valid
+    const int rdnsSize(rdns.size());
+    for (int i = 0; i < rdnsSize; i++) {
+        if (!d->isValidRDNString(rdns.at(i))) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+int LdapDN::depth() const
+{
+    QStringList rdns = d->splitOnNonEscapedChar(d->m_dn, QLatin1Char(','));
+    return rdns.size();
+}
+
+bool LdapDN::operator == (const LdapDN &rhs) const
+{
+    return d->m_dn == rhs.d->m_dn;
+}
+
+bool LdapDN::operator != (const LdapDN &rhs) const
+{
+    return d->m_dn != rhs.d->m_dn;
+}
diff --git a/src/ldapdn.h b/src/ldapdn.h
new file mode 100644 (file)
index 0000000..939e6eb
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPDN_H
+#define KLDAP_LDAPDN_H
+
+#include "kldap_export.h"
+
+#include <QtCore/QStringList>
+
+namespace KLDAP
+{
+
+class KLDAP_EXPORT LdapDN
+{
+public:
+    explicit LdapDN();
+    explicit LdapDN(const QString &dn);
+
+    LdapDN(const LdapDN &that);
+    LdapDN &operator=(const LdapDN &that);
+
+    ~LdapDN();
+
+    void clear();
+
+    bool isEmpty() const;
+
+    /**
+     * \returns A QString representing the DN.
+     */
+    QString toString() const;
+
+    /**
+     * \param depth The depth of the DN to return using a zero-based index.
+     * \returns A QString representing the DN levels deep in the directory.
+     */
+    QString toString(int depth) const;
+
+    /**
+     * \returns A QString representing the RDN of this DN.
+     */
+    QString rdnString() const;
+
+    /**
+     * \param depth The depth of the RDN to return using a zero-based index.
+     * \returns A QString representing the RDN levels deep in the directory.
+     */
+    QString rdnString(int depth) const;
+
+    /**
+     * \returns True if this is a valid DN, false otherwise.
+     */
+    bool isValid() const;
+
+    /**
+     * \returns The depth of this DN in the directory.
+     */
+    int depth() const;
+
+    bool operator == (const LdapDN &rhs) const;
+
+    bool operator != (const LdapDN &rhs) const;
+
+private:
+    class LdapDNPrivate;
+    LdapDNPrivate *const d;
+};
+
+}
+
+#endif
diff --git a/src/ldapmodel.cpp b/src/ldapmodel.cpp
new file mode 100644 (file)
index 0000000..994e352
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapmodel.h"
+#include "ldapmodel_p.h"
+#include "ldapmodelnode_p.h"
+#include "ldapsearch.h"
+
+#include "ldap_debug.h"
+#include <klocalizedstring.h>
+
+using namespace KLDAP;
+
+LdapModel::LdapModel(QObject *parent)
+    : QAbstractItemModel(parent),
+      m_d(new LdapModelPrivate(this))
+{
+    m_d->createConnections();
+}
+
+LdapModel::LdapModel(LdapConnection &connection, QObject *parent)
+    : QAbstractItemModel(parent),
+      m_d(new LdapModelPrivate(this, connection))
+{
+    m_d->createConnections();
+
+    // Populate items from the root object to that representing the baseDN
+    m_d->populateRootToBaseDN();
+}
+
+LdapModel::~LdapModel()
+{
+    delete m_d;
+}
+
+void LdapModel::setConnection(LdapConnection &connection)
+{
+    m_d->setConnection(connection);
+
+    // Refresh the model
+    m_d->recreateRootItem();
+
+    // Populate the root object by searching the baseDN
+    m_d->populateRootToBaseDN();
+}
+
+QModelIndex LdapModel::parent(const QModelIndex &child) const
+{
+    if (!child.isValid()) {
+        return QModelIndex();
+    }
+
+    LdapModelNode *childItem = static_cast<LdapModelNode *>(child.internalPointer());
+    LdapModelDNNode *parentItem = childItem->parent();
+
+    if (parentItem == m_d->rootNode()) {
+        return QModelIndex();
+    }
+
+    return createIndex(parentItem->row(), 0, parentItem);
+}
+
+QModelIndex LdapModel::index(int row, int col, const QModelIndex &parent) const
+{
+    // Retrieve a pointer to the parent item
+    LdapModelDNNode *parentItem;
+    if (!parent.isValid()) {
+        parentItem = m_d->rootNode();
+    } else {
+        parentItem = static_cast<LdapModelDNNode *>(parent.internalPointer());
+    }
+
+    LdapModelNode *childItem = parentItem->child(row);
+    if (childItem) {
+        return createIndex(row, col, childItem);
+    }
+    qCDebug(LDAP_LOG) << "Could not create valid index for row =" << row << ", col =" << col;
+    return QModelIndex();
+}
+
+QVariant LdapModel::data(const QModelIndex &index, int role) const
+{
+    if (!index.isValid()) {
+        return QVariant();
+    }
+
+    if (role == Qt::DisplayRole) {
+        // This is what gets displayed by the view delegates.
+        LdapModelNode *node = static_cast<LdapModelNode *>(index.internalPointer());
+        if (node->nodeType() == LdapModelNode::DN) {
+            LdapModelDNNode *dn = static_cast<LdapModelDNNode *>(node);
+            if (index.column() == 0) {
+                return dn->dn().rdnString();
+            } else {
+                return QVariant();
+            }
+        } else {
+            LdapModelAttrNode *attr = static_cast<LdapModelAttrNode *>(node);
+            if (index.column() == 0) {
+                return QVariant(attr->attributeName());
+            } else {
+                return QVariant(QLatin1String(attr->attributeData().constData()));
+            }
+        }
+    } else if (role == NodeTypeRole) {
+        LdapModelNode *node = static_cast<LdapModelNode *>(index.internalPointer());
+        return QVariant(int(node->nodeType()));
+    }
+
+    /** \todo Include support for nice decorative icons dependent upon
+        the objectClass + other role data. */
+    /** \todo Include support for other roles as needed */
+
+    return QVariant();
+}
+
+bool LdapModel::setData(const QModelIndex &index,
+                        const QVariant &value,
+                        int role)
+{
+    Q_UNUSED(index);
+    Q_UNUSED(value);
+    Q_UNUSED(role);
+    return false;
+}
+
+QVariant LdapModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+        if (section == 0) {
+            return i18n("Attribute");
+        } else {
+            return i18n("Value");
+        }
+    }
+
+    return QVariant();
+}
+
+Qt::ItemFlags LdapModel::flags(const QModelIndex &index) const
+{
+    /** \TODO Read-only for now, make read-write upon request */
+    if (!index.isValid()) {
+        return Qt::ItemIsEnabled;
+    }
+
+    return Qt::ItemFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
+}
+
+int LdapModel::columnCount(const QModelIndex &parent) const
+{
+    LdapModelDNNode *parentNode =
+        parent.isValid() ? static_cast<LdapModelDNNode *>(parent.internalPointer()) : m_d->rootNode();
+    return parentNode->columnCount();
+}
+
+int LdapModel::rowCount(const QModelIndex &parent) const
+{
+    if (parent.column() > 0) {
+        return 0;
+    }
+
+    const LdapModelDNNode *parentNode =
+        parent.isValid() ? static_cast<LdapModelDNNode *>(parent.internalPointer()) : m_d->rootNode();
+    return parentNode->childCount();
+}
+
+bool LdapModel::hasChildren(const QModelIndex &parent) const
+{
+    // We return true unless the item has been populated and we are able to do a definitive test
+    const LdapModelNode *node = parent.isValid() ?
+                                static_cast<const LdapModelNode *>(parent.internalPointer()) :
+                                m_d->rootNode();
+
+    if (node->nodeType() != LdapModelNode::DN) {
+        return false;
+    }
+
+    const LdapModelDNNode *parentNode = static_cast<const LdapModelDNNode *>(node);
+    if (!parent.isValid() || parentNode->isPopulated()) {
+        return parentNode->childCount() > 0;
+    }
+    return true;
+}
+
+bool LdapModel::canFetchMore(const QModelIndex &parent) const
+{
+    const LdapModelDNNode *parentNode =
+        parent.isValid() ? static_cast<LdapModelDNNode *>(parent.internalPointer()) : m_d->rootNode();
+    return !parentNode->isPopulated();
+}
+
+void LdapModel::fetchMore(const QModelIndex &parent)
+{
+    LdapModelDNNode *parentNode =
+        parent.isValid() ? static_cast<LdapModelDNNode *>(parent.internalPointer()) : m_d->rootNode();
+
+    // Search for the immediate children of parentItem.
+    m_d->searchResults().clear();
+    m_d->setSearchType(LdapModelPrivate::ChildObjects, parentNode);
+    m_d->search(parentNode->dn(),   // DN to search from
+                LdapUrl::One,      // What to search
+                QString());        // Attributes to retrieve
+    parentNode->setPopulated(true);
+}
+
+bool LdapModel::insertRows(int row, int count,
+                           const QModelIndex &parent)
+{
+    Q_UNUSED(row);
+    Q_UNUSED(count);
+    Q_UNUSED(parent);
+    return false;
+}
+
+bool LdapModel::removeRows(int row, int count,
+                           const QModelIndex &parent)
+{
+    Q_UNUSED(row);
+    Q_UNUSED(count);
+    Q_UNUSED(parent);
+    return false;
+}
+
+void LdapModel::sort(int column, Qt::SortOrder order)
+{
+    Q_UNUSED(column);
+    Q_UNUSED(order);
+}
+
+Qt::DropActions LdapModel::supportedDropActions() const
+{
+    return Qt::MoveAction;
+}
+
+QMimeData *LdapModel::mimeData(const QModelIndexList &indexes) const
+{
+    Q_UNUSED(indexes);
+    return Q_NULLPTR;
+}
+
+bool LdapModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
+                             int row, int column, const QModelIndex &parent)
+{
+    /** \todo Implement drag and drop for LdapModel */
+    Q_UNUSED(data);
+    Q_UNUSED(action);
+    Q_UNUSED(row);
+    Q_UNUSED(column);
+    Q_UNUSED(parent);
+    return false;
+}
+
+bool LdapModel::hasChildrenOfType(const QModelIndex &parent, LdapDataType type) const
+{
+    // Map from LdapDataType to our internal NodeType
+    LdapModelNode::NodeType nodeType;
+    switch (type) {
+    case Attribute:
+        nodeType = LdapModelNode::Attr;
+        break;
+
+    case DistinguishedName:
+    default:
+        nodeType = LdapModelNode::DN;
+        break;
+    }
+
+    const LdapModelNode *node = parent.isValid() ?
+                                static_cast<const LdapModelNode *>(parent.internalPointer()) :
+                                m_d->rootNode();
+
+    const LdapModelDNNode *parentNode = static_cast<const LdapModelDNNode *>(node);
+    if (!parent.isValid() || parentNode->isPopulated()) {
+        // Check to see if the parent has any children of the specified type
+        const QList<LdapModelNode *> &children = parentNode->children();
+        foreach (LdapModelNode *child, children) {
+            if (child->nodeType() == nodeType) {
+                return true;
+            }
+        }
+
+        // Either there are no children or only children of a different type
+        return false;
+    }
+
+    // If the node is not populated or is the root node (invalid), then return
+    // true to be on the safe side.
+    return true;
+}
+
+void LdapModel::revert()
+{
+
+}
+
+bool LdapModel::submit()
+{
+    return false;
+}
+
+#include "moc_ldapmodel.cpp"
diff --git a/src/ldapmodel.h b/src/ldapmodel.h
new file mode 100644 (file)
index 0000000..3bd4495
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPMODEL_H
+#define KLDAP_LDAPMODEL_H
+
+#include <QtCore/QAbstractItemModel>
+
+#include "ldapconnection.h"
+#include "ldapobject.h"
+#include "kldap_export.h"
+
+namespace KLDAP
+{
+
+/**
+ * A ModelView interface to an LDAP tree. At present the model is read only. Editing is
+ * planned for a future release.
+ *
+ * This class is best used in conjunction with an LdapStructureProxyModel object for
+ * displaying the structure of an LDAP tree, and with LdapAttributeProxyModel for
+ * displaying the attributes of particular objects within the tree.
+ *
+ * \author Sean Harmer <sh@theharmers.co.uk>
+ */
+class KLDAP_EXPORT LdapModel : public QAbstractItemModel
+{
+    Q_OBJECT
+public:
+    enum Roles {
+        NodeTypeRole = Qt::UserRole + 1
+    };
+
+    enum LdapDataType {
+        DistinguishedName = 0,
+        Attribute
+    };
+
+    /**
+     * Constructs an LdapModel. You should set a connection for the model to use with
+     * setConnection(). Clients of this class should connect a slot to the ready() signal
+     * before setting this model onto a view.
+     * @param parent the parent QObject
+     * \see setConnection()
+     * \see ready()
+     */
+    explicit LdapModel(QObject *parent = Q_NULLPTR);
+    /**
+     * Constructs an LdapModel. Clients of this class should connect a slot to the ready()
+     * signal before setting this model onto a view.
+     * @param connection the Ldap connection to use in model construction
+     * @param parent the parent QObject
+     * \see setConnection()
+     * \see ready()
+     */
+    explicit LdapModel(LdapConnection &connection, QObject *parent = Q_NULLPTR);
+    virtual ~LdapModel();
+
+    /**
+     * Set the connection that the model should use.
+     * @param connection the model connection to set
+     * \see LdapConnection
+     * \see LdapUrl
+     */
+    void setConnection(LdapConnection &connection);
+
+    //
+    // Implement the usual QAbstractItemModel interface
+    //
+    /**
+     * Reimplemented from QAbstractItemModel::index().
+     */
+    QModelIndex index(int row, int col, const QModelIndex &parent) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::parent().
+     */
+    QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::data().
+     */
+    QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::setData(). This is a placeholder for when
+     * LdapModel beomes writeable and always returns false.
+     */
+    bool setData(const QModelIndex &index,
+                 const QVariant &value,
+                 int role = Qt::EditRole) Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::headerData().
+     */
+    QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::flags().
+     */
+    Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::columnCount().
+     */
+    int columnCount(const QModelIndex &parent) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::rowCount().
+     */
+    int rowCount(const QModelIndex &parent) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::hasChildren().
+     */
+    bool hasChildren(const QModelIndex &parent) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::canFetchMore().
+     */
+    bool canFetchMore(const QModelIndex &parent) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::fetchMore().
+     */
+    void fetchMore(const QModelIndex &parent) Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::insertRows(). This is a placeholder for when
+     * LdapModel beomes writeable and always returns false.
+     */
+    bool insertRows(int row, int count,
+                    const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::removeRows(). This is a placeholder for when
+     * LdapModel beomes writeable and always returns false.
+     */
+    bool removeRows(int row, int count,
+                    const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::removeRows(). The default implementation
+     * does nothing.
+     */
+    void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) Q_DECL_OVERRIDE;
+
+    //
+    // Drag and drop support
+    //
+    /**
+     * Reimplemented from QAbstractItemModel::supportedDropActions(). The default
+     * implementation returns Qt::MoveAction.
+     */
+    Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::mimedata(). This is a placeholder for when
+     * LdapModel beomes writeable and always returns 0.
+     */
+    QMimeData *mimeData(const QModelIndexList &indexes) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::dropMimedata(). This is a placeholder for when
+     * LdapModel beomes writeable and always returns false.
+     */
+    bool dropMimeData(const QMimeData *data, Qt::DropAction action,
+                      int row, int column, const QModelIndex &parent) Q_DECL_OVERRIDE;
+
+    //
+    // Other public utility functions
+    //
+    /**
+     * Checks to see if the item referenced by \p parent has any children of
+     * the type \p type. If the item has not been populated by fetchMore() yet,
+     * then this function returns true.
+     *
+     * \see fetchMore()
+     * \param parent Index to the item to query.
+     * \param type The type of child item to search for.
+     */
+    bool hasChildrenOfType(const QModelIndex &parent, LdapDataType type) const;
+
+public Q_SLOTS:
+    /**
+     * Reimplemented from QAbstractItemModel::revert(). This is a placeholder for when
+     * LdapModel beomes writeable. This implementation does nothing.
+     */
+    void revert() Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::revert(). This is a placeholder for when
+     * LdapModel beomes writeable. This implementation does nothing and returns false.
+     */
+    bool submit() Q_DECL_OVERRIDE;
+
+Q_SIGNALS:
+    /**
+     * The ready() signal is emitted when the model is ready for use by other components.
+     * When the model is first created and a connection is set, the model queries the
+     * LDAP server for its base DN and automatically creates items down to that level.
+     * This requires the event loop to be running. This signal indicates that this process
+     * has completed and the model can now be set onto views or queried directly from code.
+     */
+    void ready();
+
+private:
+    class LdapModelPrivate;
+    LdapModelPrivate *const m_d;
+
+    Q_PRIVATE_SLOT(m_d, void gotSearchResult(KLDAP::LdapSearch *))
+    Q_PRIVATE_SLOT(m_d, void gotSearchData(KLDAP::LdapSearch *, const KLDAP::LdapObject &))
+};
+
+}
+#endif
diff --git a/src/ldapmodel_p.cpp b/src/ldapmodel_p.cpp
new file mode 100644 (file)
index 0000000..ad0bcb9
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapmodel_p.h"
+#include "ldapmodelnode_p.h"
+#include "ldapsearch.h"
+
+#include "ldap_debug.h"
+
+using namespace KLDAP;
+
+LdapModel::LdapModelPrivate::LdapModelPrivate(LdapModel *parent)
+    : m_parent(parent),
+      m_root(new LdapModelDNNode),
+      m_search(new LdapSearch),
+      m_searchResultObjects(),
+      m_baseDN(),
+      m_searchType(NotSearching),
+      m_searchItem(Q_NULLPTR)
+{
+}
+
+LdapModel::LdapModelPrivate::LdapModelPrivate(LdapModel *parent, LdapConnection &connection)
+    : m_parent(parent),
+      m_root(new LdapModelDNNode),
+      m_search(new LdapSearch(connection)),
+      m_searchResultObjects(),
+      m_baseDN(),
+      m_searchType(NotSearching),
+      m_searchItem(Q_NULLPTR)
+{
+}
+
+LdapModel::LdapModelPrivate::~LdapModelPrivate()
+{
+    delete m_root;
+
+    delete m_search;
+}
+
+void LdapModel::LdapModelPrivate::setConnection(LdapConnection &connection)
+{
+    m_search->setConnection(connection);
+}
+
+bool LdapModel::LdapModelPrivate::search(const LdapDN &searchBase,
+        LdapUrl::Scope scope,
+        const QString &filter,
+        const QStringList &attributes,
+        int pagesize)
+{
+    return m_search->search(searchBase, scope, filter, attributes, pagesize);
+}
+
+void LdapModel::LdapModelPrivate::setSearchType(SearchType t, LdapModelDNNode *item)
+{
+    //qCDebug(LDAP_LOG) << "item =" << item;
+    m_searchType = t;
+    m_searchItem = item;
+}
+
+void LdapModel::LdapModelPrivate::recreateRootItem()
+{
+    //qCDebug(LDAP_LOG);
+    delete m_root;
+    m_root = new LdapModelDNNode;
+    //qCDebug(LDAP_LOG) << "&m_root =" << &m_root;
+}
+
+void LdapModel::LdapModelPrivate::createConnections()
+{
+    connect(search(), SIGNAL(result(KLDAP::LdapSearch*)),
+            m_parent, SLOT(gotSearchResult(KLDAP::LdapSearch*)));
+    connect(search(), SIGNAL(data(KLDAP::LdapSearch*,KLDAP::LdapObject)),
+            m_parent, SLOT(gotSearchData(KLDAP::LdapSearch*,KLDAP::LdapObject)));
+}
+
+void LdapModel::LdapModelPrivate::populateRootToBaseDN()
+{
+    //qCDebug(LDAP_LOG);
+
+    if (baseDN().isEmpty()) {
+        // Query the server for the base DN
+        //qCDebug(LDAP_LOG) << "Searching for the baseDN";
+        setSearchType(LdapModelPrivate::NamingContexts, rootNode());
+        search(LdapDN(), LdapUrl::Base, QString(), QStringList() << QStringLiteral("namingContexts"));
+        return;
+    }
+
+    // Start a search for the details of the baseDN object
+    //qCDebug(LDAP_LOG) << "Searching for attributes of the baseDN";
+    searchResults().clear();
+    setSearchType(LdapModelPrivate::BaseDN, rootNode());
+    search(baseDN(), LdapUrl::Base, QString(), QStringList() << QStringLiteral("dn") << QStringLiteral("objectClass"));
+}
+
+void LdapModel::LdapModelPrivate::gotSearchResult(KLDAP::LdapSearch *search)
+{
+    Q_UNUSED(search);
+    qCDebug(LDAP_LOG);
+
+    switch (searchType()) {
+    case LdapModelPrivate::NamingContexts: {
+        // Set the baseDN
+        QString baseDN;
+        if (!searchResults().isEmpty() &&
+                searchResults().at(0).hasAttribute(QStringLiteral("namingContexts"))) {
+            baseDN = QLatin1String(searchResults().at(0).value(QStringLiteral("namingContexts")));
+            //qCDebug(LDAP_LOG) << "Found baseDN =" << baseDN;
+        }
+        setBaseDN(LdapDN(baseDN));
+
+        // Flag that we are no longer searching for the baseDN
+        setSearchType(LdapModelPrivate::NotSearching);
+
+        // Populate the root item
+        populateRootToBaseDN();
+
+        break;
+    }
+    case LdapModelPrivate::BaseDN: {
+        //qCDebug(LDAP_LOG) << "Found details of the baseDN object."
+        //         << "Creating objects down to this level.";
+
+        // Get the baseDN LdapObject
+        LdapObject baseDNObj = searchResults().at(0);
+
+        // How many levels of items do we need to create?
+        int depth = baseDNObj.dn().depth();
+
+        // Create items that represent objects down to the baseDN
+        LdapModelDNNode *parent = rootNode();
+        LdapModelDNNode *item = Q_NULLPTR;
+        for (int i = 0; i < depth; ++i) {
+            QString dn = baseDN().toString(i);
+            qCDebug(LDAP_LOG) << "Creating item for DN :" << dn;
+
+            //LdapObject obj( dn );
+            item = new LdapModelDNNode(parent, LdapDN(dn));
+            parent = item;
+        }
+
+        // Store the search result
+        if (item) {
+            item->setLdapObject(baseDNObj);
+        }
+
+        // Flag that we are no longer searching
+        setSearchType(LdapModelPrivate::NotSearching);
+        //emit( layoutChanged() );
+
+        // Let the world know we are ready for action
+        emit m_parent->ready();
+
+        break;
+    }
+    case LdapModelPrivate::ChildObjects: {
+        //qCDebug(LDAP_LOG) << "Found" << searchResults().size() << "child objects";
+
+        if (searchResults().size() != 0) {
+            // Create an index for the soon-to-be-a-parent item
+            LdapModelDNNode *parentNode = searchItem();
+            int r = parentNode->row();
+            QModelIndex parentIndex = m_parent->createIndex(r, 0, parentNode);
+
+            m_parent->beginInsertRows(parentIndex, 0, searchResults().size());
+            for (int i = 0; i < searchResults().size(); i++) {
+                LdapObject object = searchResults().at(i);
+                LdapModelDNNode *item = new LdapModelDNNode(parentNode, object.dn());
+                item->setLdapObject(object);
+            }
+
+            m_parent->endInsertRows();
+            emit m_parent->layoutChanged();
+        }
+
+        // Flag that we are no longer searching
+        setSearchType(LdapModelPrivate::NotSearching);
+
+        break;
+    }
+    default:
+        break;
+    }
+}
+
+void LdapModel::LdapModelPrivate::gotSearchData(KLDAP::LdapSearch *search,
+        const KLDAP::LdapObject &obj)
+{
+    Q_UNUSED(search);
+    //qCDebug(LDAP_LOG);
+    //qCDebug(LDAP_LOG) << "Object:";
+    //qCDebug(LDAP_LOG) << obj.toString();
+    searchResults().append(obj);
+}
diff --git a/src/ldapmodel_p.h b/src/ldapmodel_p.h
new file mode 100644 (file)
index 0000000..57dc250
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPMODELPRIVATE_H
+#define KLDAP_LDAPMODELPRIVATE_H
+
+#include "ldapconnection.h"
+#include "ldapdn.h"
+#include "ldapmodel.h"
+#include "ldapobject.h"
+
+namespace KLDAP
+{
+
+class LdapModelDNNode;
+class LdapSearch;
+
+/**
+ * @internal
+ */
+class Q_DECL_HIDDEN LdapModel::LdapModelPrivate
+{
+public:
+    enum SearchType {
+        NotSearching = 0,
+        NamingContexts,
+        BaseDN,
+        ChildObjects
+    };
+
+    explicit LdapModelPrivate(LdapModel *parent);
+    explicit LdapModelPrivate(LdapModel *parent, LdapConnection &connection);
+
+    ~LdapModelPrivate();
+
+    void setConnection(LdapConnection &connection);
+
+    bool search(const LdapDN &searchBase,
+                LdapUrl::Scope scope = LdapUrl::Sub,
+                const QString &filter = QString(),
+                const QStringList &attributes = QStringList(),
+                int pagesize = 0);
+
+    LdapModelDNNode *rootNode()
+    {
+        return m_root;
+    }
+    LdapSearch *search()
+    {
+        return m_search;
+    }
+
+    LdapObjects &searchResults()
+    {
+        return m_searchResultObjects;
+    }
+    const LdapObjects &searchResults() const
+    {
+        return m_searchResultObjects;
+    }
+
+    void recreateRootItem();
+
+    void setBaseDN(const LdapDN &baseDN)
+    {
+        m_baseDN = baseDN;
+    }
+    LdapDN &baseDN()
+    {
+        return m_baseDN;
+    }
+    const LdapDN &baseDN() const
+    {
+        return m_baseDN;
+    }
+
+    void setSearchType(SearchType t, LdapModelDNNode *item = Q_NULLPTR);
+
+    SearchType searchType()
+    {
+        return m_searchType;
+    }
+    LdapModelDNNode *searchItem()
+    {
+        return m_searchItem;
+    }
+
+    void createConnections();
+    void populateRootToBaseDN();
+    void gotSearchResult(KLDAP::LdapSearch *search);
+    void gotSearchData(KLDAP::LdapSearch *search, const KLDAP::LdapObject &obj);
+
+private:
+    LdapModel *m_parent;
+    LdapModelDNNode *m_root;
+    LdapSearch *m_search;
+    LdapObjects m_searchResultObjects;
+    LdapDN m_baseDN;
+    SearchType m_searchType;
+    LdapModelDNNode *m_searchItem;
+};
+
+}
+#endif
diff --git a/src/ldapmodelnode_p.cpp b/src/ldapmodelnode_p.cpp
new file mode 100644 (file)
index 0000000..7a4fd25
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapmodelnode_p.h"
+
+#include "ldap_debug.h"
+
+using namespace KLDAP;
+
+LdapModelNode::LdapModelNode(LdapModelDNNode *parent)
+    : m_parent(parent),
+      m_isPopulated(false)
+{
+    if (m_parent) {
+        m_parent->appendChild(this);
+    }
+}
+
+LdapModelNode::~LdapModelNode()
+{
+
+}
+
+LdapModelDNNode *LdapModelNode::parent()
+{
+    return m_parent;
+}
+
+int LdapModelNode::row() const
+{
+    if (m_parent) {
+        return m_parent->children().indexOf(const_cast<LdapModelNode *>(this));
+    }
+    return 0;
+}
+
+//
+// LdapModelDNNode imlpementation
+//
+
+LdapModelDNNode::LdapModelDNNode(LdapModelDNNode *parent,
+                                 const LdapDN &dn)
+    : LdapModelNode(parent),
+      m_childItems(),
+      m_dn(dn)
+{
+    qCDebug(LDAP_LOG) << "Creating DN =" << m_dn.toString();
+}
+
+LdapModelDNNode::~LdapModelDNNode()
+{
+    qDeleteAll(m_childItems);
+}
+
+void LdapModelDNNode::appendChild(LdapModelNode *pItem)
+{
+    m_childItems.append(pItem);
+    setPopulated(true);
+}
+
+LdapModelNode *LdapModelDNNode::child(int row)
+{
+    return m_childItems.value(row);
+}
+
+void LdapModelDNNode::setLdapObject(const LdapObject &object)
+{
+    // Remember whether this item is populated or not
+    bool populated = isPopulated();
+
+    const LdapAttrMap &attrs = object.attributes();
+    /*
+    int attributeCount = 0;
+    for ( LdapAttrMap::ConstIterator it = attrs.begin(); it != attrs.end(); ++it ) {
+      attributeCount += (*it).size();
+    }
+
+    for ( int i = 0; i < attributeCount; i++ )
+    {
+      LdapModelNode* node = new LdapModelAttrNode( this, QString::number( i ) );
+      Q_UNUSED( node );
+    }
+    */
+    LdapAttrMap::ConstIterator end(attrs.constEnd());
+    for (LdapAttrMap::ConstIterator it = attrs.constBegin(); it != end; ++it) {
+        const QString attr = it.key();
+        LdapAttrValue::ConstIterator end2((*it).constEnd());
+        for (LdapAttrValue::ConstIterator it2 = (*it).constBegin(); it2 != end2; ++it2) {
+            LdapModelNode *node = new LdapModelAttrNode(this, attr, *it2);
+            Q_UNUSED(node);
+        }
+    }
+
+    // Reset the populated flag so that we don't stop the model querying for children
+    setPopulated(populated);
+}
+
+//
+// LdapModelAttrNode imlpementation
+//
+
+LdapModelAttrNode::LdapModelAttrNode(LdapModelDNNode *parent,
+                                     const QString &attrName,
+                                     const QByteArray &attrData)
+    : LdapModelNode(parent),
+      m_attrName(attrName),
+      m_attrData(attrData)
+{
+    qCDebug(LDAP_LOG) << "Creating Name =" << m_attrName << " Data =" << m_attrData;
+}
+
+LdapModelAttrNode::~LdapModelAttrNode()
+{
+
+}
diff --git a/src/ldapmodelnode_p.h b/src/ldapmodelnode_p.h
new file mode 100644 (file)
index 0000000..b469fbc
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPMODELNODE_P_H
+#define KLDAP_LDAPMODELNODE_P_H
+
+#include <QByteArray>
+#include <QString>
+#include <QtCore/QList>
+#include <QtCore/QVariant>
+
+#include "ldapdn.h"
+#include "ldapobject.h"
+#include "kldap_export.h"
+
+namespace KLDAP
+{
+
+class LdapModelDNNode;
+
+/**
+ * @internal
+ */
+class LdapModelNode
+{
+public:
+    explicit LdapModelNode(LdapModelDNNode *parent = Q_NULLPTR);
+    virtual ~LdapModelNode();
+
+    enum NodeType {
+        DN,
+        Attr
+    };
+
+    virtual NodeType nodeType() const = 0;
+
+    LdapModelDNNode *parent();
+    int columnCount() const
+    {
+        return 2;
+    }
+    int row() const;
+
+    void setPopulated(bool b)
+    {
+        m_isPopulated = b;
+    }
+    bool isPopulated() const
+    {
+        return m_isPopulated;
+    }
+
+private:
+    LdapModelDNNode *m_parent;
+    bool m_isPopulated;
+};
+
+/**
+ * @internal
+ */
+class LdapModelDNNode : public LdapModelNode
+{
+public:
+    explicit LdapModelDNNode(LdapModelDNNode *parent = Q_NULLPTR,
+                             const LdapDN &dn = LdapDN());
+    ~LdapModelDNNode();
+
+    LdapModelNode::NodeType nodeType() const Q_DECL_OVERRIDE
+    {
+        return LdapModelNode::DN;
+    }
+
+    void appendChild(LdapModelNode *pItem);
+    LdapModelNode *child(int row);
+    int childCount() const
+    {
+        return m_childItems.size();
+    }
+    const QList<LdapModelNode *> &children() const
+    {
+        return m_childItems;
+    }
+
+    const LdapDN &dn() const
+    {
+        return m_dn;
+    }
+
+    /**
+     * Creates child LdapModelAttrNode object to store \p object's attributes
+     * and adds them as children of this node.
+     *
+     * \param The LdapObject to store in this node.
+     */
+    void setLdapObject(const LdapObject &object);
+
+private:
+    QList<LdapModelNode *> m_childItems;
+    LdapDN m_dn;
+};
+
+/**
+ * @internal
+ */
+class LdapModelAttrNode : public LdapModelNode
+{
+public:
+    explicit LdapModelAttrNode(LdapModelDNNode *parent = Q_NULLPTR,
+                               const QString &attrName = QString(),
+                               const QByteArray &attrData = QByteArray());
+    ~LdapModelAttrNode();
+
+    LdapModelNode::NodeType nodeType() const Q_DECL_OVERRIDE
+    {
+        return LdapModelNode::Attr;
+    }
+
+    const QString &attributeName()
+    {
+        return m_attrName;
+    }
+    const QByteArray &attributeData()
+    {
+        return m_attrData;
+    }
+
+private:
+    QString m_attrName;
+    QByteArray m_attrData;
+};
+
+}
+
+#endif
diff --git a/src/ldapobject.cpp b/src/ldapobject.cpp
new file mode 100644 (file)
index 0000000..21f21d2
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapobject.h"
+#include "ldif.h"
+
+#include <QtCore/QSharedData>
+
+using namespace KLDAP;
+
+class LdapObjectPrivate : public QSharedData
+{
+public:
+    LdapObjectPrivate()
+    {
+    }
+
+    LdapObjectPrivate(const LdapObjectPrivate &other)
+        : QSharedData(other)
+    {
+        mDn = other.mDn;
+        mAttrs = other.mAttrs;
+    }
+
+    LdapDN mDn;
+    LdapAttrMap mAttrs;
+};
+
+LdapObject::LdapObject()
+    : d(new LdapObjectPrivate)
+{
+}
+
+LdapObject::LdapObject(const QString &dn)
+    : d(new LdapObjectPrivate)
+{
+    d->mDn = LdapDN(dn);
+}
+
+LdapObject::~LdapObject()
+{
+}
+
+LdapObject::LdapObject(const LdapObject &that)
+    : d(that.d)
+{
+}
+
+LdapObject &LdapObject::operator=(const LdapObject &that)
+{
+    if (this != &that) {
+        d = that.d;
+    }
+
+    return *this;
+}
+
+void LdapObject::setDn(const LdapDN &dn)
+{
+    d->mDn = dn;
+}
+
+void LdapObject::setDn(const QString &dn)
+{
+    d->mDn = LdapDN(dn);
+}
+
+void LdapObject::setAttributes(const LdapAttrMap &attrs)
+{
+    d->mAttrs = attrs;
+}
+
+LdapDN LdapObject::dn() const
+{
+    return d->mDn;
+}
+
+const LdapAttrMap &LdapObject::attributes() const
+{
+    return d->mAttrs;
+}
+
+QString LdapObject::toString() const
+{
+    QString result = QStringLiteral("dn: %1\n").arg(d->mDn.toString());
+    LdapAttrMap::ConstIterator end(d->mAttrs.constEnd());
+    for (LdapAttrMap::ConstIterator it = d->mAttrs.constBegin(); it != end; ++it) {
+        const QString attr = it.key();
+        LdapAttrValue::ConstIterator end2((*it).constEnd());
+        for (LdapAttrValue::ConstIterator it2 = (*it).constBegin(); it2 != end2; ++it2) {
+            result += QString::fromUtf8(Ldif::assembleLine(attr, *it2, 76)) + QLatin1Char('\n');
+        }
+    }
+    return result;
+}
+
+void LdapObject::clear()
+{
+    d->mDn.clear();
+    d->mAttrs.clear();
+}
+
+void LdapObject::setValues(const QString &attributeName, const LdapAttrValue &values)
+{
+    d->mAttrs[ attributeName ] = values;
+}
+
+void LdapObject::addValue(const QString &attributeName, const QByteArray &value)
+{
+    d->mAttrs[ attributeName ].append(value);
+}
+
+LdapAttrValue LdapObject::values(const QString &attributeName) const
+{
+    if (hasAttribute(attributeName)) {
+        return d->mAttrs.value(attributeName);
+    } else {
+        return LdapAttrValue();
+    }
+}
+
+QByteArray LdapObject::value(const QString &attributeName) const
+{
+    if (hasAttribute(attributeName)) {
+        return d->mAttrs.value(attributeName).first();
+    } else {
+        return QByteArray();
+    }
+}
+
+bool LdapObject::hasAttribute(const QString &attributeName) const
+{
+    return d->mAttrs.contains(attributeName);
+}
diff --git a/src/ldapobject.h b/src/ldapobject.h
new file mode 100644 (file)
index 0000000..2e632f9
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPOBJECT_H
+#define KLDAP_LDAPOBJECT_H
+
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QSharedDataPointer>
+#include <QtCore/QString>
+class LdapObjectPrivate;
+
+#include "ldapdn.h"
+#include "kldap_export.h"
+
+namespace KLDAP
+{
+
+typedef QList<QByteArray> LdapAttrValue;
+typedef QMap<QString, LdapAttrValue > LdapAttrMap;
+
+/**
+ * @brief
+ * This class represents an LDAP Object
+*/
+class KLDAP_EXPORT LdapObject
+{
+public:
+    LdapObject();
+    explicit LdapObject(const QString &dn);
+    virtual ~LdapObject();
+
+    LdapObject(const LdapObject &that);
+    LdapObject &operator=(const LdapObject &that);
+
+    /**
+     * Returns the text presentation (LDIF format) of the object.
+     */
+    QString toString() const;
+
+    /**
+     * Clears the name and attributes of the object.
+     */
+    void clear();
+    /**
+     * Sets the Distinguished Name of the object.
+     */
+    void setDn(const LdapDN &dn);
+    /**
+     * Sets the Distinguished Name of the object.
+     */
+    void setDn(const QString &dn);
+    /**
+     * Sets the attributes and attribute values of the object.
+     */
+    void setAttributes(const LdapAttrMap &attrs);
+    /**
+     * Sets the given attribute values. If the given attribute not exists,
+     * then it's created, if exists, it's overwritten.
+     * @param attributeName the attribute name for which to set values
+     * @param values the values of attribute to set
+     */
+    void setValues(const QString &attributeName, const LdapAttrValue &values);
+    /**
+     * Adds the given value to the specified attribute. If the given attribute
+     * not exists, then it's created.
+     * @param attributeName the attribute for which to add a value
+     * @param value the attribute  value to add
+     */
+    void addValue(const QString &attributeName, const QByteArray &value);
+    /**
+     * Return the Distinguished Name of the object.
+     */
+    LdapDN dn() const;
+    /**
+     * Returns the attributes and their values.
+     */
+    const LdapAttrMap &attributes() const;
+    /**
+     * Returns all values of the attribute with the given name.
+     */
+    LdapAttrValue values(const QString &attributeName) const;
+    /**
+     * Returns the first value of the attribute with the given name
+     * or an empty byte array if the attribute does not exists.
+     */
+    QByteArray value(const QString &attributeName) const;
+    /**
+     * Returns true if the given attributethe exists, false otherwise.
+     */
+    bool hasAttribute(const QString &attributeName) const;
+
+private:
+    QSharedDataPointer<LdapObjectPrivate> d;
+};
+
+typedef QVector<LdapObject> LdapObjects;
+}
+
+#endif
diff --git a/src/ldapoperation.cpp b/src/ldapoperation.cpp
new file mode 100644 (file)
index 0000000..e4df81d
--- /dev/null
@@ -0,0 +1,1324 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapoperation.h"
+#include "kldap_config.h"
+
+#include "ldap_debug.h"
+
+#include <QtCore/QTime>
+
+#include <stdlib.h>
+
+//for struct timeval
+#if defined(HAVE_SYS_TIME_H)
+# include <sys/time.h>
+#elif defined(_WIN32)
+# include <winsock2.h>
+#endif
+
+#ifdef SASL2_FOUND
+#include <sasl/sasl.h>
+#endif
+
+#ifdef LDAP_FOUND
+# ifndef HAVE_WINLDAP_H
+#  include <lber.h>
+#  include <ldap.h>
+# else
+#  include <w32-ldap-help.h>
+# endif // HAVE_WINLDAP_H
+#endif // LDAP_FOUND
+
+#include "ldapdefs.h"
+
+using namespace KLDAP;
+
+#ifdef LDAP_FOUND
+static void extractControls(LdapControls &ctrls, LDAPControl **pctrls);
+#endif // LDAP_FOUND
+
+/*
+   Returns the difference between msecs and elapsed. If msecs is -1,
+   however, -1 is returned.
+*/
+static int kldap_timeout_value(int msecs, int elapsed)
+{
+    if (msecs == -1) {
+        return -1;
+    }
+
+    int timeout = msecs - elapsed;
+    return timeout < 0 ? 0 : timeout;
+}
+
+class Q_DECL_HIDDEN LdapOperation::LdapOperationPrivate
+{
+public:
+    LdapOperationPrivate();
+    ~LdapOperationPrivate();
+#ifdef LDAP_FOUND
+    int processResult(int rescode, LDAPMessage *msg);
+    int bind(const QByteArray &creds, SASL_Callback_Proc *saslproc, void *data, bool async);
+#endif
+    LdapControls mClientCtrls, mServerCtrls, mControls;
+    LdapObject mObject;
+    QByteArray mExtOid, mExtData;
+    QByteArray mServerCred;
+    QString mMatchedDn;
+    QList<QByteArray> mReferrals;
+
+    LdapConnection *mConnection;
+};
+
+LdapOperation::LdapOperation()
+    : d(new LdapOperationPrivate)
+{
+    d->mConnection = Q_NULLPTR;
+}
+
+LdapOperation::LdapOperation(LdapConnection &conn)
+    : d(new LdapOperationPrivate)
+{
+    setConnection(conn);
+}
+
+LdapOperation::~LdapOperation()
+{
+    delete d;
+}
+
+void LdapOperation::setConnection(LdapConnection &conn)
+{
+    d->mConnection = &conn;
+}
+
+LdapConnection &LdapOperation::connection()
+{
+    return *d->mConnection;
+}
+
+void LdapOperation::setClientControls(const LdapControls &ctrls)
+{
+    d->mClientCtrls = ctrls;
+}
+
+void LdapOperation::setServerControls(const LdapControls &ctrls)
+{
+    d->mServerCtrls = ctrls;
+}
+
+LdapControls LdapOperation::clientControls() const
+{
+    return d->mClientCtrls;
+}
+
+LdapControls LdapOperation::serverControls() const
+{
+    return d->mServerCtrls;
+}
+
+LdapObject LdapOperation::object() const
+{
+    return d->mObject;
+}
+
+LdapControls LdapOperation::controls() const
+{
+    return d->mControls;
+}
+
+QByteArray LdapOperation::extendedOid() const
+{
+    return d->mExtOid;
+}
+
+QByteArray LdapOperation::extendedData() const
+{
+    return d->mExtData;
+}
+
+QString LdapOperation::matchedDn() const
+{
+    return d->mMatchedDn;
+}
+
+QList<QByteArray> LdapOperation::referrals() const
+{
+    return d->mReferrals;
+}
+
+QByteArray LdapOperation::serverCred() const
+{
+    return d->mServerCred;
+}
+
+LdapOperation::LdapOperationPrivate::LdapOperationPrivate()
+    : mConnection(Q_NULLPTR)
+{
+}
+
+LdapOperation::LdapOperationPrivate::~LdapOperationPrivate()
+{
+}
+
+#ifdef LDAP_FOUND
+
+#ifdef SASL2_FOUND
+static int kldap_sasl_interact(sasl_interact_t *interact, LdapOperation::SASL_Data *data)
+{
+    if (data->proc) {
+        for (; interact->id != SASL_CB_LIST_END; interact++) {
+            switch (interact->id) {
+            case SASL_CB_GETREALM:
+                data->creds.fields |= LdapOperation::SASL_Realm;
+                break;
+            case SASL_CB_AUTHNAME:
+                data->creds.fields |= LdapOperation::SASL_Authname;
+                break;
+            case SASL_CB_PASS:
+                data->creds.fields |= LdapOperation::SASL_Password;
+                break;
+            case SASL_CB_USER:
+                data->creds.fields |= LdapOperation::SASL_Authzid;
+                break;
+            }
+        }
+        int retval;
+        if ((retval = data->proc(data->creds, data->data))) {
+            return retval;
+        }
+    }
+
+    QString value;
+
+    while (interact->id != SASL_CB_LIST_END) {
+        value.clear();
+        switch (interact->id) {
+        case SASL_CB_GETREALM:
+            value = data->creds.realm;
+            qCDebug(LDAP_LOG) << "SASL_REALM=" << value;
+            break;
+        case SASL_CB_AUTHNAME:
+            value = data->creds.authname;
+            qCDebug(LDAP_LOG) << "SASL_AUTHNAME=" << value;
+            break;
+        case SASL_CB_PASS:
+            value = data->creds.password;
+            qCDebug(LDAP_LOG) << "SASL_PASSWD=[hidden]";
+            break;
+        case SASL_CB_USER:
+            value = data->creds.authzid;
+            qCDebug(LDAP_LOG) << "SASL_AUTHZID=" << value;
+            break;
+        }
+        if (value.isEmpty()) {
+            interact->result = Q_NULLPTR;
+            interact->len = 0;
+        } else {
+            interact->result = strdup(value.toUtf8());
+            interact->len = strlen((const char *)interact->result);
+        }
+        interact++;
+    }
+    return KLDAP_SUCCESS;
+}
+#endif
+
+int LdapOperation::LdapOperationPrivate::bind(const QByteArray &creds,
+        SASL_Callback_Proc *saslproc,
+        void *data, bool async)
+{
+    Q_ASSERT(mConnection);
+    LDAP *ld = (LDAP *) mConnection->handle();
+    LdapServer server;
+    server = mConnection->server();
+
+    int ret;
+
+    if (server.auth() == LdapServer::SASL) {
+#if defined( SASL2_FOUND ) && !defined( HAVE_WINLDAP_H )
+        sasl_conn_t *saslconn = (sasl_conn_t *)mConnection->saslHandle();
+        sasl_interact_t *client_interact = Q_NULLPTR;
+        const char *out = Q_NULLPTR;
+        uint outlen;
+        const char *mechusing = Q_NULLPTR;
+        struct berval ccred, *scred;
+        int saslresult;
+        QByteArray sdata = creds;
+
+        QString mech = server.mech();
+        if (mech.isEmpty()) {
+            mech = QStringLiteral("DIGEST-MD5");
+        }
+
+        SASL_Data sasldata;
+        sasldata.proc = saslproc;
+        sasldata.data = data;
+        sasldata.creds.fields = 0;
+        sasldata.creds.realm = server.realm();
+        sasldata.creds.authname = server.user();
+        sasldata.creds.authzid = server.bindDn();
+        sasldata.creds.password = server.password();
+
+        do {
+            if (sdata.isEmpty()) {
+                do {
+                    saslresult = sasl_client_start(saslconn, mech.toLatin1(),
+                                                   &client_interact, &out, &outlen, &mechusing);
+
+                    if (saslresult == SASL_INTERACT) {
+                        if (kldap_sasl_interact(client_interact, &sasldata) != KLDAP_SUCCESS) {
+                            return KLDAP_SASL_ERROR;
+                        }
+                    }
+                    qCDebug(LDAP_LOG) << "sasl_client_start mech: "
+                                      << mechusing << " outlen " << outlen
+                                      << " result: " << saslresult;
+                } while (saslresult == SASL_INTERACT);
+                if (saslresult != SASL_CONTINUE && saslresult != SASL_OK) {
+                    return KLDAP_SASL_ERROR;
+                }
+
+            } else {
+                qCDebug(LDAP_LOG) << "sasl_client_step";
+                do {
+                    saslresult = sasl_client_step(saslconn, sdata.data(), sdata.size(),
+                                                  &client_interact, &out, &outlen);
+                    if (saslresult == SASL_INTERACT) {
+                        if (kldap_sasl_interact(client_interact, &sasldata) != KLDAP_SUCCESS) {
+                            return KLDAP_SASL_ERROR;
+                        }
+                    }
+                } while (saslresult == SASL_INTERACT);
+                qCDebug(LDAP_LOG) << "sasl_client_step result" << saslresult;
+                if (saslresult != SASL_CONTINUE && saslresult != SASL_OK) {
+                    return KLDAP_SASL_ERROR;
+                }
+            }
+
+            ccred.bv_val = (char *) out;
+            ccred.bv_len = outlen;
+
+            if (async) {
+                qCDebug(LDAP_LOG) << "ldap_sasl_bind";
+                int msgid;
+                ret =
+                    ldap_sasl_bind(ld, server.bindDn().toUtf8().data(), mech.toLatin1(),
+                                   &ccred, Q_NULLPTR, Q_NULLPTR, &msgid);
+                if (ret == 0) {
+                    ret = msgid;
+                }
+                qCDebug(LDAP_LOG) << "ldap_sasl_bind msgid" << ret;
+            } else {
+                qCDebug(LDAP_LOG) << "ldap_sasl_bind_s";
+                ret =
+                    ldap_sasl_bind_s(ld, server.bindDn().toUtf8().data(), mech.toLatin1(),
+                                     &ccred, Q_NULLPTR, Q_NULLPTR, &scred);
+                qCDebug(LDAP_LOG) << "ldap_sasl_bind_s ret" << ret;
+                if (scred) {
+                    sdata = QByteArray(scred->bv_val, scred->bv_len);
+                } else {
+                    sdata = QByteArray();
+                }
+            }
+        } while (!async && ret == KLDAP_SASL_BIND_IN_PROGRESS);
+#else
+        qCritical() << "SASL authentication is not available "
+                    << "(re-compile kldap with cyrus-sasl and OpenLDAP development).";
+        return KLDAP_SASL_ERROR;
+#endif
+    } else { //simple auth
+        QByteArray bindname, pass;
+        struct berval ccred;
+        if (server.auth() == LdapServer::Simple) {
+            bindname = server.bindDn().toUtf8();
+            pass = server.password().toUtf8();
+        }
+        ccred.bv_val = pass.data();
+        ccred.bv_len = pass.size();
+        qCDebug(LDAP_LOG) << "binding to server, bindname: " << bindname << " password: *****";
+
+        if (async) {
+            qCDebug(LDAP_LOG) << "ldap_sasl_bind (simple)";
+#ifndef HAVE_WINLDAP_H
+            int msgid = 0;
+            ret = ldap_sasl_bind(ld, bindname.data(), Q_NULLPTR, &ccred, Q_NULLPTR, Q_NULLPTR, &msgid);
+            if (ret == 0) {
+                ret = msgid;
+            }
+#else
+            ret = ldap_simple_bind(ld, bindname.data(), pass.data());
+#endif
+        } else {
+            qCDebug(LDAP_LOG) << "ldap_sasl_bind_s (simple)";
+#ifndef HAVE_WINLDAP_H
+            ret = ldap_sasl_bind_s(ld, bindname.data(), Q_NULLPTR, &ccred, Q_NULLPTR, Q_NULLPTR, Q_NULLPTR);
+#else
+            ret = ldap_simple_bind_s(ld, bindname.data(), pass.data());
+#endif
+        }
+    }
+    return ret;
+}
+
+int LdapOperation::LdapOperationPrivate::processResult(int rescode, LDAPMessage *msg)
+{
+    //qCDebug(LDAP_LOG);
+    int retval;
+    LDAP *ld = (LDAP *) mConnection->handle();
+
+    qCDebug(LDAP_LOG) << "rescode: " << rescode;
+    switch (rescode) {
+    case RES_SEARCH_ENTRY: {
+        //qCDebug(LDAP_LOG) << "Found search entry";
+        mObject.clear();
+        LdapAttrMap attrs;
+        char *name;
+        struct berval **bvals;
+        BerElement     *entry;
+
+        char *dn = ldap_get_dn(ld, msg);
+        mObject.setDn(QString::fromUtf8(dn));
+        ldap_memfree(dn);
+
+        // iterate over the attributes
+        name = ldap_first_attribute(ld, msg, &entry);
+        while (name != Q_NULLPTR) {
+            // print the values
+            bvals = ldap_get_values_len(ld, msg, name);
+            LdapAttrValue values;
+            if (bvals) {
+                for (int i = 0; bvals[i] != Q_NULLPTR; i++) {
+                    char *val = bvals[i]->bv_val;
+                    unsigned long len = bvals[i]->bv_len;
+                    values.append(QByteArray(val, len));
+                }
+                ldap_value_free_len(bvals);
+            }
+            attrs[ QString::fromLatin1(name) ] = values;
+            ldap_memfree(name);
+
+            // next attribute
+            name = ldap_next_attribute(ld, msg, entry);
+        }
+        ber_free(entry, 0);
+        mObject.setAttributes(attrs);
+        break;
+    }
+    case RES_SEARCH_REFERENCE:
+        // Will only get this if following references is disabled. ignore it
+        rescode = 0;
+        break;
+    case RES_EXTENDED: {
+        char *retoid;
+        struct berval *retdata;
+        retval = ldap_parse_extended_result(ld, msg, &retoid, &retdata, 0);
+        if (retval != KLDAP_SUCCESS) {
+            ldap_msgfree(msg);
+            return -1;
+        }
+        mExtOid = retoid ? QByteArray(retoid) : QByteArray();
+        mExtData = retdata ? QByteArray(retdata->bv_val, retdata->bv_len) : QByteArray();
+        ldap_memfree(retoid);
+        ber_bvfree(retdata);
+        break;
+    }
+    case RES_BIND: {
+        struct berval *servercred = Q_NULLPTR;
+#ifndef HAVE_WINLDAP_H
+        // FIXME: Error handling Winldap does not have ldap_parse_sasl_bind_result
+        retval = ldap_parse_sasl_bind_result(ld, msg, &servercred, 0);
+#else
+        retval = KLDAP_SUCCESS;
+#endif
+        if (retval != KLDAP_SUCCESS && retval != KLDAP_SASL_BIND_IN_PROGRESS) {
+            qCDebug(LDAP_LOG) << "RES_BIND error: " << retval;
+            ldap_msgfree(msg);
+            return -1;
+        }
+        qCDebug(LDAP_LOG) << "RES_BIND rescode" << rescode << "retval:" << retval;
+        if (servercred) {
+            mServerCred = QByteArray(servercred->bv_val, servercred->bv_len);
+            ber_bvfree(servercred);
+        } else {
+            mServerCred = QByteArray();
+        }
+        break;
+    }
+    default: {
+        LDAPControl **serverctrls = Q_NULLPTR;
+        char *matcheddn = Q_NULLPTR, *errmsg = Q_NULLPTR;
+        char **referralsp;
+        int errcodep;
+        retval =
+            ldap_parse_result(ld, msg, &errcodep, &matcheddn, &errmsg, &referralsp,
+                              &serverctrls, 0);
+        qCDebug(LDAP_LOG) << "rescode" << rescode << "retval:" << retval
+                          << "matcheddn:" << matcheddn << "errcode:"
+                          << errcodep << "errmsg:" << errmsg;
+        if (retval != KLDAP_SUCCESS) {
+            ldap_msgfree(msg);
+            return -1;
+        }
+        mControls.clear();
+        if (serverctrls) {
+            extractControls(mControls, serverctrls);
+            ldap_controls_free(serverctrls);
+        }
+        mReferrals.clear();
+        if (referralsp) {
+            char **tmp = referralsp;
+            while (*tmp) {
+                mReferrals.append(QByteArray(*tmp));
+                ldap_memfree(*tmp);
+                tmp++;
+            }
+            ldap_memfree((char *) referralsp);
+        }
+        mMatchedDn.clear();
+        if (matcheddn) {
+            mMatchedDn = QString::fromUtf8(matcheddn);
+            ldap_memfree(matcheddn);
+        }
+        if (errmsg) {
+            ldap_memfree(errmsg);
+        }
+    }
+    }
+
+    ldap_msgfree(msg);
+
+    return rescode;
+}
+
+static void addModOp(LDAPMod ***pmods, int mod_type, const QString &attr,
+                     const QByteArray *value = Q_NULLPTR)
+{
+    //  qCDebug(LDAP_LOG) << "type:" << mod_type << "attr:" << attr <<
+    //    "value:" << QString::fromUtf8(value,value.size()) <<
+    //    "size:" << value.size();
+    LDAPMod **mods;
+
+    mods = *pmods;
+
+    uint i = 0;
+
+    if (mods == Q_NULLPTR) {
+        mods = (LDAPMod **)malloc(2 * sizeof(LDAPMod *));
+        mods[ 0 ] = (LDAPMod *)malloc(sizeof(LDAPMod));
+        mods[ 1 ] = Q_NULLPTR;
+        memset(mods[ 0 ], 0, sizeof(LDAPMod));
+    } else {
+        while (mods[ i ] != Q_NULLPTR &&
+                (strcmp(attr.toUtf8(), mods[i]->mod_type) != 0 ||
+                 (mods[ i ]->mod_op & ~LDAP_MOD_BVALUES) != mod_type)) {
+            i++;
+        }
+
+        if (mods[ i ] == Q_NULLPTR) {
+            mods = (LDAPMod **)realloc(mods, (i + 2) * sizeof(LDAPMod *));
+            if (mods == Q_NULLPTR) {
+                qCritical() << "addModOp: realloc";
+                return;
+            }
+            mods[ i + 1 ] = Q_NULLPTR;
+            mods[ i ] = (LDAPMod *) malloc(sizeof(LDAPMod));
+            memset(mods[ i ], 0, sizeof(LDAPMod));
+        }
+    }
+
+    mods[ i ]->mod_op = mod_type | LDAP_MOD_BVALUES;
+    if (mods[ i ]->mod_type == Q_NULLPTR) {
+        mods[ i ]->mod_type = strdup(attr.toUtf8());
+    }
+
+    *pmods = mods;
+
+    if (value == Q_NULLPTR) {
+        return;
+    }
+
+    int vallen = value->size();
+    BerValue *berval;
+    berval = (BerValue *) malloc(sizeof(BerValue));
+    berval -> bv_len = vallen;
+    if (vallen > 0) {
+        berval -> bv_val = (char *) malloc(vallen);
+        memcpy(berval -> bv_val, value->data(), vallen);
+    } else {
+        berval -> bv_val = Q_NULLPTR;
+    }
+
+    if (mods[ i ] -> mod_vals.modv_bvals == Q_NULLPTR) {
+        mods[ i ]->mod_vals.modv_bvals =
+            (BerValue **) malloc(sizeof(BerValue *) * 2);
+        mods[ i ]->mod_vals.modv_bvals[ 0 ] = berval;
+        mods[ i ]->mod_vals.modv_bvals[ 1 ] = Q_NULLPTR;
+//    qCDebug(LDAP_LOG) << "new bervalue struct" << attr << value;
+    } else {
+        uint j = 0;
+        while (mods[ i ]->mod_vals.modv_bvals[ j ] != Q_NULLPTR) {
+            j++;
+        }
+        mods[ i ]->mod_vals.modv_bvals =
+            (BerValue **)realloc(mods[ i ]->mod_vals.modv_bvals,
+                                 (j + 2) * sizeof(BerValue *));
+        if (mods[ i ]->mod_vals.modv_bvals == Q_NULLPTR) {
+            qCritical() << "addModOp: realloc";
+            free(berval);
+            return;
+        }
+        mods[ i ]->mod_vals.modv_bvals[ j ] = berval;
+        mods[ i ]->mod_vals.modv_bvals[ j + 1 ] = Q_NULLPTR;
+        qCDebug(LDAP_LOG) << j << ". new bervalue";
+    }
+}
+
+static void addControlOp(LDAPControl ***pctrls, const QString &oid,
+                         const QByteArray &value, bool critical)
+{
+    LDAPControl **ctrls;
+    LDAPControl *ctrl = (LDAPControl *) malloc(sizeof(LDAPControl));
+
+    ctrls = *pctrls;
+
+    qCDebug(LDAP_LOG) << "oid:'" << oid << "' val: '" << value << "'";
+    int vallen = value.size();
+    ctrl->ldctl_value.bv_len = vallen;
+    if (vallen) {
+        ctrl->ldctl_value.bv_val = (char *) malloc(vallen);
+        memcpy(ctrl->ldctl_value.bv_val, value.data(), vallen);
+    } else {
+        ctrl->ldctl_value.bv_val = Q_NULLPTR;
+    }
+    ctrl->ldctl_iscritical = critical;
+    ctrl->ldctl_oid = strdup(oid.toUtf8());
+
+    uint i = 0;
+
+    if (ctrls == Q_NULLPTR) {
+        ctrls = (LDAPControl **)malloc(2 * sizeof(LDAPControl *));
+        ctrls[ 0 ] = Q_NULLPTR;
+        ctrls[ 1 ] = Q_NULLPTR;
+    } else {
+        while (ctrls[ i ] != Q_NULLPTR) {
+            i++;
+        }
+        ctrls[ i + 1 ] = Q_NULLPTR;
+        ctrls =
+            (LDAPControl **)realloc(ctrls, (i + 2) * sizeof(LDAPControl *));
+    }
+    ctrls[ i ] = ctrl;
+    *pctrls = ctrls;
+}
+
+static void createControls(LDAPControl ***pctrls, const LdapControls &ctrls)
+{
+    for (int i = 0; i < ctrls.count(); ++i) {
+        addControlOp(pctrls, ctrls[i].oid(), ctrls[i].value(), ctrls[i].critical());
+    }
+}
+
+static void extractControls(LdapControls &ctrls, LDAPControl **pctrls)
+{
+    LDAPControl *ctrl;
+    LdapControl control;
+    int i = 0;
+
+    while (pctrls[i]) {
+        ctrl = pctrls[ i ];
+        control.setOid(QString::fromUtf8(ctrl->ldctl_oid));
+        control.setValue(QByteArray(ctrl->ldctl_value.bv_val,
+                                    ctrl->ldctl_value.bv_len));
+        control.setCritical(ctrl->ldctl_iscritical);
+        ctrls.append(control);
+        i++;
+    }
+}
+
+int LdapOperation::bind(const QByteArray &creds, SASL_Callback_Proc *saslproc, void *data)
+{
+    return d->bind(creds, saslproc, data, true);
+}
+
+int LdapOperation::bind_s(SASL_Callback_Proc *saslproc, void *data)
+{
+    return d->bind(QByteArray(), saslproc, data, false);
+}
+
+int LdapOperation::search(const LdapDN &base, LdapUrl::Scope scope,
+                          const QString &filter, const QStringList &attributes)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    char **attrs = Q_NULLPTR;
+    int msgid;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    int count = attributes.count();
+    if (count > 0) {
+        attrs = static_cast<char **>(malloc((count + 1) * sizeof(char *)));
+        for (int i = 0; i < count; i++) {
+            attrs[i] = strdup(attributes.at(i).toUtf8());
+        }
+        attrs[count] = Q_NULLPTR;
+    }
+
+    int lscope = LDAP_SCOPE_BASE;
+    switch (scope) {
+    case LdapUrl::Base:
+        lscope = LDAP_SCOPE_BASE;
+        break;
+    case LdapUrl::One:
+        lscope = LDAP_SCOPE_ONELEVEL;
+        break;
+    case LdapUrl::Sub:
+        lscope = LDAP_SCOPE_SUBTREE;
+        break;
+    }
+
+    qCDebug(LDAP_LOG) << "asyncSearch() base=\"" << base.toString()
+                      << "\" scope=" << (int)scope
+                      << "filter=\"" << filter
+                      << "\" attrs=" << attributes;
+    int retval =
+        ldap_search_ext(ld, base.toString().toUtf8().data(), lscope,
+                        filter.isEmpty() ? QByteArray("objectClass=*").data() :
+                        filter.toUtf8().data(),
+                        attrs, 0, serverctrls, clientctrls, Q_NULLPTR,
+                        d->mConnection->sizeLimit(), &msgid);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+
+    // free the attributes list again
+    if (count > 0) {
+        for (int i = 0; i < count; i++) {
+            free(attrs[i]);
+        }
+        free(attrs);
+    }
+
+    if (retval == 0) {
+        retval = msgid;
+    }
+    return retval;
+}
+
+int LdapOperation::add(const LdapObject &object)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    int msgid;
+    LDAPMod **lmod = Q_NULLPTR;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    for (LdapAttrMap::ConstIterator it = object.attributes().begin();
+            it != object.attributes().end(); ++it) {
+        QString attr = it.key();
+        for (LdapAttrValue::ConstIterator it2 = (*it).begin(); it2 != (*it).end(); ++it2) {
+            addModOp(&lmod, 0, attr, &(*it2));
+        }
+    }
+
+    int retval =
+        ldap_add_ext(ld, object.dn().toString().toUtf8().data(), lmod, serverctrls,
+                     clientctrls, &msgid);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+    ldap_mods_free(lmod, 1);
+    if (retval == 0) {
+        retval = msgid;
+    }
+    return retval;
+}
+
+int LdapOperation::add_s(const LdapObject &object)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    LDAPMod **lmod = Q_NULLPTR;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    for (LdapAttrMap::ConstIterator it = object.attributes().begin();
+            it != object.attributes().end(); ++it) {
+        QString attr = it.key();
+        for (LdapAttrValue::ConstIterator it2 = (*it).begin(); it2 != (*it).end(); ++it2) {
+            addModOp(&lmod, 0, attr, &(*it2));
+        }
+    }
+
+    int retval =
+        ldap_add_ext_s(ld, object.dn().toString().toUtf8().data(), lmod, serverctrls,
+                       clientctrls);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+    ldap_mods_free(lmod, 1);
+    return retval;
+}
+
+int LdapOperation::add(const LdapDN &dn, const ModOps &ops)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    int msgid;
+    LDAPMod **lmod = Q_NULLPTR;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    for (int i = 0; i < ops.count(); ++i) {
+        for (int j = 0; j < ops[i].values.count(); ++j) {
+            addModOp(&lmod, 0, ops[i].attr, &ops[i].values[j]);
+        }
+    }
+
+    int retval =
+        ldap_add_ext(ld, dn.toString().toUtf8().data(), lmod, serverctrls,
+                     clientctrls, &msgid);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+    ldap_mods_free(lmod, 1);
+    if (retval == 0) {
+        retval = msgid;
+    }
+    return retval;
+}
+
+int LdapOperation::add_s(const LdapDN &dn, const ModOps &ops)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    LDAPMod **lmod = Q_NULLPTR;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    for (int i = 0; i < ops.count(); ++i) {
+        for (int j = 0; j < ops[i].values.count(); ++j) {
+            addModOp(&lmod, 0, ops[i].attr, &ops[i].values[j]);
+        }
+    }
+    qCDebug(LDAP_LOG) << dn.toString();
+    int retval =
+        ldap_add_ext_s(ld, dn.toString().toUtf8().data(), lmod, serverctrls,
+                       clientctrls);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+    ldap_mods_free(lmod, 1);
+    return retval;
+}
+
+int LdapOperation::rename(const LdapDN &dn, const QString &newRdn,
+                          const QString &newSuperior, bool deleteold)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    int msgid;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    int retval = ldap_rename(ld, dn.toString().toUtf8().data(), newRdn.toUtf8().data(),
+                             newSuperior.isEmpty() ? (char *) Q_NULLPTR : newSuperior.toUtf8().data(),
+                             deleteold, serverctrls, clientctrls, &msgid);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+
+    if (retval == 0) {
+        retval = msgid;
+    }
+    return retval;
+}
+
+int LdapOperation::rename_s(const LdapDN &dn, const QString &newRdn,
+                            const QString &newSuperior, bool deleteold)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    int retval = ldap_rename_s(ld, dn.toString().toUtf8().data(), newRdn.toUtf8().data(),
+                               newSuperior.isEmpty() ? (char *) Q_NULLPTR : newSuperior.toUtf8().data(),
+                               deleteold, serverctrls, clientctrls);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+
+    return retval;
+}
+
+int LdapOperation::del(const LdapDN &dn)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    int msgid;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    int retval =
+        ldap_delete_ext(ld, dn.toString().toUtf8().data(), serverctrls, clientctrls, &msgid);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+
+    if (retval == 0) {
+        retval = msgid;
+    }
+    return retval;
+}
+
+int LdapOperation::del_s(const LdapDN &dn)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    int retval = ldap_delete_ext_s(ld, dn.toString().toUtf8().data(), serverctrls, clientctrls);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+
+    return retval;
+}
+
+int LdapOperation::modify(const LdapDN &dn, const ModOps &ops)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *)d->mConnection->handle();
+
+    int msgid;
+    LDAPMod **lmod = Q_NULLPTR;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    for (int i = 0; i < ops.count(); ++i) {
+        int mtype = 0;
+        switch (ops[i].type) {
+        case Mod_None:
+            mtype = 0;
+            break;
+        case Mod_Add:
+            mtype = LDAP_MOD_ADD;
+            break;
+        case Mod_Replace:
+            mtype = LDAP_MOD_REPLACE;
+            break;
+        case Mod_Del:
+            mtype = LDAP_MOD_DELETE;
+            break;
+        }
+        addModOp(&lmod, mtype, ops[i].attr, Q_NULLPTR);
+        for (int j = 0; j < ops[i].values.count(); ++j) {
+            addModOp(&lmod, mtype, ops[i].attr, &ops[i].values[j]);
+        }
+    }
+
+    int retval =
+        ldap_modify_ext(ld, dn.toString().toUtf8().data(), lmod, serverctrls, clientctrls, &msgid);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+    ldap_mods_free(lmod, 1);
+    if (retval == 0) {
+        retval = msgid;
+    }
+    return retval;
+}
+
+int LdapOperation::modify_s(const LdapDN &dn, const ModOps &ops)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    LDAPMod **lmod = Q_NULLPTR;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    for (int i = 0; i < ops.count(); ++i) {
+        int mtype = 0;
+        switch (ops[i].type) {
+        case Mod_None:
+            mtype = 0;
+            break;
+        case Mod_Add:
+            mtype = LDAP_MOD_ADD;
+            break;
+        case Mod_Replace:
+            mtype = LDAP_MOD_REPLACE;
+            break;
+        case Mod_Del:
+            mtype = LDAP_MOD_DELETE;
+            break;
+        }
+        addModOp(&lmod, mtype, ops[i].attr, Q_NULLPTR);
+        for (int j = 0; j < ops[i].values.count(); ++j) {
+            addModOp(&lmod, mtype, ops[i].attr, &ops[i].values[j]);
+        }
+    }
+
+    int retval =
+        ldap_modify_ext_s(ld, dn.toString().toUtf8().data(), lmod, serverctrls, clientctrls);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+    ldap_mods_free(lmod, 1);
+    return retval;
+}
+
+int LdapOperation::compare(const LdapDN &dn, const QString &attr, const QByteArray &value)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+    int msgid;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    int vallen = value.size();
+    BerValue *berval;
+    berval = (BerValue *) malloc(sizeof(BerValue));
+    berval -> bv_val = (char *) malloc(vallen);
+    berval -> bv_len = vallen;
+    memcpy(berval -> bv_val, value.data(), vallen);
+
+    int retval = ldap_compare_ext(ld, dn.toString().toUtf8().data(), attr.toUtf8().data(), berval,
+                                  serverctrls, clientctrls, &msgid);
+
+    ber_bvfree(berval);
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+
+    if (retval == 0) {
+        retval = msgid;
+    }
+    return retval;
+}
+
+int LdapOperation::compare_s(const LdapDN &dn, const QString &attr, const QByteArray &value)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    int vallen = value.size();
+    BerValue *berval;
+    berval = (BerValue *) malloc(sizeof(BerValue));
+    berval -> bv_val = (char *) malloc(vallen);
+    berval -> bv_len = vallen;
+    memcpy(berval -> bv_val, value.data(), vallen);
+
+    int retval = ldap_compare_ext_s(ld, dn.toString().toUtf8().data(), attr.toUtf8().data(), berval,
+                                    serverctrls, clientctrls);
+
+    ber_bvfree(berval);
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+
+    return retval;
+}
+
+int LdapOperation::exop(const QString &oid, const QByteArray &data)
+{
+    Q_ASSERT(d->mConnection);
+#if defined(HAVE_LDAP_EXTENDED_OPERATION) && defined(HAVE_LDAP_EXTENDED_OPERATION_PROTOTYPE)
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+    int msgid;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    int vallen = data.size();
+    BerValue *berval;
+    berval = (BerValue *) malloc(sizeof(BerValue));
+    berval -> bv_val = (char *) malloc(vallen);
+    berval -> bv_len = vallen;
+    memcpy(berval -> bv_val, data.data(), vallen);
+
+    int retval = ldap_extended_operation(ld, oid.toUtf8().data(), berval,
+                                         serverctrls, clientctrls, &msgid);
+
+    ber_bvfree(berval);
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+
+    if (retval == 0) {
+        retval = msgid;
+    }
+    return retval;
+#else
+    qCritical() << "Your LDAP client libraries don't support extended operations.";
+    return -1;
+#endif
+}
+
+int LdapOperation::exop_s(const QString &oid, const QByteArray &data)
+{
+#if defined(HAVE_LDAP_EXTENDED_OPERATION) && defined(HAVE_LDAP_EXTENDED_OPERATION_PROTOTYPE)
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+    BerValue *retdata;
+    char *retoid;
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    int vallen = data.size();
+    BerValue *berval;
+    berval = (BerValue *) malloc(sizeof(BerValue));
+    berval -> bv_val = (char *) malloc(vallen);
+    berval -> bv_len = vallen;
+    memcpy(berval -> bv_val, data.data(), vallen);
+
+    int retval = ldap_extended_operation_s(ld, oid.toUtf8().data(), berval,
+                                           serverctrls, clientctrls, &retoid, &retdata);
+
+    ber_bvfree(berval);
+    ber_bvfree(retdata);
+    free(retoid);
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+
+    return retval;
+#else
+    qCritical() << "Your LDAP client libraries don't support extended operations.";
+    return -1;
+#endif
+}
+
+int LdapOperation::abandon(int id)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    LDAPControl **serverctrls = Q_NULLPTR, **clientctrls = Q_NULLPTR;
+    createControls(&serverctrls, d->mServerCtrls);
+    createControls(&serverctrls, d->mClientCtrls);
+
+    int retval = ldap_abandon_ext(ld, id, serverctrls, clientctrls);
+
+    ldap_controls_free(serverctrls);
+    ldap_controls_free(clientctrls);
+
+    return retval;
+}
+
+int LdapOperation::waitForResult(int id, int msecs)
+{
+    Q_ASSERT(d->mConnection);
+    LDAP *ld = (LDAP *) d->mConnection->handle();
+
+    LDAPMessage *msg;
+    int rescode;
+
+    QTime stopWatch;
+    stopWatch.start();
+    int attempt(1);
+    int timeout(0);
+
+    do {
+        // Calculate the timeout value to use and assign it to a timeval structure
+        // see man select (2) for details
+        timeout = kldap_timeout_value(msecs, stopWatch.elapsed());
+        qCDebug(LDAP_LOG) << "(" << id << "," << msecs
+                          << "): Waiting" << timeout
+                          << "msecs for result. Attempt #" << attempt++;
+        struct timeval tv;
+        tv.tv_sec = timeout / 1000;
+        tv.tv_usec = (timeout % 1000) * 1000;
+
+        // Wait for a result
+        rescode = ldap_result(ld, id, 0, timeout < 0 ? Q_NULLPTR : &tv, &msg);
+        if (rescode == -1) {
+            return -1;
+        }
+        // Act on the return code
+        if (rescode != 0) {
+            // Some kind of result is available for processing
+            return d->processResult(rescode, msg);
+        }
+    } while (msecs == -1 || stopWatch.elapsed() < msecs);
+
+    return 0; //timeout
+}
+
+#else
+
+int LdapOperation::bind(const QByteArray &creds, SASL_Callback_Proc *saslproc, void *data)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::bind_s(SASL_Callback_Proc *saslproc, void *data)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::search(const LdapDN &base, LdapUrl::Scope scope,
+                          const QString &filter, const QStringList &attributes)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::add(const LdapObject &object)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::add_s(const LdapObject &object)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::add(const LdapDN &dn, const ModOps &ops)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::add_s(const LdapDN &dn, const ModOps &ops)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::rename(const LdapDN &dn, const QString &newRdn,
+                          const QString &newSuperior, bool deleteold)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::rename_s(const LdapDN &dn, const QString &newRdn,
+                            const QString &newSuperior, bool deleteold)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::del(const LdapDN &dn)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::del_s(const LdapDN &dn)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::modify(const LdapDN &dn, const ModOps &ops)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::modify_s(const LdapDN &dn, const ModOps &ops)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::compare(const LdapDN &dn, const QString &attr, const QByteArray &value)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::exop(const QString &oid, const QByteArray &data)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::compare_s(const LdapDN &dn, const QString &attr, const QByteArray &value)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::exop_s(const QString &oid, const QByteArray &data)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::waitForResult(int id, int msecs)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+int LdapOperation::abandon(int id)
+{
+    qCritical() << "LDAP support not compiled";
+    return -1;
+}
+
+#endif
diff --git a/src/ldapoperation.h b/src/ldapoperation.h
new file mode 100644 (file)
index 0000000..9f4860a
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPOPERATION_H
+#define KLDAP_LDAPOPERATION_H
+
+#include "kldap_export.h"
+#include "ldapconnection.h"
+#include "ldapcontrol.h"
+#include "ldapobject.h"
+#include "ldapdn.h"
+#include "ldapserver.h"
+#include "ldapurl.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QString>
+
+namespace KLDAP
+{
+
+/**
+ * @brief
+ * This class allows sending an ldap operation
+ * (search, rename, modify, delete, compare, exop) to an LDAP server.
+ */
+class KLDAP_EXPORT LdapOperation
+{
+public:
+    typedef enum {
+        Mod_None, Mod_Add, Mod_Replace, Mod_Del
+    } ModType;
+
+    typedef enum {
+        RES_BIND = 0x61,
+        RES_SEARCH_ENTRY = 0x64,
+        RES_SEARCH_REFERENCE = 0x73,
+        RES_SEARCH_RESULT = 0x65,
+        RES_MODIFY = 0x67,
+        RES_ADD = 0x69,
+        RES_DELETE = 0x69,
+        RES_MODDN = 0x6d,
+        RES_COMPARE = 0x6f,
+        RES_EXTENDED = 0x78,
+        RES_EXTENDED_PARTIAL = 0x79
+    } ResultType;
+
+    typedef struct {
+        ModType type;
+        QString attr;
+        QList<QByteArray> values;
+    } ModOp ;
+
+    typedef QVector<ModOp> ModOps;
+
+    enum SASL_Fields {
+        SASL_Authname = 0x1,
+        SASL_Authzid = 0x2,
+        SASL_Realm = 0x4,
+        SASL_Password = 0x8
+    };
+
+    struct SASL_Credentials {
+        int fields;
+        QString authname;
+        QString authzid;
+        QString realm;
+        QString password;
+    };
+
+    typedef int (SASL_Callback_Proc)(SASL_Credentials &cred, void *data);
+
+    struct SASL_Data {
+        SASL_Callback_Proc *proc;
+        void *data;
+        SASL_Credentials creds;
+    };
+
+    LdapOperation();
+    LdapOperation(LdapConnection &conn);
+    virtual ~LdapOperation();
+
+    /**
+     * Sets the connection object. Without living connection object,
+     * LDAP operations are not possible.
+     * @param the connection object to set
+     */
+    void setConnection(LdapConnection &conn);
+    /**
+     * Returns the connection object.
+     */
+    LdapConnection &connection();
+    /**
+     * Sets the client controls which will sent with each operation.
+     */
+    void setClientControls(const LdapControls &ctrls);
+    /**
+     * Sets the server controls which will sent with each operation.
+     */
+    void setServerControls(const LdapControls &ctrls);
+    /**
+     * Returns the client controls (which set by setClientControls()).
+     */
+    LdapControls clientControls() const;
+    /**
+     * Returns the server controls (which set by setServerControls()).
+     */
+    LdapControls serverControls() const;
+
+    /**
+     * Binds to the server which specified in the connection object.
+     * Can do simple or SASL bind. Returns a message id if successful, negative value if not.
+     */
+    int bind(const QByteArray &creds = QByteArray(),
+             SASL_Callback_Proc *saslproc = Q_NULLPTR, void *data = Q_NULLPTR);
+
+    /**
+     * Binds to the server which specified in the connection object.
+     * Can do simple or SASL bind. This is the synchronous version.
+     * Returns KLDAP_SUCCESS id if successful, else an LDAP error code.
+     */
+    int bind_s(SASL_Callback_Proc *saslproc = Q_NULLPTR, void *data = Q_NULLPTR);
+
+    /**
+     * Starts a search operation with the given base DN, scope, filter and
+     * result attributes. Returns a message id if successful, -1 if not.
+     */
+    int search(const LdapDN &base, LdapUrl::Scope scope,
+               const QString &filter, const QStringList &attrs);
+    /**
+     * Starts an addition operation.
+     * Returns a message id if successful, -1 if not.
+     * @param object the additional operation to start
+     */
+    int add(const LdapObject &object);
+    /**
+     * Adds the specified object to the LDAP database.
+     * Returns KLDAP_SUCCESS id if successful, else an LDAP error code.
+     * @param object the object to add to LDAP database
+     */
+    int add_s(const LdapObject &object);
+    /**
+     * Starts an addition operation. This version accepts ModOps not LdapObject.
+     * Returns a message id if successful, -1 if not.
+     * @param dn the LdapDN operation to start
+     * @param ops the ModOps operation to start
+     */
+    int add(const LdapDN &dn, const ModOps &ops);
+    /**
+     * Adds the specified object to the LDAP database. This version accepts ModOps not LdapObject.
+     * This is the synchronous version.
+     * Returns KLDAP_SUCCESS id if successful, else an LDAP error code.
+     * @param dn the LdapDN object to add
+     * @param ops the ModOps object to add
+     */
+    int add_s(const LdapDN &dn, const ModOps &ops);
+    /**
+     * Starts a modrdn operation on given DN, changing its RDN to newRdn,
+     * changing its parent to newSuperior (if it's not empty), and deletes
+     * the old dn if deleteold is true.
+     * Returns a message id if successful, -1 if not.
+     */
+    int rename(const LdapDN &dn, const QString &newRdn,
+               const QString &newSuperior, bool deleteold = true);
+    /**
+     * Performs a modrdn operation on given DN, changing its RDN to newRdn,
+     * changing its parent to newSuperior (if it's not empty), and deletes
+     * the old dn if deleteold is true. This is the synchronous version.
+     * Returns KLDAP_SUCCESS id if successful, else an LDAP error code.
+     */
+    int rename_s(const LdapDN &dn, const QString &newRdn,
+                 const QString &newSuperior, bool deleteold = true);
+    /**
+     * Starts a delete operation on the given DN.
+     * Returns a message id if successful, -1 if not.
+     */
+    int del(const LdapDN &dn);
+    /**
+     * Deletes the given DN. This is the synchronous version.
+     * Returns KLDAP_SUCCESS id if successful, else an LDAP error code.
+     * @param dn the dn to delete
+     */
+    int del_s(const LdapDN &dn);
+    /**
+     * Starts a modify operation on the given DN.
+     * Returns a message id if successful, -1 if not.
+     * @param dn the DN to start modify operation on
+     */
+    int modify(const LdapDN &dn, const ModOps &ops);
+    /**
+     * Performs a modify operation on the given DN.
+     * This is the synchronous version.
+     * Returns KLDAP_SUCCESS id if successful, else an LDAP error code.
+     */
+    int modify_s(const LdapDN &dn, const ModOps &ops);
+    /**
+     * Starts a compare operation on the given DN, compares the specified
+     * attribute with the given value.
+     * Returns a message id if successful, -1 if not.
+     */
+    int compare(const LdapDN &dn, const QString &attr, const QByteArray &value);
+    /**
+     * Performs a compare operation on the given DN, compares the specified
+     * attribute with the given value. This is the synchronous version.
+     * Returns KLDAP_COMPARE_TRUE if the entry contains the attribute value
+     * and KLDAP_COMPARE_FALSE if it does not. Otherwise, some error code
+     * is returned.
+     */
+    int compare_s(const LdapDN &dn, const QString &attr, const QByteArray &value);
+    /**
+     * Starts an extended operation specified with oid and data.
+     * Returns a message id if successful, -1 if not.
+     */
+    int exop(const QString &oid, const QByteArray &data);
+    /**
+     * Performs an extended operation specified with oid and data.
+     * This is the synchronous version.
+     * Returns KLDAP_SUCCESS id if successful, else an LDAP error code.
+     */
+    int exop_s(const QString &oid, const QByteArray &data);
+    /**
+     * Abandons a long-running operation. Requires the message id.
+     */
+    int abandon(int id);
+    /**
+     * Waits for up to \p msecs milliseconds for a result message from the LDAP
+     * server. If \p msecs is -1, then this function will block indefinitely.
+     * If \p msecs is 0, then this function will return immediately, that is it
+     * will perform a poll for a result message.
+     *
+     * Returns the type of the result LDAP message (RES_XXX constants).
+     * -1 if error occurred, 0 if the timeout value elapsed. Note!
+     * Return code -1 means that fetching the message resulted in error,
+     * not the LDAP operation error. Call connection().ldapErrorCode() to
+     * determine if the operation succeeded.
+     */
+    int waitForResult(int id, int msecs = -1);
+    /**
+     * Returns the result object if result() returned RES_SEARCH_ENTRY.
+     */
+    LdapObject object() const;
+    /**
+     * Returns the server controls from the returned ldap message (grabbed
+     * by result()).
+     */
+    LdapControls controls() const;
+    /**
+     * Returns the OID of the extended operation response (result
+     * returned RES_EXTENDED).
+     */
+    QByteArray extendedOid() const;
+    /**
+     * Returns the data from the extended operation response (result
+     * returned RES_EXTENDED).
+     */
+    QByteArray extendedData() const;
+    /**
+     * The server might supply a matched DN string in the message indicating
+     * how much of a name in a request was recognized. This can be grabbed by
+     * matchedDn().
+     */
+    QString matchedDn() const;
+    /**
+     * This function returns the referral strings from the parsed message
+     * (if any).
+     */
+    QList<QByteArray> referrals() const;
+    /**
+     * Returns the server response for a bind request (result
+     * returned RES_BIND).
+     */
+    QByteArray serverCred() const;
+
+private:
+    class LdapOperationPrivate;
+    LdapOperationPrivate *const d;
+
+    Q_DISABLE_COPY(LdapOperation)
+};
+
+}
+
+#endif
diff --git a/src/ldapsearch.cpp b/src/ldapsearch.cpp
new file mode 100644 (file)
index 0000000..f427615
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapsearch.h"
+#include "ldapdn.h"
+#include "ldapdefs.h"
+
+#include <QtCore/QEventLoop>
+#include <QtCore/QTimer>
+
+#include "ldap_debug.h"
+#include <KLocalizedString>
+using namespace KLDAP;
+
+//blocking the GUI for xxx milliseconds
+#define LDAPSEARCH_BLOCKING_TIMEOUT 10
+
+class LdapSearchPrivate
+{
+public:
+    LdapSearchPrivate(LdapSearch *parent)
+        : mParent(parent)
+    {
+    }
+
+    void result();
+    bool connect();
+    void closeConnection();
+    bool startSearch(const LdapDN &base, LdapUrl::Scope scope,
+                     const QString &filter, const QStringList &attributes,
+                     int pagesize, int count);
+
+    LdapSearch *mParent;
+    LdapConnection *mConn;
+    LdapOperation mOp;
+    bool mOwnConnection, mAbandoned;
+    int mId, mPageSize;
+    LdapDN mBase;
+    QString mFilter;
+    QStringList mAttributes;
+    LdapUrl::Scope mScope;
+
+    QString mErrorString;
+    int mError;
+    int mCount, mMaxCount;
+    bool mFinished;
+};
+
+void LdapSearchPrivate::result()
+{
+    if (mAbandoned) {
+        mOp.abandon(mId);
+        return;
+    }
+    int res = mOp.waitForResult(mId, LDAPSEARCH_BLOCKING_TIMEOUT);
+
+    qCDebug(LDAP_LOG) << "LDAP result:" << res;
+
+    if (res != 0 &&
+            (res == -1 ||
+             (mConn->ldapErrorCode() != KLDAP_SUCCESS &&
+              mConn->ldapErrorCode() != KLDAP_SASL_BIND_IN_PROGRESS))) {
+        //error happened, but no timeout
+        mError = mConn->ldapErrorCode();
+        mErrorString = mConn->ldapErrorString();
+        emit mParent->result(mParent);
+        return;
+    }
+
+    //binding
+    if (res == LdapOperation::RES_BIND) {
+
+        QByteArray servercc;
+        servercc = mOp.serverCred();
+
+        qCDebug(LDAP_LOG) << "LdapSearch RES_BIND";
+        if (mConn->ldapErrorCode() == KLDAP_SUCCESS) {   //bind succeeded
+            qCDebug(LDAP_LOG) << "bind succeeded";
+            LdapControls savedctrls = mOp.serverControls();
+            if (mPageSize) {
+                LdapControls ctrls = savedctrls;
+                LdapControl::insert(ctrls, LdapControl::createPageControl(mPageSize));
+                mOp.setServerControls(ctrls);
+            }
+
+            mId = mOp.search(mBase, mScope, mFilter, mAttributes);
+            mOp.setServerControls(savedctrls);
+        } else { //next bind step
+            qCDebug(LDAP_LOG) << "bind next step";
+            mId = mOp.bind(servercc);
+        }
+        if (mId < 0) {
+            if (mId == KLDAP_SASL_ERROR) {
+                mError = mId;
+                mErrorString = mConn->saslErrorString();
+            } else {
+                mError = mConn->ldapErrorCode();
+                mErrorString = mConn->ldapErrorString();
+            }
+            emit mParent->result(mParent);
+            return;
+        }
+        QTimer::singleShot(0, mParent, SLOT(result()));
+        return;
+    }
+
+    //End of entries
+    if (res == LdapOperation::RES_SEARCH_RESULT) {
+        if (mPageSize) {
+            QByteArray cookie;
+            int estsize = -1;
+            const int numberOfControls(mOp.controls().count());
+            for (int i = 0; i < numberOfControls; ++i) {
+                estsize = mOp.controls().at(i).parsePageControl(cookie);
+                if (estsize != -1) {
+                    break;
+                }
+            }
+            qCDebug(LDAP_LOG) << " estimated size:" << estsize;
+            if (estsize != -1 && !cookie.isEmpty()) {
+                LdapControls ctrls, savedctrls;
+                savedctrls = mOp.serverControls();
+                ctrls = savedctrls;
+                LdapControl::insert(ctrls, LdapControl::createPageControl(mPageSize, cookie));
+                mOp.setServerControls(ctrls);
+                mId = mOp.search(mBase, mScope, mFilter, mAttributes);
+                mOp.setServerControls(savedctrls);
+                if (mId == -1) {
+                    mError = mConn->ldapErrorCode();
+                    mErrorString = mConn->ldapErrorString();
+                    emit mParent->result(mParent);
+                    return;
+                }
+                //continue with the next page
+                QTimer::singleShot(0, mParent, SLOT(result()));
+                return;
+            }
+        }
+        mFinished = true;
+        emit mParent->result(mParent);
+        return;
+    }
+
+    //Found an entry
+    if (res == LdapOperation::RES_SEARCH_ENTRY) {
+        emit mParent->data(mParent, mOp.object());
+        mCount++;
+    }
+
+    //If not reached the requested entries, continue
+    if (mMaxCount <= 0 || mCount < mMaxCount) {
+        QTimer::singleShot(0, mParent, SLOT(result()));
+    }
+    //If reached the requested entries, indicate it
+    if (mMaxCount > 0 && mCount == mMaxCount) {
+        qCDebug(LDAP_LOG) << mCount << " entries reached";
+        emit mParent->result(mParent);
+    }
+}
+
+bool LdapSearchPrivate::connect()
+{
+    int ret = mConn->connect();
+    if (ret != KLDAP_SUCCESS) {
+        mError = ret;
+        mErrorString = mConn->connectionError();
+        closeConnection();
+        return false;
+    }
+    return true;
+}
+
+void LdapSearchPrivate::closeConnection()
+{
+    if (mOwnConnection && mConn) {
+        delete mConn;
+        mConn = Q_NULLPTR;
+    }
+}
+
+//This starts the real job
+bool LdapSearchPrivate::startSearch(const LdapDN &base, LdapUrl::Scope scope,
+                                      const QString &filter,
+                                      const QStringList &attributes, int pagesize, int count)
+{
+    qCDebug(LDAP_LOG) << "search: base=" << base.toString() << "scope=" << (int)scope
+                      << "filter=" << filter << "attributes=" << attributes
+                      << "pagesize=" << pagesize;
+    mAbandoned = false;
+    mError = 0;
+    mErrorString.clear();
+    mOp.setConnection(*mConn);
+    mPageSize = pagesize;
+    mBase = base;
+    mScope = scope;
+    mFilter = filter;
+    mAttributes = attributes;
+    mMaxCount = count;
+    mCount = 0;
+    mFinished = false;
+
+    LdapControls savedctrls = mOp.serverControls();
+    if (pagesize) {
+        LdapControls ctrls = savedctrls;
+        mConn->setOption(0x0008, Q_NULLPTR);   // Disable referals or paging won't work
+        LdapControl::insert(ctrls, LdapControl::createPageControl(pagesize));
+        mOp.setServerControls(ctrls);
+    }
+
+    mId = mOp.bind();
+    if (mId < 0) {
+        if (mId == KLDAP_SASL_ERROR) {
+            mError = mId;
+            mErrorString = mConn->saslErrorString();
+        } else {
+            mError = mConn->ldapErrorCode();
+            mErrorString = mConn->ldapErrorString();
+            if (mError == -1 && mErrorString.isEmpty()) {
+                mErrorString = i18n("Cannot access to server. Please reconfigure it.");
+            }
+        }
+        return false;
+    }
+    qCDebug(LDAP_LOG) << "startSearch msg id=" << mId;
+
+    //maybe do this with threads?- need thread-safe client libs!!!
+    QTimer::singleShot(0, mParent, SLOT(result()));
+
+    return true;
+}
+
+///////////////////////////////////////////////
+
+LdapSearch::LdapSearch()
+    : d(new LdapSearchPrivate(this))
+{
+    d->mOwnConnection = true;
+    d->mConn = Q_NULLPTR;
+}
+
+LdapSearch::LdapSearch(LdapConnection &connection)
+    : d(new LdapSearchPrivate(this))
+{
+    d->mOwnConnection = false;
+    d->mConn = &connection;
+}
+
+LdapSearch::~LdapSearch()
+{
+    d->closeConnection();
+    delete d;
+}
+
+void LdapSearch::setConnection(LdapConnection &connection)
+{
+    d->closeConnection();
+    d->mOwnConnection = false;
+    d->mConn = &connection;
+}
+
+void LdapSearch::setClientControls(const LdapControls &ctrls)
+{
+    d->mOp.setClientControls(ctrls);
+}
+
+void LdapSearch::setServerControls(const LdapControls &ctrls)
+{
+    d->mOp.setServerControls(ctrls);
+}
+
+bool LdapSearch::search(const LdapServer &server,
+                        const QStringList &attributes, int count)
+{
+    if (d->mOwnConnection) {
+        d->closeConnection();
+        d->mConn = new LdapConnection(server);
+        if (!d->connect()) {
+            return false;
+        }
+    }
+    return d->startSearch(server.baseDn(), server.scope(), server.filter(),
+                          attributes, server.pageSize(), count);
+}
+
+bool LdapSearch::search(const LdapUrl &url, int count)
+{
+    if (d->mOwnConnection) {
+        d->closeConnection();
+        d->mConn = new LdapConnection(url);
+        if (!d->connect()) {
+            return false;
+        }
+    }
+    bool critical = true;
+    int pagesize = url.extension(QStringLiteral("x-pagesize"), critical).toInt();
+    return d->startSearch(url.dn(), url.scope(), url.filter(),
+                          url.attributes(), pagesize, count);
+}
+
+bool LdapSearch::search(const LdapDN &base, LdapUrl::Scope scope,
+                        const QString &filter, const QStringList &attributes,
+                        int pagesize, int count)
+{
+    Q_ASSERT(!d->mOwnConnection);
+    return d->startSearch(base, scope, filter, attributes, pagesize, count);
+}
+
+void LdapSearch::continueSearch()
+{
+    Q_ASSERT(!d->mFinished);
+    d->mCount = 0;
+    QTimer::singleShot(0, this, SLOT(result()));
+}
+
+bool LdapSearch::isFinished()
+{
+    return d->mFinished;
+}
+
+void LdapSearch::abandon()
+{
+    d->mAbandoned = true;
+}
+
+int LdapSearch::error() const
+{
+    return d->mError;
+}
+
+QString LdapSearch::errorString() const
+{
+    return d->mErrorString;
+}
+
+#include "moc_ldapsearch.cpp"
diff --git a/src/ldapsearch.h b/src/ldapsearch.h
new file mode 100644 (file)
index 0000000..108a384
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPSEARCH_H
+#define KLDAP_LDAPSEARCH_H
+
+#include <QtCore/QByteArray>
+#include <QtCore/QList>
+#include <QtCore/QObject>
+#include <QtCore/QString>
+class LdapSearchPrivate;
+
+#include "kldap_export.h"
+
+#include "ldapconnection.h"
+#include "ldapcontrol.h"
+#include "ldapobject.h"
+#include "ldapoperation.h"
+#include "ldapserver.h"
+#include "ldapurl.h"
+
+namespace KLDAP
+{
+
+/**
+ * @brief
+ * This class starts a search operation on a LDAP server and returns the
+ * search values via a Qt signal.
+ */
+class KLDAP_EXPORT LdapSearch : public QObject
+{
+    Q_OBJECT
+
+public:
+    /**
+     * Constructs an LdapSearch object
+     */
+    LdapSearch();
+
+    /**
+     * Constructs an LdapConnection object with the given connection. If this
+     * form of constructor used, then always this connection will be used
+     * regardless of the LDAP Url or LdapServer object passed to search().
+     * @param connection the connection used to construct LdapConnection object
+     */
+    explicit LdapSearch(LdapConnection &connection);
+
+    virtual ~LdapSearch();
+
+    /**
+     * Sets the connection for this object to use for searches from now
+     * onwards, regardless of the LDAP Url or LdapServer object passed to
+     * search().
+     */
+    void setConnection(LdapConnection &connection);
+
+    /**
+     * Sets the client controls which will sent with each operation.
+     */
+    void setClientControls(const LdapControls &ctrls);
+
+    /**
+     * Sets the server controls which will sent with each operation.
+     */
+    void setServerControls(const LdapControls &ctrls);
+
+    /**
+     * Starts a search operation on the LDAP server @param server,
+     * returning the attributes specified with @param attributes.
+     * @param count means how many entries to list. If it's >0, then result()
+     * will be emitted when the number of entries is reached, but with
+     * isFinished() set to false.
+     */
+    bool search(const LdapServer &server,
+                const QStringList &attributes = QStringList(), int count = 0);
+
+    /**
+     * Starts a search operation on the given LDAP URL.
+     */
+    bool search(const LdapUrl &url, int count = 0);
+
+    /**
+     * Starts a search operation if the LdapConnection object already set
+     * in the constructor.
+     */
+    bool search(const LdapDN &base,
+                LdapUrl::Scope scope = LdapUrl::Sub,
+                const QString &filter = QString(),
+                const QStringList &attributes = QStringList(),
+                int pagesize = 0, int count = 0);
+
+    /**
+     * Continues the search (if you set count to non-zero in search(), and isFinished() is false)
+     */
+    void continueSearch();
+    /**
+     * Returns true if the search is finished else returns false.
+     */
+    bool isFinished();
+    /**
+     * Tries to abandon the search.
+     */
+    void abandon();
+
+    /**
+     * Returns the error code of the search operation (0 if no error).
+     */
+    int error() const;
+
+    /**
+     * Returns the error description of the search operation.
+     */
+    QString errorString() const;
+
+Q_SIGNALS:
+    /**
+     * Emitted for each result object.
+     */
+    void data(KLDAP::LdapSearch *search, const KLDAP::LdapObject &obj);
+
+    /**
+     * Emitted when the searching finished.
+     */
+    void result(KLDAP::LdapSearch *search);
+
+private:
+    LdapSearchPrivate *const d;
+
+    Q_PRIVATE_SLOT(d, void result())
+
+    Q_DISABLE_COPY(LdapSearch)
+};
+
+}
+
+#endif
diff --git a/src/ldapserver.cpp b/src/ldapserver.cpp
new file mode 100644 (file)
index 0000000..5d9764d
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapserver.h"
+
+#include "ldap_debug.h"
+
+using namespace KLDAP;
+
+class Q_DECL_HIDDEN LdapServer::LdapServerPrivate
+{
+public:
+    QString mHost;
+    int mPort;
+    LdapDN mBaseDn;
+    QString mUser;
+    QString mBindDn;
+    QString mRealm;
+    QString mPassword;
+    QString mMech;
+    QString mFilter;
+    int mTimeLimit;
+    int mSizeLimit;
+    int mVersion;
+    int mPageSize;
+    int mTimeout;
+    Security mSecurity;
+    Auth mAuth;
+    LdapUrl::Scope mScope;
+};
+
+LdapServer::LdapServer()
+    : d(new LdapServerPrivate)
+{
+    clear();
+}
+
+LdapServer::LdapServer(const LdapUrl &url)
+    : d(new LdapServerPrivate)
+{
+    clear();
+
+    setUrl(url);
+}
+
+LdapServer::LdapServer(const LdapServer &that)
+    : d(new LdapServerPrivate)
+{
+    *d = *that.d;
+}
+
+LdapServer &LdapServer::operator= (const LdapServer &that)
+{
+    if (this == &that) {
+        return *this;
+    }
+
+    *d = *that.d;
+
+    return *this;
+}
+
+LdapServer::~LdapServer()
+{
+    delete d;
+}
+
+void LdapServer::clear()
+{
+    d->mPort = 389;
+    d->mHost.clear();
+    d->mUser.clear();
+    d->mBindDn.clear();
+    d->mMech.clear();
+    d->mPassword.clear();
+    d->mSecurity = None;
+    d->mAuth = Anonymous;
+    d->mVersion = 3;
+    d->mTimeout = 0;
+    d->mSizeLimit = d->mTimeLimit = d->mPageSize = 0;
+}
+
+QString LdapServer::host() const
+{
+    return d->mHost;
+}
+
+int LdapServer::port() const
+{
+    return d->mPort;
+}
+
+LdapDN LdapServer::baseDn() const
+{
+    return d->mBaseDn;
+}
+
+QString LdapServer::user() const
+{
+    return d->mUser;
+}
+
+QString LdapServer::bindDn() const
+{
+    return d->mBindDn;
+}
+
+QString LdapServer::realm() const
+{
+    return d->mRealm;
+}
+
+QString LdapServer::password() const
+{
+    return d->mPassword;
+}
+
+QString LdapServer::filter() const
+{
+    return d->mFilter;
+}
+
+LdapUrl::Scope LdapServer::scope() const
+{
+    return d->mScope;
+}
+
+int LdapServer::timeLimit() const
+{
+    return d->mTimeLimit;
+}
+
+int LdapServer::sizeLimit() const
+{
+    return d->mSizeLimit;
+}
+
+int LdapServer::pageSize() const
+{
+    return d->mPageSize;
+}
+
+int LdapServer::version() const
+{
+    return d->mVersion;
+}
+
+LdapServer::Security LdapServer::security() const
+{
+    return d->mSecurity;
+}
+
+LdapServer::Auth LdapServer::auth() const
+{
+    return d->mAuth;
+}
+
+QString LdapServer::mech() const
+{
+    return d->mMech;
+}
+
+int LdapServer::timeout() const
+{
+    return d->mTimeout;
+}
+
+void LdapServer::setHost(const QString &host)
+{
+    d->mHost = host;
+}
+
+void LdapServer::setPort(int port)
+{
+    d->mPort = port;
+}
+
+void LdapServer::setBaseDn(const LdapDN &baseDn)
+{
+    d->mBaseDn = baseDn;
+}
+
+void LdapServer::setUser(const QString &user)
+{
+    d->mUser = user;
+}
+
+void LdapServer::setBindDn(const QString &bindDn)
+{
+    d->mBindDn = bindDn;
+}
+
+void LdapServer::setRealm(const QString &realm)
+{
+    d->mRealm = realm;
+}
+
+void LdapServer::setPassword(const QString &password)
+{
+    d->mPassword = password;
+}
+
+void LdapServer::setTimeLimit(int timelimit)
+{
+    d->mTimeLimit = timelimit;
+}
+
+void LdapServer::setSizeLimit(int sizelimit)
+{
+    d->mSizeLimit = sizelimit;
+}
+
+void LdapServer::setPageSize(int pagesize)
+{
+    d->mPageSize = pagesize;
+}
+
+void LdapServer::setFilter(const QString &filter)
+{
+    d->mFilter = filter;
+}
+
+void LdapServer::setScope(LdapUrl::Scope scope)
+{
+    d->mScope = scope;
+}
+
+void LdapServer::setVersion(int version)
+{
+    d->mVersion = version;
+}
+
+void LdapServer::setSecurity(Security security)
+{
+    d->mSecurity = security;
+}
+
+void LdapServer::setAuth(Auth auth)
+{
+    d->mAuth = auth;
+}
+
+void LdapServer::setMech(const QString &mech)
+{
+    d->mMech = mech;
+}
+
+void LdapServer::setTimeout(int timeout)
+{
+    d->mTimeout = timeout;
+}
+
+void LdapServer::setUrl(const LdapUrl &url)
+{
+    bool critical = true;
+
+    d->mHost = url.host();
+    int port = url.port();
+    if (port <= 0) {
+        d->mPort = 389;
+    } else {
+        d->mPort = port;
+    }
+    d->mBaseDn = url.dn();
+    d->mScope = url.scope();
+
+    d->mFilter = url.filter();
+
+    d->mSecurity = None;
+    if (url.scheme() == QLatin1String("ldaps")) {
+        d->mSecurity = SSL;
+    } else if (url.hasExtension(QStringLiteral("x-tls"))) {
+        d->mSecurity = TLS;
+    }
+    qCDebug(LDAP_LOG) << "security:" << d->mSecurity;
+
+    d->mMech.clear();
+    d->mUser.clear();
+    d->mBindDn.clear();
+    if (url.hasExtension(QStringLiteral("x-sasl"))) {
+        d->mAuth = SASL;
+        if (url.hasExtension(QStringLiteral("x-mech"))) {
+            d->mMech = url.extension(QStringLiteral("x-mech"), critical);
+        }
+        if (url.hasExtension(QStringLiteral("x-realm"))) {
+            d->mRealm = url.extension(QStringLiteral("x-realm"), critical);
+        }
+        if (url.hasExtension(QStringLiteral("bindname"))) {
+            d->mBindDn = url.extension(QStringLiteral("bindname"), critical);
+        }
+        d->mUser = url.userName();
+    } else if (url.hasExtension(QStringLiteral("bindname"))) {
+        d->mAuth = Simple;
+        d->mBindDn = url.extension(QStringLiteral("bindname"), critical);
+    } else {
+        QString user = url.userName();
+        if (user.isEmpty()) {
+            d->mAuth = Anonymous;
+        } else {
+            d->mAuth = Simple;
+            d->mBindDn = user;
+        }
+    }
+    d->mPassword = url.password();
+    if (url.hasExtension(QStringLiteral("x-version"))) {
+        d->mVersion = url.extension(QStringLiteral("x-version"), critical).toInt();
+    } else {
+        d->mVersion = 3;
+    }
+
+    if (url.hasExtension(QStringLiteral("x-timeout"))) {
+        d->mTimeout = url.extension(QStringLiteral("x-timeout"), critical).toInt();
+    } else {
+        d->mTimeout = 0;
+    }
+
+    if (url.hasExtension(QStringLiteral("x-timelimit"))) {
+        d->mTimeLimit = url.extension(QStringLiteral("x-timelimit"), critical).toInt();
+    } else {
+        d->mTimeLimit = 0;
+    }
+
+    if (url.hasExtension(QStringLiteral("x-sizelimit"))) {
+        d->mSizeLimit = url.extension(QStringLiteral("x-sizelimit"), critical).toInt();
+    } else {
+        d->mSizeLimit = 0;
+    }
+
+    if (url.hasExtension(QStringLiteral("x-pagesize"))) {
+        d->mPageSize = url.extension(QStringLiteral("x-pagesize"), critical).toInt();
+    } else {
+        d->mPageSize = 0;
+    }
+}
+
+LdapUrl LdapServer::url() const
+{
+    LdapUrl url;
+    url.setScheme(d->mSecurity == SSL ? QStringLiteral("ldaps") : QStringLiteral("ldap"));
+    url.setPort(d->mPort);
+    url.setHost(d->mHost);
+    url.setDn(d->mBaseDn);
+    url.setFilter(d->mFilter);
+    url.setScope(d->mScope);
+    if (d->mAuth == SASL) {
+        url.setUserName(d->mUser);
+        url.setPassword(d->mPassword);
+        url.setExtension(QStringLiteral("bindname"), d->mBindDn, true);
+        url.setExtension(QStringLiteral("x-sasl"), QString());
+        if (!d->mMech.isEmpty()) {
+            url.setExtension(QStringLiteral("x-mech"), d->mMech);
+        }
+        if (!d->mRealm.isEmpty()) {
+            url.setExtension(QStringLiteral("x-realm"), d->mRealm);
+        }
+    } else if (d->mAuth == Simple) {
+        url.setUserName(d->mBindDn);
+        url.setPassword(d->mPassword);
+    }
+    if (d->mVersion == 2) {
+        url.setExtension(QStringLiteral("x-version"), d->mVersion);
+    }
+    if (d->mTimeout) {
+        url.setExtension(QStringLiteral("x-timeout"), d->mTimeout);
+    }
+    if (d->mTimeLimit != 0) {
+        url.setExtension(QStringLiteral("x-timelimit"), d->mTimeLimit);
+    }
+    if (d->mSizeLimit != 0) {
+        url.setExtension(QStringLiteral("x-sizelimit"), d->mSizeLimit);
+    }
+    if (d->mPageSize != 0) {
+        url.setExtension(QStringLiteral("x-pagesize"), d->mPageSize);
+    }
+    if (d->mSecurity == TLS) {
+        url.setExtension(QStringLiteral("x-tls"), 1, true);
+    }
+    return url;
+}
diff --git a/src/ldapserver.h b/src/ldapserver.h
new file mode 100644 (file)
index 0000000..7e75649
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPSERVER_H
+#define KLDAP_LDAPSERVER_H
+
+#include <QtCore/QString>
+
+#include "ldapurl.h"
+#include "ldapdn.h"
+#include "kldap_export.h"
+
+namespace KLDAP
+{
+
+/**
+ * @short A class that contains LDAP server connection settings.
+ *
+ * This class holds various parameters that are needed to connect
+ * to an LDAP server.
+ */
+class KLDAP_EXPORT LdapServer
+{
+public:
+    /**
+     * Creates an empty LDAP server object.
+     */
+    LdapServer();
+
+    /**
+     * Creates a new LDAP server object.
+     *
+     * @param url The LDAP url of the server.
+     */
+    LdapServer(const LdapUrl &url);
+
+    /**
+     * Creates a new LDAP server object from an @p other object.
+     */
+    LdapServer(const LdapServer &other);
+
+    /**
+     * Overwrites the values of the LDAP server object with
+     * the values from an @p other object.
+     */
+    LdapServer &operator=(const LdapServer &other);
+
+    /**
+     * Destroys the LDAP server object.
+     */
+    virtual ~LdapServer();
+
+    /**
+     * Describes the encryption settings that can be used
+     * for the LDAP connection.
+     */
+    typedef enum {
+        None, ///< Do not use any encryption.
+        TLS,  ///< Use TLS encryption.
+        SSL   ///< Use SSL encryption.
+    } Security;
+
+    /**
+     * Describes the authentication method that can be used
+     * for the LDAP connection.
+     */
+    typedef enum {
+        Anonymous,  ///< Do no authentication.
+        Simple,     ///< Authenticate via login and password.
+        SASL        ///< Azthenticate with the SASL framework.
+    } Auth;
+
+    /**
+     * Clears all server settings.
+     */
+    void clear();
+
+    /**
+     * Sets the host of the LDAP connection.
+     */
+    void setHost(const QString &host);
+
+    /**
+     * Returns the host of the LDAP connection.
+     */
+    QString host() const;
+
+    /**
+     * Sets the port of the LDAP connection.
+     * If not port is set, 389 is used as default.
+     * @param port the LDAP port connection to set
+     */
+    void setPort(int port);
+
+    /**
+     * Returns the port of the LDAP connection.
+     */
+    int port() const;
+
+    /**
+     * Sets the @p baseDn of the LDAP connection.
+     */
+    void setBaseDn(const LdapDN &baseDn);
+
+    /**
+     * Returns the baseDn of the LDAP connection.
+     */
+    LdapDN baseDn() const;
+
+    /**
+     * Sets the @p user of the LDAP connection.
+     */
+    void setUser(const QString &user);
+
+    /**
+     * Returns the user of the LDAP connection.
+     */
+    QString user() const;
+
+    /**
+     * Sets the @p bindDn of the LDAP connection.
+     */
+    void setBindDn(const QString &bindDn);
+
+    /**
+     * Returns the bindDn of the LDAP connection.
+     */
+    QString bindDn() const;
+
+    /**
+     * Sets the @p realm of the LDAP connection.
+     */
+    void setRealm(const QString &realm);
+
+    /**
+     * Returns the realm of the LDAP connection.
+     */
+    QString realm() const;
+
+    /**
+     * Sets the @p password of the LDAP connection.
+     */
+    void setPassword(const QString &password);
+
+    /**
+     * Returns the password of the LDAP connection.
+     */
+    QString password() const;
+
+    /**
+     * Sets the protocol @p version of the LDAP connection.
+     * If no version is set, 3 is used as default.
+     * @param version the protocol version to set
+     */
+    void setVersion(int version);
+
+    /**
+     * Returns the protocol version of the LDAP connection.
+     */
+    int version() const;
+
+    /**
+     * Sets the security @p mode of the LDAP connection.
+     * If no security is set, None is used as default.
+     * @param mode the security mode to set
+     */
+    void setSecurity(Security mode);
+
+    /**
+     * Returns the security mode of the LDAP connection.
+     */
+    Security security() const;
+
+    /**
+     * Sets the @p authentication method of the LDAP connection.
+     * If no authentication method is set, Anonymous is used as default.
+     * @param authentication the authentication method to set
+     */
+    void setAuth(Auth authentication);
+
+    /**
+     * Returns the authentication method of the LDAP connection.
+     */
+    Auth auth() const;
+
+    /**
+     * Sets the @p mech of the LDAP connection.
+     */
+    void setMech(const QString &mech);
+
+    /**
+     * Returns the mech of the LDAP connection.
+     */
+    QString mech() const;
+
+    /**
+     * Sets the @p timeout of the LDAP connection.
+     */
+    void setTimeout(int timeout);
+
+    /**
+     * Returns the timeout of the LDAP connection.
+     */
+    int timeout() const;
+
+    /**
+     * Sets the search @p scope of the LDAP connection.
+     */
+    void setScope(LdapUrl::Scope scope);
+
+    /**
+     * Returns the search scope of the LDAP connection.
+     */
+    LdapUrl::Scope scope() const;
+
+    /**
+     * Sets the time @p limit of the LDAP connection.
+     */
+    void setTimeLimit(int limit);
+
+    /**
+     * Returns the time limit of the LDAP connection.
+     */
+    int timeLimit() const;
+
+    /**
+     * Sets the size @p limit of the LDAP connection.
+     */
+    void setSizeLimit(int sizelimit);
+
+    /**
+     * Returns the size limit of the LDAP connection.
+     */
+    int sizeLimit() const;
+
+    /**
+     * Sets the page @p size of the LDAP connection.
+     */
+    void setPageSize(int size);
+
+    /**
+     * Returns the page size of the LDAP connection.
+     */
+    int pageSize() const;
+
+    /**
+     * Sets the @p filter string of the LDAP connection.
+     */
+    void setFilter(const QString &filter);
+
+    /**
+     * Returns the filter string of the LDAP connection.
+     */
+    QString filter() const;
+
+    /**
+     * Sets the server parameters from an RFC2255 compliant LDAP @p url.
+     */
+    void setUrl(const LdapUrl &url);
+
+    /**
+     * Returns the server parameters as an RFC2255 compliant LDAP Url.
+     * The URL extensions which are supported:
+     * Standard: bindname
+     * KLDAP extensions: x-tls, x-version, x-sasl, x-mech, x-realm,
+     * x-sizelimit, x-timelimit, x-pagesize, x-timeout
+     */
+    LdapUrl url() const;
+
+private:
+    class LdapServerPrivate;
+    LdapServerPrivate *const d;
+};
+
+}
+
+#endif
diff --git a/src/ldapstructureproxymodel.cpp b/src/ldapstructureproxymodel.cpp
new file mode 100644 (file)
index 0000000..6a3c485
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapstructureproxymodel.h"
+#include "ldapmodel.h"
+#include "ldapmodelnode_p.h"
+
+#include "ldap_debug.h"
+#include <klocalizedstring.h>
+
+using namespace KLDAP;
+
+class Q_DECL_HIDDEN LdapStructureProxyModel::LdapStructureProxyModelPrivate
+{
+public:
+    LdapStructureProxyModelPrivate();
+
+};
+
+LdapStructureProxyModel::LdapStructureProxyModelPrivate::LdapStructureProxyModelPrivate()
+{
+
+}
+
+LdapStructureProxyModel::LdapStructureProxyModel(QObject *parent)
+    : QSortFilterProxyModel(parent),
+      m_d(new LdapStructureProxyModelPrivate())
+{
+
+}
+
+LdapStructureProxyModel::~LdapStructureProxyModel()
+{
+    delete m_d;
+}
+
+QVariant LdapStructureProxyModel::data(const QModelIndex &index,
+                                       int role) const
+{
+    // Included just in case we decide to do any special presentation of the data
+    // at some other point throughout the 4.x series.
+    return sourceModel()->data(mapToSource(index), role);
+}
+
+bool LdapStructureProxyModel::setData(const QModelIndex &index,
+                                      const QVariant &value,
+                                      int role)
+{
+    Q_UNUSED(index);
+    Q_UNUSED(value);
+    Q_UNUSED(role);
+    return false;
+}
+
+bool LdapStructureProxyModel::filterAcceptsRow(int sourceRow,
+        const QModelIndex &sourceParent) const
+{
+    QModelIndex idx = sourceModel()->index(sourceRow, 0, sourceParent);
+    LdapModelNode::NodeType nodeType =
+        static_cast<LdapModelNode::NodeType>(
+            sourceModel()->data(idx, LdapModel::NodeTypeRole).toUInt());
+    return nodeType == LdapModelNode::DN;
+}
+
+QVariant LdapStructureProxyModel::headerData(int section,
+        Qt::Orientation orientation,
+        int role) const
+{
+    Q_UNUSED(section);
+    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+        return i18n("Distinguished Name");
+    }
+
+    return QVariant();
+}
+
+int LdapStructureProxyModel::columnCount(const QModelIndex &/*parent*/) const
+{
+    // No need for more than one column just to show the structure
+    return 1;
+}
+
+Qt::ItemFlags LdapStructureProxyModel::flags(const QModelIndex &index) const
+{
+    // Included so as not to break BC in case we wish to use this later in 4.x
+    return sourceModel()->flags(mapToSource(index));
+}
+
+bool LdapStructureProxyModel::hasChildren(const QModelIndex &parent) const
+{
+    // We need to handle this carefully bacause of the filtering out of attributes
+    // and the lazy population approach.
+    LdapModel *model = static_cast<LdapModel *>(sourceModel());
+    return model->hasChildrenOfType(mapToSource(parent), LdapModel::DistinguishedName);
+}
+
+QModelIndex LdapStructureProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
+{
+    return QSortFilterProxyModel::mapFromSource(sourceIndex);
+}
+
+QModelIndex LdapStructureProxyModel::mapToSource(const QModelIndex &proxyIndex) const
+{
+    return QSortFilterProxyModel::mapToSource(proxyIndex);
+}
+
+bool LdapStructureProxyModel::insertRows(int row, int count,
+        const QModelIndex &parent)
+{
+    Q_UNUSED(row);
+    Q_UNUSED(count);
+    Q_UNUSED(parent);
+    return false;
+}
+
+bool LdapStructureProxyModel::removeRows(int row, int count,
+        const QModelIndex &parent)
+{
+    Q_UNUSED(row);
+    Q_UNUSED(count);
+    Q_UNUSED(parent);
+    return false;
+}
+
+void LdapStructureProxyModel::sort(int column, Qt::SortOrder order)
+{
+    Q_UNUSED(column);
+    Q_UNUSED(order);
+}
+
+Qt::DropActions LdapStructureProxyModel::supportedDropActions() const
+{
+    return Qt::MoveAction;
+}
+
+QMimeData *LdapStructureProxyModel::mimeData(const QModelIndexList &indexes) const
+{
+    Q_UNUSED(indexes);
+    return Q_NULLPTR;
+}
+
+bool LdapStructureProxyModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
+        int row, int column, const QModelIndex &parent)
+{
+    /** \todo Implement drag and drop for LdapModel */
+    Q_UNUSED(data);
+    Q_UNUSED(action);
+    Q_UNUSED(row);
+    Q_UNUSED(column);
+    Q_UNUSED(parent);
+    return false;
+}
+
diff --git a/src/ldapstructureproxymodel.h b/src/ldapstructureproxymodel.h
new file mode 100644 (file)
index 0000000..10b0b88
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2006 Sean Harmer <sh@theharmers.co.uk>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPSTRUCTUREPROXYMODEL_H
+#define KLDAP_LDAPSTRUCTUREPROXYMODEL_H
+
+#include <QSortFilterProxyModel>
+
+#include "kldap_export.h"
+
+namespace KLDAP
+{
+
+class KLDAP_EXPORT LdapStructureProxyModel : public QSortFilterProxyModel
+{
+    Q_OBJECT
+public:
+    explicit LdapStructureProxyModel(QObject *parent = Q_NULLPTR);
+    ~LdapStructureProxyModel();
+
+    QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::setData(). This is a placeholder for when
+     * LdapStructureProxyModel beomes writeable and always returns false.
+     */
+    bool setData(const QModelIndex &index,
+                 const QVariant &value,
+                 int role = Qt::EditRole) Q_DECL_OVERRIDE;
+    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE;
+    QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE;
+    int columnCount(const QModelIndex &parent) const Q_DECL_OVERRIDE;
+    Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
+    bool hasChildren(const QModelIndex &parent) const Q_DECL_OVERRIDE;
+
+    QModelIndex mapFromSource(const QModelIndex &sourceIndex) const Q_DECL_OVERRIDE;
+    QModelIndex mapToSource(const QModelIndex &proxyIndex) const Q_DECL_OVERRIDE;
+
+    /**
+     * Reimplemented from QAbstractItemModel::insertRows(). This is a placeholder for when
+     * LdapStructureProxyModel beomes writeable and always returns false.
+     */
+    bool insertRows(int row, int count,
+                    const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::removeRows(). This is a placeholder for when
+     * LdapStructureProxyModel beomes writeable and always returns false.
+     */
+    bool removeRows(int row, int count,
+                    const QModelIndex &parent = QModelIndex()) Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::removeRows(). The default implementation
+     * does nothing.
+     */
+    void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) Q_DECL_OVERRIDE;
+    //
+    // Drag and drop support
+    //
+    /**
+     * Reimplemented from QAbstractItemModel::supportedDropActions(). The default
+     * implementation returns Qt::MoveAction.
+     */
+    Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::mimedata(). This is a placeholder for when
+     * LdapStructureProxyModel beomes writeable and always returns 0.
+     */
+    QMimeData *mimeData(const QModelIndexList &indexes) const Q_DECL_OVERRIDE;
+    /**
+     * Reimplemented from QAbstractItemModel::dropMimedata(). This is a placeholder for when
+     * LdapStructureProxyModel beomes writeable and always returns false.
+     */
+    bool dropMimeData(const QMimeData *data, Qt::DropAction action,
+                      int row, int column, const QModelIndex &parent) Q_DECL_OVERRIDE;
+
+private:
+    class LdapStructureProxyModelPrivate;
+    LdapStructureProxyModelPrivate *const m_d;
+};
+
+}
+#endif
diff --git a/src/ldapurl.cpp b/src/ldapurl.cpp
new file mode 100644 (file)
index 0000000..cc4df65
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldapurl.h"
+
+#include "ldap_debug.h"
+
+#include <QtCore/QStringList>
+
+using namespace KLDAP;
+
+class Q_DECL_HIDDEN LdapUrl::LdapUrlPrivate
+{
+public:
+    LdapUrlPrivate()
+        : m_scope(Base)
+    {
+    }
+
+    QMap<QString, Extension> m_extensions;
+    QStringList m_attributes;
+    Scope m_scope;
+    QString m_filter;
+};
+
+LdapUrl::LdapUrl()
+    : d(new LdapUrlPrivate)
+{
+}
+
+LdapUrl::LdapUrl(const QUrl &_url)
+    : QUrl(_url), d(new LdapUrlPrivate)
+{
+    QString tmp = path();
+    if (tmp.startsWith(QLatin1Char('/'))) {
+        tmp = tmp.mid(1);
+    }
+    setPath(tmp);
+    parseQuery();
+}
+
+LdapUrl::LdapUrl(const LdapUrl &that)
+    : QUrl(that), d(new LdapUrlPrivate)
+{
+    *d = *that.d;
+}
+
+LdapUrl &LdapUrl::operator=(const LdapUrl &that)
+{
+    if (this == &that) {
+        return *this;
+    }
+
+    QUrl::operator=(that);
+    *d = *that.d;
+
+    return *this;
+}
+
+LdapUrl::~LdapUrl()
+{
+    delete d;
+}
+
+void LdapUrl::setDn(const LdapDN &dn)
+{
+    QString tmp = dn.toString();
+    if (tmp.startsWith(QLatin1Char('/'))) {
+        setPath(tmp);
+    } else {
+        setPath(QLatin1Char('/')  + tmp);
+    }
+}
+
+LdapDN LdapUrl::dn() const
+{
+    QString tmp = path();
+    if (tmp.startsWith(QLatin1Char('/'))) {
+        tmp = tmp.mid(1);
+    }
+    LdapDN tmpDN(tmp);
+    return tmpDN;
+}
+
+QStringList LdapUrl::attributes() const
+{
+    return d->m_attributes;
+}
+
+void LdapUrl::setAttributes(const QStringList &attributes)
+{
+    d->m_attributes = attributes;
+    updateQuery();
+}
+
+LdapUrl::Scope LdapUrl::scope() const
+{
+    return d->m_scope;
+}
+
+void LdapUrl::setScope(Scope scope)
+{
+    d->m_scope = scope;
+    updateQuery();
+}
+
+QString LdapUrl::filter() const
+{
+    return d->m_filter;
+}
+
+void LdapUrl::setFilter(const QString &filter)
+{
+    d->m_filter = filter;
+    updateQuery();
+}
+
+bool LdapUrl::hasExtension(const QString &key) const
+{
+    return d->m_extensions.contains(key);
+}
+
+LdapUrl::Extension LdapUrl::extension(const QString &key) const
+{
+    QMap<QString, Extension>::const_iterator it;
+
+    it = d->m_extensions.constFind(key);
+    if (it != d->m_extensions.constEnd()) {
+        return (*it);
+    } else {
+        Extension ext;
+        ext.value = QLatin1String("");
+        ext.critical = false;
+        return ext;
+    }
+}
+
+QString LdapUrl::extension(const QString &key, bool &critical) const
+{
+    Extension ext;
+
+    ext = extension(key);
+    critical = ext.critical;
+    return ext.value;
+}
+
+void LdapUrl::setExtension(const QString &key, const LdapUrl::Extension &ext)
+{
+    d->m_extensions[ key ] = ext;
+    updateQuery();
+}
+
+void LdapUrl::setExtension(const QString &key, const QString &value, bool critical)
+{
+    Extension ext;
+    ext.value = value;
+    ext.critical = critical;
+    setExtension(key, ext);
+}
+
+void LdapUrl::setExtension(const QString &key, int value, bool critical)
+{
+    Extension ext;
+    ext.value = QString::number(value);
+    ext.critical = critical;
+    setExtension(key, ext);
+}
+
+void LdapUrl::removeExtension(const QString &key)
+{
+    d->m_extensions.remove(key);
+    updateQuery();
+}
+
+void LdapUrl::updateQuery()
+{
+    QMap<QString, Extension>::const_iterator it;
+    QString q(QLatin1Char('?'));
+
+    // set the attributes to query
+    if (!d->m_attributes.isEmpty()) {
+        q += d->m_attributes.join(QStringLiteral(","));
+    }
+
+    // set the scope
+    q += QLatin1Char('?');
+    switch (d->m_scope) {
+    case Sub:
+        q += QStringLiteral("sub");
+        break;
+    case One:
+        q += QStringLiteral("one");
+        break;
+    case Base:
+        q += QStringLiteral("base");
+        break;
+    }
+
+    // set the filter
+    q += QLatin1Char('?');
+    if (d->m_filter != QLatin1String("(objectClass=*)") && !d->m_filter.isEmpty()) {
+        q += QLatin1String(toPercentEncoding(d->m_filter));
+    }
+
+    // set the extensions
+    q += QLatin1Char('?');
+    for (it = d->m_extensions.constBegin(); it != d->m_extensions.constEnd(); ++it) {
+        if (it.value().critical) {
+            q += QLatin1Char('!');
+        }
+        q += it.key();
+        if (!it.value().value.isEmpty()) {
+            q += QLatin1Char('=') + QLatin1String(toPercentEncoding(it.value().value));
+        }
+        q += QLatin1Char(',');
+    }
+    while (q.endsWith(QLatin1Char('?')) || q.endsWith(QLatin1Char(','))) {
+        q.remove(q.length() - 1, 1);
+    }
+
+    setQuery(q);
+    qCDebug(LDAP_LOG) << "LDAP URL updateQuery():" << toDisplayString();
+}
+
+void LdapUrl::parseQuery()
+{
+    Extension ext;
+    QStringList extensions;
+    QString q = query();
+    // remove first ?
+    if (q.startsWith(QLatin1Char('?'))) {
+        q.remove(0, 1);
+    }
+
+    // split into a list
+    QStringList url_items = q.split(QLatin1Char('?'));
+
+    d->m_attributes.clear();
+    d->m_scope = Base;
+    d->m_filter = QStringLiteral("(objectClass=*)");
+    d->m_extensions.clear();
+
+    int i = 0;
+    QStringList::const_iterator end(url_items.constEnd());
+    for (QStringList::const_iterator it = url_items.constBegin();
+            it != end; ++it, i++) {
+        switch (i) {
+        case 0:
+            d->m_attributes = (*it).split(QLatin1Char(','), QString::SkipEmptyParts);
+            break;
+        case 1:
+            if ((*it) == QLatin1String("sub")) {
+                d->m_scope = Sub;
+            } else if ((*it) == QLatin1String("one")) {
+                d->m_scope = One;
+            }
+            break;
+        case 2:
+            d->m_filter = fromPercentEncoding((*it).toLatin1());
+            break;
+        case 3:
+            extensions = (*it).split(QLatin1Char(','), QString::SkipEmptyParts);
+            break;
+        }
+    }
+
+    QString name, value;
+    QStringList::const_iterator end2(extensions.constEnd());
+    for (QStringList::const_iterator it = extensions.constBegin();
+            it != end2; ++it) {
+        ext.critical = false;
+        name = fromPercentEncoding((*it).section(QLatin1Char('='), 0, 0).toLatin1()).toLower();
+        value = fromPercentEncoding((*it).section(QLatin1Char('='), 1).toLatin1());
+        if (name.startsWith(QLatin1Char('!'))) {
+            ext.critical = true;
+            name.remove(0, 1);
+        }
+        qCDebug(LDAP_LOG) << "LdapUrl extensions name=" << name << "value:" << value;
+        ext.value = value.replace(QLatin1String("%2"), QLatin1String(","));
+        setExtension(name, ext);
+    }
+}
diff --git a/src/ldapurl.h b/src/ldapurl.h
new file mode 100644 (file)
index 0000000..e3a1565
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+    This file is part of libkldap.
+    Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General  Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDAPURL_H
+#define KLDAP_LDAPURL_H
+
+#include <QtCore/QMap>
+#include <QtCore/QStringList>
+
+#include <QUrl>
+
+#include "ldapdn.h"
+#include "kldap_export.h"
+
+namespace KLDAP
+{
+
+/**
+ * @short A special url class for LDAP.
+ *
+ * LdapUrl implements an RFC 2255 compliant LDAP Url parser, with minimal
+ * differences. LDAP Urls implemented by this class has the following format:
+ * ldap[s]://[user[:password]@]hostname[:port]["/" [dn ["?" [attributes]
+ * ["?" [scope] ["?" [filter] ["?" extensions]]]]]]
+ */
+class KLDAP_EXPORT LdapUrl : public QUrl
+{
+public:
+
+    /**
+     * A class holding the extension name and state whether
+     * the extension is critical.
+     */
+    typedef struct {
+        QString value;
+        bool critical;
+    } Extension;
+
+    /**
+     * Describes the scope of the LDAP url.
+     */
+    typedef enum {
+        Base,  ///< Only the same level as the url.
+        One,   ///< The level of the url and the one below.
+        Sub    ///< All levels below the url's level.
+    } Scope;
+
+    /**
+     * Constructs an empty LDAP url.
+     */
+    LdapUrl();
+
+    /**
+     * Constructs a LDAP url from a KUrl @p url.
+     */
+    explicit LdapUrl(const QUrl &url);
+
+    /**
+     * Constructs a LDAP url from an other url.
+     */
+    LdapUrl(const LdapUrl &other);
+
+    /**
+     * Overwrites the values of the LDAP url with values
+     * from an @p other url.
+     */
+    LdapUrl &operator=(const LdapUrl &other);
+
+    /**
+     * Destroys the LDAP url.
+     */
+    virtual ~LdapUrl();
+
+    /**
+     * Sets the @p dn part of the LDAP url.
+     */
+    void setDn(const LdapDN &dn);
+
+    /**
+     * Returns the dn part of the LDAP url.
+     * This is equal to path() with the slash removed from the beginning.
+     */
+    LdapDN dn() const;
+
+    /**
+     * Sets the @p attributes part of the LDAP url.
+     */
+    void setAttributes(const QStringList &attributes);
+
+    /**
+     * Returns the attributes part of the LDAP url.
+     */
+    QStringList attributes() const;
+
+    /**
+     * Sets the scope part of the LDAP url.
+     */
+    void setScope(Scope scope);
+
+    /**
+     * Returns the scope part of the LDAP url.
+     */
+    Scope scope() const;
+
+    /**
+     * Sets the filter part of the LDAP url.
+     */
+    void setFilter(const QString &filter);
+
+    /**
+     * Returns the filter part of the LDAP url.
+     */
+    QString filter() const;
+
+    /**
+     * Returns whether the specified @p extension exists in the LDAP url.
+     */
+    bool hasExtension(const QString &extension) const;
+
+    /**
+     * Returns the specified @p extension.
+     */
+    Extension extension(const QString &extension) const;
+
+    /**
+     * Returns the specified @p extension.
+     */
+    QString extension(const QString &extension, bool &critical) const;
+
+    /**
+     * Sets the specified extension @p key with the value and criticality in @p extension.
+     */
+    void setExtension(const QString &key, const Extension &extension);
+
+    /**
+     * Sets the specified extension @p key with the @p value and criticality specified.
+     */
+    void setExtension(const QString &key, const QString &value, bool critical = false);
+
+    /**
+     * Sets the specified extension @p key with the @p value and criticality specified.
+     */
+    void setExtension(const QString &key, int value, bool critical = false);
+
+    /**
+     * Removes the specified @p extension.
+     */
+    void removeExtension(const QString &extension);
+
+    /**
+     * Updates the query component from the attributes, scope, filter and extensions.
+     */
+    void updateQuery();
+
+    /**
+     * Parses the query argument of the URL and makes it available via the
+     * attributes(), extension(), filter() and scope() methods
+     */
+    void parseQuery();
+
+private:
+    class LdapUrlPrivate;
+    LdapUrlPrivate *const d;
+};
+
+}
+
+#endif
diff --git a/src/ldif.cpp b/src/ldif.cpp
new file mode 100644 (file)
index 0000000..393ffb8
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#include "ldif.h"
+
+#include "ldap_debug.h"
+
+using namespace KLDAP;
+
+class Q_DECL_HIDDEN Ldif::LdifPrivate
+{
+public:
+    int mModType;
+    bool mDelOldRdn, mUrl;
+    LdapDN mDn;
+    QString mAttr, mNewRdn, mNewSuperior, mOid;
+    QByteArray mLdif, mValue;
+    EntryType mEntryType;
+
+    bool mIsNewLine, mIsComment, mCritical;
+    ParseValue mLastParseValue;
+    uint mPos, mLineNumber;
+    QByteArray mLine;
+};
+
+Ldif::Ldif() : d(new LdifPrivate)
+{
+    startParsing();
+}
+
+Ldif::Ldif(const Ldif &that) : d(new LdifPrivate)
+{
+    *d = *that.d;
+
+    startParsing();
+}
+
+Ldif &Ldif::operator=(const Ldif &that)
+{
+    if (this == &that) {
+        return *this;
+    }
+
+    *d = *that.d;
+
+    return *this;
+}
+
+Ldif::~Ldif()
+{
+    delete d;
+}
+
+QByteArray Ldif::assembleLine(const QString &fieldname,
+                              const QByteArray &value,
+                              uint linelen, bool url)
+{
+    bool safe = false;
+    bool isDn;
+    QByteArray result;
+
+    if (url) {
+        result = fieldname.toUtf8() + ":< " + value;
+    } else {
+        isDn = fieldname.toLower() == QLatin1String("dn");
+        //SAFE-INIT-CHAR
+        if (value.size() > 0 && value[0] > 0 && value[0] != '\n' &&
+                value[0] != '\r' && value[0] != ':' && value[0] != '<') {
+            safe = true;
+        }
+
+        //SAFE-CHAR
+        if (safe) {
+            for (int i = 1; i < value.size(); i++) {
+                //allow utf-8 in Distinguished Names
+                if ((isDn && value[i] == 0) ||
+                        (!isDn && value[i] <= 0) ||
+                        value[i] == '\r' || value[i] == '\n') {
+                    safe = false;
+                    break;
+                }
+            }
+        }
+
+        if (value.size() == 0) {
+            safe = true;
+        }
+
+        if (safe) {
+            result = fieldname.toUtf8() + ": " + value;
+        } else {
+            result = fieldname.toUtf8() + ":: " + value.toBase64();
+        }
+
+        if (linelen > 0) {
+            int i = (uint)(fieldname.length() + 2) > linelen ? fieldname.length() + 2 : linelen;
+            while (i < result.length()) {
+                result.insert(i, "\n ");
+                i += linelen + 2;
+            }
+        }
+    }
+    return result;
+}
+
+QByteArray Ldif::assembleLine(const QString &fieldname, const QString &value,
+                              uint linelen, bool url)
+{
+    return assembleLine(fieldname, value.toUtf8(), linelen, url);
+}
+
+bool Ldif::splitLine(const QByteArray &line, QString &fieldname, QByteArray &value)
+{
+    int position;
+    QByteArray tmp;
+    int linelen;
+
+//  qCDebug(LDAP_LOG) << "line:" << QString::fromUtf8(line);
+
+    position = line.indexOf(":");
+    if (position == -1) {
+        // strange: we did not find a fieldname
+        fieldname = QLatin1String("");
+        value = line.trimmed();
+//    qCDebug(LDAP_LOG) << "value :" << value[0];
+        return false;
+    }
+
+    linelen = line.size();
+    fieldname = QString::fromUtf8(line.left(position).trimmed());
+
+    if (linelen > (position + 1) && line[ position + 1 ] == ':') {
+        // String is BASE64 encoded -> decode it now.
+        if (linelen <= (position + 3)) {
+            value.resize(0);
+            return false;
+        }
+        value = QByteArray::fromBase64(line.mid(position + 3));
+        return false;
+    }
+
+    if (linelen > (position + 1) && line[ position + 1 ] == '<') {
+        // String is an URL.
+        if (linelen <= (position + 3)) {
+            value.resize(0);
+            return false;
+        }
+        value = QByteArray::fromBase64(line.mid(position + 3));
+        return true;
+    }
+
+    if (linelen <= (position + 2)) {
+        value.resize(0);
+        return false;
+    }
+    value = line.mid(position + 2);
+    return false;
+}
+
+bool Ldif::splitControl(const QByteArray &line, QString &oid, bool &critical,
+                        QByteArray &value)
+{
+    QString tmp;
+    critical = false;
+    bool url = splitLine(line, tmp, value);
+
+    qCDebug(LDAP_LOG) << "value:" << QString::fromUtf8(value);
+    if (tmp.isEmpty()) {
+        tmp = QString::fromUtf8(value);
+        value.resize(0);
+    }
+    if (tmp.endsWith(QLatin1String("true"))) {
+        critical = true;
+        tmp.truncate(tmp.length() - 5);
+    } else if (tmp.endsWith(QLatin1String("false"))) {
+        critical = false;
+        tmp.truncate(tmp.length() - 6);
+    }
+    oid = tmp;
+    return url;
+}
+
+Ldif::ParseValue Ldif::processLine()
+{
+
+    if (d->mIsComment) {
+        return None;
+    }
+
+    ParseValue retval = None;
+    if (d->mLastParseValue == EndEntry) {
+        d->mEntryType = Entry_None;
+    }
+
+    d->mUrl = splitLine(d->mLine, d->mAttr, d->mValue);
+
+    QString attrLower = d->mAttr.toLower();
+
+    switch (d->mEntryType) {
+    case Entry_None:
+        if (attrLower == QLatin1String("version")) {
+            if (!d->mDn.isEmpty()) {
+                retval = Err;
+            }
+        } else if (attrLower == QLatin1String("dn")) {
+            qCDebug(LDAP_LOG) << "ldapentry dn:" << QString::fromUtf8(d->mValue);
+            d->mDn = LdapDN(QString::fromUtf8(d->mValue));
+            d->mModType = Mod_None;
+            retval = NewEntry;
+        } else if (attrLower == QLatin1String("changetype")) {
+            if (d->mDn.isEmpty()) {
+                retval = Err;
+            } else {
+                QString tmpval = QString::fromUtf8(d->mValue);
+                qCDebug(LDAP_LOG) << "changetype:" << tmpval;
+                if (tmpval == QLatin1String("add")) {
+                    d->mEntryType = Entry_Add;
+                } else if (tmpval == QLatin1String("delete")) {
+                    d->mEntryType = Entry_Del;
+                } else if (tmpval == QLatin1String("modrdn") || tmpval == QLatin1String("moddn")) {
+                    d->mNewRdn.clear();
+                    d->mNewSuperior.clear();
+                    d->mDelOldRdn = true;
+                    d->mEntryType = Entry_Modrdn;
+                } else if (tmpval == QLatin1String("modify")) {
+                    d->mEntryType = Entry_Mod;
+                } else {
+                    retval = Err;
+                }
+            }
+        } else if (attrLower == QLatin1String("control")) {
+            d->mUrl = splitControl(d->mValue, d->mOid, d->mCritical, d->mValue);
+            retval = Control;
+        } else if (!d->mAttr.isEmpty() && d->mValue.size() > 0) {
+            d->mEntryType = Entry_Add;
+            retval = Item;
+        }
+        break;
+    case Entry_Add:
+        if (d->mAttr.isEmpty() && d->mValue.size() == 0) {
+            retval = EndEntry;
+        } else {
+            retval = Item;
+        }
+        break;
+    case Entry_Del:
+        if (d->mAttr.isEmpty() && d->mValue.size() == 0) {
+            retval = EndEntry;
+        } else {
+            retval = Err;
+        }
+        break;
+    case Entry_Mod:
+        if (d->mModType == Mod_None) {
+            qCDebug(LDAP_LOG) << "new modtype" << d->mAttr;
+            if (d->mAttr.isEmpty() && d->mValue.size() == 0) {
+                retval = EndEntry;
+            } else if (attrLower == QLatin1String("add")) {
+                d->mModType = Mod_Add;
+            } else if (attrLower == QLatin1String("replace")) {
+                d->mModType = Mod_Replace;
+                d->mAttr = QString::fromUtf8(d->mValue);
+                d->mValue = QByteArray();
+                retval = Item;
+            } else if (attrLower == QLatin1String("delete")) {
+                d->mModType = Mod_Del;
+                d->mAttr = QString::fromUtf8(d->mValue);
+                d->mValue = QByteArray();
+                retval = Item;
+            } else {
+                retval = Err;
+            }
+        } else {
+            if (d->mAttr.isEmpty()) {
+                if (QString::fromUtf8(d->mValue) == QLatin1String("-")) {
+                    d->mModType = Mod_None;
+                } else if (d->mValue.size() == 0) {
+                    retval = EndEntry;
+                } else {
+                    retval = Err;
+                }
+            } else {
+                retval = Item;
+            }
+        }
+        break;
+    case Entry_Modrdn:
+        if (d->mAttr.isEmpty() && d->mValue.size() == 0) {
+            retval = EndEntry;
+        } else if (attrLower == QLatin1String("newrdn")) {
+            d->mNewRdn = QString::fromUtf8(d->mValue);
+        } else if (attrLower == QLatin1String("newsuperior")) {
+            d->mNewSuperior = QString::fromUtf8(d->mValue);
+        } else if (attrLower == QLatin1String("deleteoldrdn")) {
+            if (d->mValue.size() > 0 && d->mValue[0] == '0') {
+                d->mDelOldRdn = false;
+            } else if (d->mValue.size() > 0 && d->mValue[0] == '1') {
+                d->mDelOldRdn = true;
+            } else {
+                retval = Err;
+            }
+        } else {
+            retval = Err;
+        }
+        break;
+    }
+    return retval;
+}
+
+Ldif::ParseValue Ldif::nextItem()
+{
+    ParseValue retval = None;
+    char c = 0;
+
+    while (retval == None) {
+        if (d->mPos < (uint)d->mLdif.size()) {
+            c = d->mLdif[d->mPos];
+            d->mPos++;
+            if (d->mIsNewLine && c == '\r') {
+                continue; //handle \n\r line end
+            }
+            if (d->mIsNewLine && (c == ' ' || c == '\t')) {     //line folding
+                d->mIsNewLine = false;
+                continue;
+            }
+            if (d->mIsNewLine) {
+                d->mIsNewLine = false;
+                retval = processLine();
+                d->mLastParseValue = retval;
+                d->mLine.resize(0);
+                d->mIsComment = (c == '#');
+            }
+            if (c == '\n' || c == '\r') {
+                d->mLineNumber++;
+                d->mIsNewLine = true;
+                continue;
+            }
+        } else {
+            retval = MoreData;
+            break;
+        }
+
+        if (!d->mIsComment) {
+            d->mLine += c;
+        }
+    }
+    return retval;
+}
+
+void Ldif::endLdif()
+{
+    QByteArray tmp(3, '\n');
+    d->mLdif = tmp;
+    d->mPos = 0;
+}
+
+void Ldif::startParsing()
+{
+    d->mPos = d->mLineNumber = 0;
+    d->mDelOldRdn = false;
+    d->mEntryType = Entry_None;
+    d->mModType = Mod_None;
+    d->mDn = LdapDN();
+    d->mNewRdn.clear();
+    d->mNewSuperior.clear();
+    d->mLine = QByteArray();
+    d->mIsNewLine = false;
+    d->mIsComment = false;
+    d->mLastParseValue = None;
+}
+
+void Ldif::setLdif(const QByteArray &ldif)
+{
+    d->mLdif = ldif;
+    d->mPos = 0;
+}
+
+Ldif::EntryType Ldif::entryType() const
+{
+    return d->mEntryType;
+}
+
+int Ldif::modType() const
+{
+    return d->mModType;
+}
+
+LdapDN Ldif::dn() const
+{
+    return d->mDn;
+}
+
+QString Ldif::newRdn() const
+{
+    return d->mNewRdn;
+}
+
+QString Ldif::newSuperior() const
+{
+    return d->mNewSuperior;
+}
+
+bool Ldif::delOldRdn() const
+{
+    return d->mDelOldRdn;
+}
+
+QString Ldif::attr() const
+{
+    return d->mAttr;
+}
+
+QByteArray Ldif::value() const
+{
+    return d->mValue;
+}
+
+bool Ldif::isUrl() const
+{
+    return d->mUrl;
+}
+
+bool Ldif::isCritical() const
+{
+    return d->mCritical;
+}
+
+QString Ldif::oid() const
+{
+    return d->mOid;
+}
+
+uint Ldif::lineNumber() const
+{
+    return d->mLineNumber;
+}
diff --git a/src/ldif.h b/src/ldif.h
new file mode 100644 (file)
index 0000000..710521b
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+  This file is part of libkldap.
+  Copyright (c) 2004-2006 Szombathelyi György <gyurco@freemail.hu>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KLDAP_LDIF_H
+#define KLDAP_LDIF_H
+
+#include <QtCore/QString>
+#include <QtCore/QByteArray>
+
+#include "ldapdn.h"
+#include "kldap_export.h"
+
+namespace KLDAP
+{
+
+/**
+ * Ldif
+ *
+ * Ldif implements an RFC 2849 compliant Ldif parser. Ldif files are used to
+ * represent directory information on LDAP-based servers, or to describe a set
+ * of changes which are to be applied to a directory.
+ */
+
+class KLDAP_EXPORT Ldif
+{
+public:
+
+    typedef enum {
+        None, NewEntry, EndEntry, Item, Control, Err, MoreData
+    } ParseValue;
+
+    typedef enum {
+        Entry_None, Entry_Add, Entry_Del, Entry_Mod, Entry_Modrdn
+    } EntryType;
+
+    typedef enum {
+        Mod_None, Mod_Add, Mod_Replace, Mod_Del
+    } ModType;
+
+    Ldif();
+
+    Ldif(const Ldif &that);
+    Ldif &operator=(const Ldif &that);
+
+    virtual ~Ldif();
+
+    /**
+     * Assembles fieldname and value into a valid Ldif line, BASE64 encodes the
+     * value if necessary and optionally splits into more lines.
+     * @param fieldname The name of the entry.
+     * @param value The value of the entry.
+     * @param linelen Maximum length of the lines in the result.
+     * @param url If true, encode value as url ( use :< ).
+     */
+    static QByteArray assembleLine(const QString &fieldname,
+                                   const QByteArray &value, uint linelen = 0,
+                                   bool url = false);
+    /**
+     * This is the same as the above function, the only difference that
+     * this accepts QString as the value.
+     */
+    static QByteArray assembleLine(const QString &fieldname,
+                                   const QString &value, uint linelen = 0,
+                                   bool url = false);
+
+    /**
+     * Splits one line from an Ldif file to attribute and value components.
+     * @return true if value is an URL, false otherwise
+     */
+    static bool splitLine(const QByteArray &line, QString &fieldname,
+                          QByteArray &value);
+
+    /**
+     * Splits a control specification (without the "control:" directive)
+     * @param line is the control directive
+     * @param oid will contain the OID
+     * @param critical will contain the criticality of control
+     * @param value is the control value
+     */
+    static bool splitControl(const QByteArray &line, QString &oid,
+                             bool &critical, QByteArray &value);
+
+    /**
+     * Starts the parsing of a new Ldif
+     */
+    void startParsing();
+
+    /**
+     * Process one Ldif line
+     */
+    ParseValue processLine();
+
+    /**
+     * Process the Ldif until a complete item can be returned
+     * @return NewEntry if a new DN encountered, Item if a new item returned,
+     * Err if the Ldif contains error, EndEntry if the parser reached the end
+     * of the current entry and MoreData if the parser encountered the end of
+     * the current chunk of the Ldif.
+     *
+     * If you want to finish the parsing after receiving MoreData, then call
+     * endLdif(), so the parser can safely flush the current entry.
+     */
+    ParseValue nextItem();
+
+    /**
+     * Sets a chunk of Ldif. Call before startParsing(), or if nextItem()
+     * returned MoreData.
+     * @param ldif the Ldif chunk to set
+     */
+    void setLdif(const QByteArray &ldif);
+
+    /**
+     * Indicates the end of the Ldif file/stream. Call if nextItem() returned
+     * MoreData, but actually you don't have more data.
+     */
+    void endLdif();
+
+    /**
+     * Returns the requested LDAP operation extracted from the current entry.
+     */
+    EntryType entryType() const;
+
+    /**
+     * Returns the LDAP modify request type if entryType() returned Entry_Mod.
+     */
+    int modType() const;
+
+    /**
+     * Returns the Distinguished Name of the current entry.
+     */
+    LdapDN dn() const;
+
+    /**
+     * Returns the new Relative Distinguished Name if modType() returned
+     * Entry_Modrdn.
+     */
+    QString newRdn() const;
+
+    /**
+     * Returns the new parent of the entry if modType() returned Entry_Modrdn.
+     */
+    QString newSuperior() const;
+
+    /**
+     * Returns if the delete of the old RDN is required.
+     */
+    bool delOldRdn() const;
+
+    /**
+     * Returns the attribute name.
+     */
+    QString attr() const;
+
+    /**
+     * Returns the attribute value.
+     */
+    QByteArray value() const;
+
+    /**
+     * Returns if val() is an url
+     */
+    bool isUrl() const;
+
+    /**
+     * Returns the criticality level when modType() returned Control.
+     */
+    bool isCritical() const;
+
+    /**
+     * Returns the OID when modType() returned Control.
+     */
+    QString oid() const;
+
+    /**
+     * Returns the line number which the parser processes.
+     */
+    uint lineNumber() const;
+
+private:
+    class LdifPrivate;
+    LdifPrivate *const d;
+};
+
+}
+
+#endif
diff --git a/src/w32-ldap-help.h b/src/w32-ldap-help.h
new file mode 100644 (file)
index 0000000..3f04447
--- /dev/null
@@ -0,0 +1,132 @@
+//krazy:excludeall=style
+/* w32-ldap-help.h - Map utf8 based API into a wchar_t API.
+
+  Copyright (c) 2010 Andre Heinecke <aheinecke@intevation.de>
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General  Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This 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
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public License
+  along with this library; see the file COPYING.LIB.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+ */
+
+#ifndef W32_LDAP_HELP_H
+#define W32_LDAP_HELP_H
+
+#include <windows.h>
+#ifdef UNICODE
+# undef UNICODE
+# include <winldap.h>
+# include <winber.h>
+# define UNICODE
+#else
+# include <winldap.h>
+# include <winber.h>
+#endif // UNICODE
+
+/*
+ * From the openldap manpage:
+ * ber_len_t  is an unsigned integer of at least 32 bits used to represent
+ * a length.  It is commonly equivalent to a size_t.   ber_slen_t  is  the
+ *  signed variant to ber_len_t.
+ */
+typedef ULONG ber_len_t;
+
+#ifndef timeval
+#define timeval l_timeval
+#endif
+
+/* Redirect used ldap functions to functions with win_ prefix
+ * to further redirect those depending on the Windows Flavour */
+//#define ldap_err2string(a) win_ldap_err2string(a)
+#define ldap_init(a,b) win_ldap_init(a,b)
+#define ldap_sasl_bind(a, b, c, d, e, f, g) \
+    win_ldap_sasl_bind(a, b, c, d, e, f, g)
+#define ldap_sasl_bind_s(a, b, c, d, e, f, g) \
+    win_ldap_sasl_bind_s(a, b, c, d, e, f, g)
+#define ldap_parse_sasl_bind_result ( a, b, c, d, e ) \
+    win_ldap_parse_sasl_bind_result((a), (b), (c), (d), (e))
+#define ldap_get_dn(a, b) win_ldap_get_dn(a,b)
+#define ldap_memfree(a)      win_ldap_memfree(a)
+#define ldap_mods_free(a, b) win_ldap_mods_free(a, b)
+#define ldap_first_attribute(a, b, c) \
+    win_ldap_first_attribute(a, b, c)
+#define ldap_get_values_len(a, b, c) \
+    win_ldap_get_values_len(a, b, c)
+#define ldap_next_attribute(a, b, c ) \
+    win_ldap_next_attribute(a, b, c)
+#define ldap_parse_result(a, b, c, d, e, f, g, h) \
+    win_ldap_parse_result(a, b, c, d, e, f, g, h)
+#define ldap_parse_extended_result(a, b, c, d, e) \
+    win_ldap_parse_extended_result(a, b, c, d, e)
+#define ldap_add_ext(a, b, c, d, e, f) \
+    win_ldap_add_ext((a), (b), (c), (d), (e), (f))
+#define ldap_add_ext_s(a, b, c, d, e) \
+    win_ldap_add_ext_s((a), (b), (c), (d), (e))
+# define ldap_compare_ext_s(a, b, c, d, e, f) \
+    win_ldap_compare_ext_s((a), (b), (c), (d), (e), (f))
+# define ldap_compare_ext(a, b, c, d, e, f, g) \
+    win_ldap_compare_ext((a), (b), (c), (d), (e), (f), (g))
+# define ldap_modify_ext_s(a, b, c, d, e ) \
+    win_ldap_modify_ext_s((a), (b), (c), (d), (e))
+# define ldap_search_ext(a, b, c, d, e, f, g, h, i, j, k) \
+    win_ldap_search_ext((a), (b), (c), (d), (e), (f), (g), (h), (i), (j), (k))
+#define ldap_rename_ext( a,  b,  c,  d,  e,  f,  g,  h  ) \
+    win_ldap_rename_ext((a), (b), (c), (d), (e), (f), (g), (h) )
+#define ldap_rename( a,  b,  c,  d,  e,  f,  g,  h  ) \
+    ldap_rename_ext((a), (b), (c), (d), (e), (f), (g), (h) )
+#define ldap_delete_ext(a,  b,  c,  d,  e  ) \
+    win_ldap_delete_ext((a), (b), (c), (d), (e) )
+#define ldap_modify_ext(a,  b,  c,  d,  e,  f ) \
+    win_ldap_modify_ext( (a), (b), (c), (d), (e), (f))
+#define ldap_abandon_ext(a, b, c, d) \
+    win_ldap_abandon_ext((a), (b), (c), (d))
+#define ldap_controls_free(a) win_ldap_controls_free(a)
+
+// Use the functions that are available on the platform
+// or redirect to wrapper functions
+
+/* Windows offers ASCII variants of most LDAP functions
+ * we only have to ensure that those are used */
+# define LDAPControl LDAPControlA
+# define LDAPMod LDAPModA
+# define win_ldap_init(a,b)              ldap_initA ((a), (b))
+# define win_ldap_simple_bind_s(a,b,c)   ldap_simple_bind_sA ((a), (b), (c))
+# define win_ldap_sasl_bind(a, b, c, d, e, f, g) \
+    ldap_sasl_bindA(a, b, c, d, e, f, g)
+# define win_ldap_sasl_bind_s(a, b, c, d, e, f, g) \
+    ldap_sasl_bind_sA(a, b, c, d, e, f, g)
+# define win_ldap_search_st(a,b,c,d,e,f,g,h)     \
+    ldap_search_stA ((a), (b), (c), (d), (e), (f), (g), (h))
+# define win_ldap_search_ext(a, b, c, d, e, f, g, h, i, j, k) \
+    my_win_ldap_search_ext((a), (b), (c), (d), (e), (f), (g), (h), (i), (j), (k))
+# define win_ldap_get_dn(a, b)           ldap_get_dnA((a), (b))
+# define win_ldap_first_attribute(a,b,c) ldap_first_attributeA ((a), (b), (c))
+# define win_ldap_next_attribute(a,b,c)  ldap_next_attributeA ((a), (b), (c))
+# define win_ldap_get_values_len(a,b,c)  ldap_get_values_lenA ((a), (b), (c))
+# define win_ldap_memfree(a)             ldap_memfreeA ((a))
+# define win_ldap_err2string(a)          ldap_err2stringA((a))
+# define win_ldap_controls_free(a)       ldap_controls_freeA((a))
+# define win_ldap_mods_free(a, b)        ldap_mods_freeA((a), (b))
+# define win_ldap_add_ext(a, b, c, d, e, f) \
+    ldap_add_extA((a), (b), (c), (d), (e), ((ulong*)f))
+# define win_ldap_add_ext_s(a, b, c, d, e) \
+    ldap_add_ext_sA((a), (b), (c), (d), (e))
+# define win_ldap_parse_extended_result(a, b, c, d, e ) \
+    ldap_parse_extended_resultA((*a), (b), (c), (d), (e))
+# define win_ldap_parse_result(a, b, c, d, e, f, g, h ) \
+    ldap_parse_resultA((a), (b), ((ulong *)c), (d), (e), (f), (g), (h))
+# define win_ldap_modify_ext_s(a, b, c, d, e ) \
+    ldap_modify_ext_sW((a), (b), (c), (d), (e))
+# define win_ldap_compare_ext_s(a, b, c, d, e, f ) \
+    ldap_compare_ext_sA((a), (b), (c), (d), (e), (f))
+#endif /*W32_LDAP_HELP_H*/