[kde-doc-english] [kldap] /: Move kioslave ldap here

Montel Laurent montel at kde.org
Sun Apr 3 18:38:38 UTC 2016


Git commit be1dda4d707b81956431a09798c44a5b0f925cfc by Montel Laurent.
Committed on 03/04/2016 at 18:38.
Pushed by mlaurent into branch 'master'.

Move kioslave ldap here

M  +11   -1    CMakeLists.txt
A  +1    -0    kioslave/.krazy
A  +5    -0    kioslave/.reviewboardrc
A  +4    -0    kioslave/CMakeLists.txt
A  +1    -0    kioslave/docs/CMakeLists.txt
A  +3    -0    kioslave/docs/ldap/CMakeLists.txt
A  +30   -0    kioslave/docs/ldap/index.docbook
A  +5    -0    kioslave/kdepimlibs-kioslave.categories
A  +2    -0    kioslave/src/CMakeLists.txt
A  +50   -0    kioslave/src/common.h     [License: LGPL (v2+)]
A  +14   -0    kioslave/src/ldap/CMakeLists.txt
A  +2    -0    kioslave/src/ldap/Messages.sh
A  +819  -0    kioslave/src/ldap/kio_ldap.cpp     [License: BSD X11 (BSD like)]
A  +70   -0    kioslave/src/ldap/kio_ldap.h     [License: BSD X11 (BSD like)]
A  +17   -0    kioslave/src/ldap/ldap.protocol
A  +17   -0    kioslave/src/ldap/ldaps.protocol
A  +5    -0    kldap.categories

http://commits.kde.org/kldap/be1dda4d707b81956431a09798c44a5b0f925cfc

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4ff88d0..4fc466e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,6 +19,14 @@ include(ECMQtDeclareLoggingCategory)
 
 set(KF5_VERSION "5.19.0")
 set(KLDAP_LIB_VERSION "5.2.40")
+set(MBOXLIB_VERSION "5.2.40")
+
+find_package(KF5KIO ${KF5_VERSION} CONFIG REQUIRED)
+find_package(KF5I18n ${KF5_VERSION} CONFIG REQUIRED)
+find_package(KF5DocTools ${KF5_VERSION} CONFIG REQUIRED)
+find_package(KF5Mbox ${MBOXLIB_VERSION} CONFIG REQUIRED)
+add_definitions("-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII")
+
 
 ecm_setup_version(${KLDAP_LIB_VERSION} VARIABLE_PREFIX KLDAP
                         VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kldap_version.h"
@@ -79,9 +87,11 @@ install(FILES
 ########### Targets ###########
 add_subdirectory(cmake)
 add_subdirectory(src)
-
+add_subdirectory(kioslave)
 if(BUILD_TESTING)
     add_subdirectory(autotests)
 endif()
 
+install( FILES kldap.categories DESTINATION ${KDE_INSTALL_CONFDIR} )
+
 feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/kioslave/.krazy b/kioslave/.krazy
new file mode 100644
index 0000000..0b16e7f
--- /dev/null
+++ b/kioslave/.krazy
@@ -0,0 +1 @@
+SKIP /tests/
diff --git a/kioslave/.reviewboardrc b/kioslave/.reviewboardrc
new file mode 100644
index 0000000..5c1c502
--- /dev/null
+++ b/kioslave/.reviewboardrc
@@ -0,0 +1,5 @@
+REVIEWBOARD_URL = "https://git.reviewboard.kde.org"
+#REPOSITORY = "git://anongit.kde.org/kioslave"
+BRANCH = "master"
+TARGET_GROUPS = "kdepimlibs"
+TARGET_PEOPLE = "mlaurent"
diff --git a/kioslave/CMakeLists.txt b/kioslave/CMakeLists.txt
new file mode 100644
index 0000000..9f7c57a
--- /dev/null
+++ b/kioslave/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_definitions("-DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII")
+add_subdirectory(src)
+add_subdirectory(docs)
+
diff --git a/kioslave/docs/CMakeLists.txt b/kioslave/docs/CMakeLists.txt
new file mode 100644
index 0000000..181669e
--- /dev/null
+++ b/kioslave/docs/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(ldap)
diff --git a/kioslave/docs/ldap/CMakeLists.txt b/kioslave/docs/ldap/CMakeLists.txt
new file mode 100644
index 0000000..d77d09f
--- /dev/null
+++ b/kioslave/docs/ldap/CMakeLists.txt
@@ -0,0 +1,3 @@
+########### install files ###############
+kdoctools_create_handbook(index.docbook INSTALL_DESTINATION ${KDE_INSTALL_DOCBUNDLEDIR}/en SUBDIR kioslave5/ldap)
+
diff --git a/kioslave/docs/ldap/index.docbook b/kioslave/docs/ldap/index.docbook
new file mode 100644
index 0000000..2cd0aac
--- /dev/null
+++ b/kioslave/docs/ldap/index.docbook
@@ -0,0 +1,30 @@
+<?xml version="1.0" ?>
+<!DOCTYPE article PUBLIC "-//KDE//DTD DocBook XML V4.5-Based Variant V1.1//EN"
+"dtd/kdedbx45.dtd" [
+<!ENTITY % addindex "IGNORE">
+<!ENTITY % English "INCLUDE" > <!-- change language only here -->
+]>
+	
+<article lang="&language;" id="ldap">
+<title>ldap</title>
+<articleinfo>
+<authorgroup>
+<author>&Lauri.Watts; &Lauri.Watts.mail;</author>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+</articleinfo>
+
+<para><acronym>ldap</acronym> is the lightweight directory access
+protocol.  It provides access to an X.500 directory, or to a stand-alone
+<acronym>LDAP</acronym> server.</para>
+
+<para>You can use the ldap kioslave as follows:</para>
+
+<para><userinput>ldap://host:port/ou=People,o=where,c=de??sub</userinput>
+for a subtree-query</para>
+
+<para>or
+<userinput>ldap://host:port/cn=MM,ou=People,o=where,c=de??base</userinput>
+for a complete branch.</para>
+
+</article>
diff --git a/kioslave/kdepimlibs-kioslave.categories b/kioslave/kdepimlibs-kioslave.categories
new file mode 100644
index 0000000..f5262f5
--- /dev/null
+++ b/kioslave/kdepimlibs-kioslave.categories
@@ -0,0 +1,5 @@
+log_kldap kioslave (kldap)
+log_sieve kioslave (sieve)
+log_smtp kioslave (smtp)
+log_pop3 kioslave (pop3)
+
diff --git a/kioslave/src/CMakeLists.txt b/kioslave/src/CMakeLists.txt
new file mode 100644
index 0000000..7307efa
--- /dev/null
+++ b/kioslave/src/CMakeLists.txt
@@ -0,0 +1,2 @@
+remove_definitions(-DQT_NO_CAST_FROM_BYTEARRAY)
+add_subdirectory(ldap)
diff --git a/kioslave/src/common.h b/kioslave/src/common.h
new file mode 100644
index 0000000..acdeb17
--- /dev/null
+++ b/kioslave/src/common.h
@@ -0,0 +1,50 @@
+/*  This file is part of the KDE project
+    Copyright (C) 2008 Jarosław Staniek <staniek at 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 _KIOSLAVE_COMMON_H
+#define _KIOSLAVE_COMMON_H
+
+#include <stdio.h>
+#include <QFile>
+#include <QDir>
+
+extern "C" {
+#include <sasl/sasl.h>
+}
+
+inline bool initSASL()
+{
+#ifdef Q_OS_WIN32  //krazy:exclude=cpp
+    QByteArray libInstallPath(QFile::encodeName(QDir::toNativeSeparators(KGlobal::dirs()->installPath("lib") + QLatin1String("sasl2"))));
+    QByteArray configPath(QFile::encodeName(QDir::toNativeSeparators(KGlobal::dirs()->installPath("config") + QLatin1String("sasl2"))));
+    if (sasl_set_path(SASL_PATH_TYPE_PLUGIN, libInstallPath.data()) != SASL_OK ||
+            sasl_set_path(SASL_PATH_TYPE_CONFIG, configPath.data()) != SASL_OK) {
+        fprintf(stderr, "SASL path initialization failed!\n");
+        return false;
+    }
+#endif
+
+    if (sasl_client_init(NULL) != SASL_OK) {
+        fprintf(stderr, "SASL library initialization failed!\n");
+        return false;
+    }
+    return true;
+}
+
+#endif
diff --git a/kioslave/src/ldap/CMakeLists.txt b/kioslave/src/ldap/CMakeLists.txt
new file mode 100644
index 0000000..29a0380
--- /dev/null
+++ b/kioslave/src/ldap/CMakeLists.txt
@@ -0,0 +1,14 @@
+
+set(kio_ldap_PART_SRCS kio_ldap.cpp)
+ecm_qt_declare_logging_category(kio_ldap_PART_SRCS HEADER kldap_debug.h IDENTIFIER KLDAP_LOG CATEGORY_NAME log_kldap)
+
+add_library(kio_ldap MODULE ${kio_ldap_PART_SRCS})
+
+target_link_libraries(kio_ldap KF5::KIOCore KF5::I18n KF5::Ldap KF5::Mbox)
+set_target_properties(kio_ldap PROPERTIES OUTPUT_NAME "ldap")
+install(TARGETS kio_ldap  DESTINATION ${KDE_INSTALL_PLUGINDIR}/kf5/kio)
+
+
+########### install files ###############
+
+install( FILES ldap.protocol ldaps.protocol  DESTINATION  ${KDE_INSTALL_KSERVICES5DIR} )
diff --git a/kioslave/src/ldap/Messages.sh b/kioslave/src/ldap/Messages.sh
new file mode 100644
index 0000000..bb14723
--- /dev/null
+++ b/kioslave/src/ldap/Messages.sh
@@ -0,0 +1,2 @@
+#! /usr/bin/env bash
+$XGETTEXT *.cpp -o $podir/kio_ldap.pot
diff --git a/kioslave/src/ldap/kio_ldap.cpp b/kioslave/src/ldap/kio_ldap.cpp
new file mode 100644
index 0000000..4ab7285
--- /dev/null
+++ b/kioslave/src/ldap/kio_ldap.cpp
@@ -0,0 +1,819 @@
+/*
+  Copyright (c) 2004-2007 Szombathelyi György <gyurco at freemail.hu>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#include "kio_ldap.h"
+#include "kldap_debug.h"
+
+#include <kldap/ldif.h>
+#include <kldap/ldapcontrol.h>
+
+#include <qdebug.h>
+#include <KLocalizedString>
+#include <QCoreApplication>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+
+using namespace KIO;
+using namespace KLDAP;
+
+extern "C" {
+    int Q_DECL_EXPORT kdemain(int argc, char **argv);
+}
+
+/**
+ * The main program.
+ */
+int kdemain(int argc, char **argv)
+{
+    QCoreApplication app(argc, argv);   // needed for QSocketNotifier
+    app.setApplicationName(QStringLiteral("kio_ldap"));
+
+    qCDebug(KLDAP_LOG) << "Starting kio_ldap instance";
+
+    if (argc != 4) {
+        qCritical() << "Usage kio_ldap protocol pool app" << endl;
+        return -1;
+    }
+
+    // let the protocol class do its work
+    LDAPProtocol slave(argv[1], argv[2], argv[3]);
+    slave.dispatchLoop();
+
+    qCDebug(KLDAP_LOG) << "Done";
+    return 0;
+}
+
+/**
+ * Initialize the ldap slave
+ */
+LDAPProtocol::LDAPProtocol(const QByteArray &protocol, const QByteArray &pool,
+                           const QByteArray &app)
+    : SlaveBase(protocol, pool, app)
+{
+    mConnected = false;
+    mOp.setConnection(mConn);
+    qCDebug(KLDAP_LOG) << "LDAPProtocol::LDAPProtocol (" << protocol << ")";
+}
+
+LDAPProtocol::~LDAPProtocol()
+{
+    closeConnection();
+}
+
+void LDAPProtocol::LDAPErr(int err)
+{
+
+    QString extramsg;
+    if (mConnected) {
+        if (err == KLDAP_SUCCESS) {
+            err = mConn.ldapErrorCode();
+        }
+        if (err != KLDAP_SUCCESS) {
+            extramsg = i18n("\nAdditional info: ") + mConn.ldapErrorString();
+        }
+    }
+    if (err == KLDAP_SUCCESS) {
+        return;
+    }
+
+    qDebug() << "error code: " << err << " msg: " << LdapConnection::errorString(err) <<
+             extramsg << "'" << endl;
+    QString msg;
+    msg = mServer.url().toDisplayString();
+    if (!extramsg.isEmpty()) {
+        msg += extramsg;
+    }
+
+    /* FIXME: No need to close on all errors */
+    closeConnection();
+
+    switch (err) {
+    /* FIXME: is it worth mapping the following error codes to kio errors?
+
+      LDAP_OPERATIONS_ERROR
+      LDAP_STRONG_AUTH_REQUIRED
+      LDAP_PROTOCOL_ERROR
+      LDAP_TIMELIMIT_EXCEEDED
+      LDAP_SIZELIMIT_EXCEEDED
+      LDAP_COMPARE_FALSE
+      LDAP_COMPARE_TRUE
+      LDAP_PARTIAL_RESULTS
+      LDAP_NO_SUCH_ATTRIBUTE
+      LDAP_UNDEFINED_TYPE
+      LDAP_INAPPROPRIATE_MATCHING
+      LDAP_CONSTRAINT_VIOLATION
+      LDAP_INVALID_SYNTAX
+      LDAP_NO_SUCH_OBJECT
+      LDAP_ALIAS_PROBLEM
+      LDAP_INVALID_DN_SYNTAX
+      LDAP_IS_LEAF
+      LDAP_ALIAS_DEREF_PROBLEM
+      LDAP_INAPPROPRIATE_AUTH
+      LDAP_BUSY
+      LDAP_UNAVAILABLE
+      LDAP_UNWILLING_TO_PERFORM
+      LDAP_LOOP_DETECT
+      LDAP_NAMING_VIOLATION
+      LDAP_OBJECT_CLASS_VIOLATION
+      LDAP_NOT_ALLOWED_ON_NONLEAF
+      LDAP_NOT_ALLOWED_ON_RDN
+      LDAP_NO_OBJECT_CLASS_MODS
+      LDAP_OTHER
+      LDAP_LOCAL_ERROR
+      LDAP_ENCODING_ERROR
+      LDAP_DECODING_ERROR
+      LDAP_FILTER_ERROR
+    */
+    case KLDAP_AUTH_UNKNOWN:
+    case KLDAP_INVALID_CREDENTIALS:
+    case KLDAP_STRONG_AUTH_NOT_SUPPORTED:
+        error(ERR_COULD_NOT_AUTHENTICATE, msg);
+        break;
+    case KLDAP_ALREADY_EXISTS:
+        error(ERR_FILE_ALREADY_EXIST, msg);
+        break;
+    case KLDAP_INSUFFICIENT_ACCESS:
+        error(ERR_ACCESS_DENIED, msg);
+        break;
+    case KLDAP_CONNECT_ERROR:
+    case KLDAP_SERVER_DOWN:
+        error(ERR_COULD_NOT_CONNECT, msg);
+        break;
+    case KLDAP_TIMEOUT:
+        error(ERR_SERVER_TIMEOUT, msg);
+        break;
+    case KLDAP_PARAM_ERROR:
+        error(ERR_INTERNAL, msg);
+        break;
+    case KLDAP_NO_MEMORY:
+        error(ERR_OUT_OF_MEMORY, msg);
+        break;
+
+    default:
+        error(ERR_SLAVE_DEFINED,
+              i18n("LDAP server returned the error: %1 %2\nThe LDAP URL was: %3",
+                   LdapConnection::errorString(err), extramsg, mServer.url().toDisplayString()));
+    }
+}
+
+void LDAPProtocol::controlsFromMetaData(LdapControls &serverctrls,
+                                        LdapControls &clientctrls)
+{
+    QString oid;
+    bool critical;
+    QByteArray value;
+    int i = 0;
+    while (hasMetaData(QStringLiteral("SERVER_CTRL%1").arg(i))) {
+        QByteArray val = metaData(QStringLiteral("SERVER_CTRL%1").arg(i)).toUtf8();
+        Ldif::splitControl(val, oid, critical, value);
+        qCDebug(KLDAP_LOG) << "server ctrl #" << i << " value: " << val <<
+                           " oid: " << oid << " critical: " << critical << " value: " <<
+                           QString::fromUtf8(value, value.size()) << endl;
+        LdapControl ctrl(oid, val, critical);
+        serverctrls.append(ctrl);
+        i++;
+    }
+    i = 0;
+    while (hasMetaData(QStringLiteral("CLIENT_CTRL%1").arg(i))) {
+        QByteArray val = metaData(QStringLiteral("CLIENT_CTRL%1").arg(i)).toUtf8();
+        Ldif::splitControl(val, oid, critical, value);
+        qCDebug(KLDAP_LOG) << "client ctrl #" << i << " value: " << val <<
+                           " oid: " << oid << " critical: " << critical << " value: " <<
+                           QString::fromUtf8(value, value.size()) << endl;
+        LdapControl ctrl(oid, val, critical);
+        clientctrls.append(ctrl);
+        i++;
+    }
+
+}
+
+void LDAPProtocol::LDAPEntry2UDSEntry(const LdapDN &dn, UDSEntry &entry,
+                                      const LdapUrl &usrc, bool dir)
+{
+    int pos;
+    entry.clear();
+    QString name = dn.toString();
+    if ((pos = name.indexOf(QLatin1Char(','))) > 0) {
+        name = name.left(pos);
+    }
+    if ((pos = name.indexOf(QLatin1Char('='))) > 0) {
+        name.remove(0, pos + 1);
+    }
+    name.replace(QLatin1Char(' '), QLatin1String("_"));
+    if (!dir) {
+        name += QLatin1String(".ldif");
+    }
+    entry.insert(KIO::UDSEntry::UDS_NAME, name);
+
+    // the file type
+    entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, dir ? S_IFDIR : S_IFREG);
+
+    // the mimetype
+    if (!dir) {
+        entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, QStringLiteral("text/plain"));
+    }
+
+    entry.insert(KIO::UDSEntry::UDS_ACCESS, dir ? 0500 : 0400);
+
+    // the url
+    LdapUrl url = usrc;
+    url.setPath(QLatin1Char('/') + dn.toString());
+    url.setScope(dir ? LdapUrl::One : LdapUrl::Base);
+    entry.insert(KIO::UDSEntry::UDS_URL, url.toDisplayString());
+}
+
+void LDAPProtocol::changeCheck(const LdapUrl &url)
+{
+    LdapServer server;
+    server.setUrl(url);
+
+    if (mConnected) {
+        if (server.host() != mServer.host() ||
+                server.port() != mServer.port() ||
+                server.baseDn() != mServer.baseDn() ||
+                server.user() != mServer.user() ||
+                server.bindDn() != mServer.bindDn() ||
+                server.realm() != mServer.realm() ||
+                server.password() != mServer.password() ||
+                server.timeLimit() != mServer.timeLimit() ||
+                server.sizeLimit() != mServer.sizeLimit() ||
+                server.version() != mServer.version() ||
+                server.security() != mServer.security() ||
+                server.auth() != mServer.auth() ||
+                server.mech() != mServer.mech()) {
+
+            closeConnection();
+            mServer = server;
+            openConnection();
+        }
+    } else {
+        mServer = server;
+        openConnection();
+    }
+}
+
+void LDAPProtocol::setHost(const QString &host, quint16 port,
+                           const QString &user, const QString &password)
+{
+    if (mServer.host() != host ||
+            mServer.port() != port ||
+            mServer.user() != user ||
+            mServer.password() != password) {
+        closeConnection();
+    }
+
+    mServer.host() = host;
+    if (port > 0) {
+        mServer.setPort(port);
+    } else {
+        struct servent *pse;
+        if ((pse = getservbyname(mProtocol, "tcp")) == NULL) {
+            if (mProtocol == "ldaps") {
+                mServer.setPort(636);
+            } else {
+                mServer.setPort(389);
+            }
+        } else {
+            mServer.setPort(ntohs(pse->s_port));
+        }
+    }
+    mServer.setUser(user);
+    mServer.setPassword(password);
+
+    qCDebug(KLDAP_LOG) << "setHost: " << host << " port: " << port << " user: " <<
+                       user << " pass: [protected]" << endl;
+}
+
+void LDAPProtocol::openConnection()
+{
+    if (mConnected) {
+        return;
+    }
+
+    mConn.setServer(mServer);
+    if (mConn.connect() != 0) {
+        error(ERR_COULD_NOT_CONNECT, mConn.connectionError());
+        return;
+    }
+
+    mConnected = true;
+
+    AuthInfo info;
+    info.url.setScheme(QLatin1String(mProtocol));
+    info.url.setHost(mServer.host());
+    info.url.setPort(mServer.port());
+    info.url.setUserName(mServer.user());
+    info.caption = i18n("LDAP Login");
+    info.comment = QString::fromLatin1(mProtocol) + QLatin1String("://") + mServer.host() + QLatin1Char(':') +
+                   QString::number(mServer.port());
+    info.commentLabel = i18n("site:");
+    info.username = mServer.auth() == LdapServer::SASL ? mServer.user() : mServer.bindDn();
+    info.password = mServer.password();
+    info.keepPassword = true;
+    bool cached = checkCachedAuthentication(info);
+
+    bool firstauth = true;
+    int retval;
+
+    while (true) {
+        retval = mOp.bind_s();
+        if (retval == 0) {
+            qCDebug(KLDAP_LOG) << "connected!";
+            connected();
+            return;
+        }
+        if (retval == KLDAP_INVALID_CREDENTIALS ||
+                retval == KLDAP_INSUFFICIENT_ACCESS ||
+                retval == KLDAP_INAPPROPRIATE_AUTH  ||
+                retval == KLDAP_UNWILLING_TO_PERFORM) {
+
+            if (firstauth && cached) {
+                if (mServer.auth() == LdapServer::SASL) {
+                    mServer.setUser(info.username);
+                } else {
+                    mServer.setBindDn(info.username);
+                }
+                mServer.setPassword(info.password);
+                mConn.setServer(mServer);
+                cached = false;
+            } else {
+                bool ok = firstauth ?
+                          openPasswordDialog(info) :
+                          openPasswordDialog(info, i18n("Invalid authorization information."));
+                if (!ok) {
+                    error(ERR_USER_CANCELED, i18n("LDAP connection canceled."));
+                    closeConnection();
+                    return;
+                }
+                if (mServer.auth() == LdapServer::SASL) {
+                    mServer.setUser(info.username);
+                } else {
+                    mServer.setBindDn(info.username);
+                }
+                mServer.setPassword(info.password);
+                firstauth = false;
+                mConn.setServer(mServer);
+            }
+
+        } else {
+            LDAPErr(retval);
+            closeConnection();
+            return;
+        }
+    }
+}
+
+void LDAPProtocol::closeConnection()
+{
+    if (mConnected) {
+        mConn.close();
+    }
+    mConnected = false;
+
+    qCDebug(KLDAP_LOG) << "connection closed!";
+}
+
+/**
+ * Get the information contained in the URL.
+ */
+void LDAPProtocol::get(const QUrl &_url)
+{
+    qCDebug(KLDAP_LOG) << "get(" << _url << ")";
+
+    LdapUrl usrc(_url);
+    int ret, id;
+
+    changeCheck(usrc);
+    if (!mConnected) {
+        finished();
+        return;
+    }
+
+    LdapControls serverctrls, clientctrls;
+    controlsFromMetaData(serverctrls, clientctrls);
+    if (mServer.pageSize()) {
+        LdapControls ctrls = serverctrls;
+        ctrls.append(LdapControl::createPageControl(mServer.pageSize()));
+        qCDebug(KLDAP_LOG) << "page size: " << mServer.pageSize();
+        mOp.setServerControls(ctrls);
+    } else {
+        mOp.setServerControls(serverctrls);
+    }
+    mOp.setClientControls(clientctrls);
+
+    if ((id = mOp.search(usrc.dn(), usrc.scope(), usrc.filter(), usrc.attributes())) == -1) {
+        LDAPErr();
+        return;
+    }
+
+    // tell the mimetype
+    mimeType(QStringLiteral("text/plain"));
+    // collect the result
+    //QByteArray result;
+    filesize_t processed_size = 0;
+
+    while (true) {
+        ret = mOp.waitForResult(id, -1);
+        if (ret == -1 || mConn.ldapErrorCode() != KLDAP_SUCCESS) {
+            LDAPErr();
+            return;
+        }
+        qCDebug(KLDAP_LOG) << " ldap_result: " << ret;
+        if (ret == LdapOperation::RES_SEARCH_RESULT) {
+
+            if (mServer.pageSize()) {
+                QByteArray cookie;
+                int estsize = -1;
+                for (int i = 0; i < mOp.controls().count(); ++i) {
+                    qCDebug(KLDAP_LOG) << " control oid: " << mOp.controls().at(i).oid();
+                    estsize = mOp.controls().at(i).parsePageControl(cookie);
+                    if (estsize != -1) {
+                        break;
+                    }
+                }
+                qCDebug(KLDAP_LOG) << " estimated size: " << estsize;
+                if (estsize != -1 && !cookie.isEmpty()) {
+                    LdapControls ctrls;
+                    ctrls = serverctrls;
+                    qCDebug(KLDAP_LOG) << "page size: " << mServer.pageSize() << " estimated size: " << estsize;
+                    ctrls.append(LdapControl::createPageControl(mServer.pageSize(), cookie));
+                    mOp.setServerControls(ctrls);
+                    if ((id = mOp.search(usrc.dn(), usrc.scope(), usrc.filter(), usrc.attributes())) == -1) {
+                        LDAPErr();
+                        return;
+                    }
+                    continue;
+                }
+            }
+            break;
+        }
+        if (ret != LdapOperation::RES_SEARCH_ENTRY) {
+            continue;
+        }
+
+        QByteArray entry = mOp.object().toString().toUtf8() + '\n';
+        processed_size += entry.size();
+        data(entry);
+        processedSize(processed_size);
+    }
+
+    totalSize(processed_size);
+
+    // tell we are finished
+    data(QByteArray());
+    finished();
+}
+
+/**
+ * Test if the url contains a directory or a file.
+ */
+void LDAPProtocol::stat(const QUrl &_url)
+{
+    qCDebug(KLDAP_LOG) << "stat(" << _url << ")";
+
+    QStringList att, saveatt;
+    LdapUrl usrc(_url);
+    int ret, id;
+
+    changeCheck(usrc);
+    if (!mConnected) {
+        finished();
+        return;
+    }
+
+    // look how many entries match
+    saveatt = usrc.attributes();
+    att.append(QStringLiteral("dn"));
+
+    if ((id = mOp.search(usrc.dn(), usrc.scope(), usrc.filter(), att)) == -1) {
+        LDAPErr();
+        return;
+    }
+
+    qCDebug(KLDAP_LOG) << "stat() getting result";
+    do {
+        ret = mOp.waitForResult(id, -1);
+        if (ret == -1 || mConn.ldapErrorCode() != KLDAP_SUCCESS) {
+            LDAPErr();
+            return;
+        }
+        if (ret == LdapOperation::RES_SEARCH_RESULT) {
+            error(ERR_DOES_NOT_EXIST, _url.toDisplayString());
+            return;
+        }
+    } while (ret != LdapOperation::RES_SEARCH_ENTRY);
+
+    mOp.abandon(id);
+
+    usrc.setAttributes(saveatt);
+
+    UDSEntry uds;
+    bool critical;
+    LDAPEntry2UDSEntry(usrc.dn(), uds, usrc, usrc.extension(QStringLiteral("x-dir"), critical) != QLatin1String("base"));
+
+    statEntry(uds);
+    // we are done
+    finished();
+}
+
+/**
+ * Deletes one entry;
+ */
+void LDAPProtocol::del(const QUrl &_url, bool)
+{
+    qCDebug(KLDAP_LOG) << "del(" << _url << ")";
+
+    LdapUrl usrc(_url);
+    int id, ret;
+
+    changeCheck(usrc);
+    if (!mConnected) {
+        finished();
+        return;
+    }
+
+    LdapControls serverctrls, clientctrls;
+    controlsFromMetaData(serverctrls, clientctrls);
+    mOp.setServerControls(serverctrls);
+    mOp.setClientControls(clientctrls);
+
+    qCDebug(KLDAP_LOG) << " del: " << usrc.dn().toString().toUtf8();
+
+    if ((id = mOp.del(usrc.dn())) == -1) {
+        LDAPErr();
+        return;
+    }
+    ret = mOp.waitForResult(id, -1);
+    if (ret == -1 || mConn.ldapErrorCode() != KLDAP_SUCCESS) {
+        LDAPErr();
+        return;
+    }
+
+    finished();
+}
+
+void LDAPProtocol::put(const QUrl &_url, int, KIO::JobFlags flags)
+{
+    qCDebug(KLDAP_LOG) << "put(" << _url << ")";
+
+    LdapUrl usrc(_url);
+
+    changeCheck(usrc);
+    if (!mConnected) {
+        finished();
+        return;
+    }
+
+    LdapControls serverctrls, clientctrls;
+    controlsFromMetaData(serverctrls, clientctrls);
+    mOp.setServerControls(serverctrls);
+    mOp.setClientControls(clientctrls);
+
+    LdapObject addObject;
+    LdapOperation::ModOps modops;
+    QByteArray buffer;
+    int result = 0;
+    Ldif::ParseValue ret;
+    Ldif ldif;
+    ret = Ldif::MoreData;
+    int ldaperr;
+
+    do {
+        if (ret == Ldif::MoreData) {
+            dataReq(); // Request for data
+            result = readData(buffer);
+            ldif.setLdif(buffer);
+        }
+        if (result < 0) {
+            //error
+            return;
+        }
+        if (result == 0) {
+            qCDebug(KLDAP_LOG) << "EOF!";
+            ldif.endLdif();
+        }
+        do {
+
+            ret = ldif.nextItem();
+            qCDebug(KLDAP_LOG) << "nextitem: " << ret;
+
+            switch (ret) {
+            case Ldif::None:
+            case Ldif::NewEntry:
+            case Ldif::MoreData:
+                break;
+            case Ldif::EndEntry:
+                ldaperr = KLDAP_SUCCESS;
+                switch (ldif.entryType()) {
+                case Ldif::Entry_None:
+                    error(ERR_INTERNAL, i18n("The Ldif parser failed."));
+                    return;
+                case Ldif::Entry_Del:
+                    qCDebug(KLDAP_LOG) << "kio_ldap_del";
+                    ldaperr = mOp.del_s(ldif.dn());
+                    break;
+                case Ldif::Entry_Modrdn:
+                    qCDebug(KLDAP_LOG) << "kio_ldap_modrdn olddn:" << ldif.dn().toString() <<
+                                       " newRdn: " <<  ldif.newRdn() <<
+                                       " newSuperior: " << ldif.newSuperior() <<
+                                       " deloldrdn: " << ldif.delOldRdn() << endl;
+                    ldaperr = mOp.rename_s(ldif.dn(), ldif.newRdn(),
+                                           ldif.newSuperior(), ldif.delOldRdn());
+                    break;
+                case Ldif::Entry_Mod:
+                    qCDebug(KLDAP_LOG) << "kio_ldap_mod";
+                    ldaperr = mOp.modify_s(ldif.dn(), modops);
+                    modops.clear();
+                    break;
+                case Ldif::Entry_Add:
+                    qCDebug(KLDAP_LOG) << "kio_ldap_add " << ldif.dn().toString();
+                    addObject.setDn(ldif.dn());
+                    ldaperr = mOp.add_s(addObject);
+                    if (ldaperr == KLDAP_ALREADY_EXISTS && (flags & KIO::Overwrite)) {
+                        qCDebug(KLDAP_LOG) << ldif.dn().toString() << " already exists, delete first";
+                        ldaperr = mOp.del_s(ldif.dn());
+                        if (ldaperr == KLDAP_SUCCESS) {
+                            ldaperr = mOp.add_s(addObject);
+                        }
+                    }
+                    addObject.clear();
+                    break;
+                }
+                if (ldaperr != KLDAP_SUCCESS) {
+                    qCDebug(KLDAP_LOG) << "put ldap error: " << ldaperr;
+                    LDAPErr(ldaperr);
+                    return;
+                }
+                break;
+            case Ldif::Item:
+                switch (ldif.entryType()) {
+                case Ldif::Entry_Mod: {
+                    LdapOperation::ModOp op;
+                    op.type = LdapOperation::Mod_None;
+                    switch (ldif.modType()) {
+                    case Ldif::Mod_None:
+                        op.type = LdapOperation::Mod_None;
+                        break;
+                    case Ldif::Mod_Add:
+                        op.type = LdapOperation::Mod_Add;
+                        break;
+                    case Ldif::Mod_Replace:
+                        op.type = LdapOperation::Mod_Replace;
+                        break;
+                    case Ldif::Mod_Del:
+                        op.type = LdapOperation::Mod_Del;
+                        break;
+                    }
+                    op.attr = ldif.attr();
+                    if (!ldif.value().isNull()) {
+                        op.values.append(ldif.value());
+                    }
+                    modops.append(op);
+                    break;
+                }
+                case Ldif::Entry_Add:
+                    if (ldif.value().size() > 0) {
+                        addObject.addValue(ldif.attr(), ldif.value());
+                    }
+                    break;
+                default:
+                    error(ERR_INTERNAL, i18n("The Ldif parser failed."));
+                    return;
+                }
+                break;
+            case Ldif::Control: {
+                LdapControl control;
+                control.setControl(ldif.oid(), ldif.value(), ldif.isCritical());
+                serverctrls.append(control);
+                mOp.setServerControls(serverctrls);
+                break;
+            }
+            case Ldif::Err:
+                error(ERR_SLAVE_DEFINED,
+                      i18n("Invalid Ldif file in line %1.", ldif.lineNumber()));
+                return;
+            }
+        } while (ret != Ldif::MoreData);
+    } while (result > 0);
+
+    finished();
+}
+
+/**
+ * List the contents of a directory.
+ */
+void LDAPProtocol::listDir(const QUrl &_url)
+{
+    int ret, ret2, id, id2;
+    unsigned long total = 0;
+    QStringList att, saveatt;
+    LdapUrl usrc(_url), usrc2;
+    bool critical = true;
+    bool isSub = (usrc.extension(QStringLiteral("x-dir"), critical) == QLatin1String("sub"));
+
+//Reactivate it
+    //qCDebug(KLDAP_LOG) << "listDir(" << _url << ")";
+
+    changeCheck(usrc);
+    if (!mConnected) {
+        finished();
+        return;
+    }
+    usrc2 = usrc;
+
+    saveatt = usrc.attributes();
+    // look up the entries
+    if (isSub) {
+        att.append(QStringLiteral("dn"));
+        usrc.setAttributes(att);
+    }
+    if (_url.query().isEmpty()) {
+        usrc.setScope(LdapUrl::One);
+    }
+
+    if ((id = mOp.search(usrc.dn(), usrc.scope(), usrc.filter(), usrc.attributes())) == -1) {
+        LDAPErr();
+        return;
+    }
+
+    usrc.setAttributes(QStringList() << QLatin1String(""));
+    usrc.setExtension(QStringLiteral("x-dir"), QStringLiteral("base"));
+    // publish the results
+    UDSEntry uds;
+
+    while (true) {
+        ret = mOp.waitForResult(id, -1);
+        if (ret == -1 || mConn.ldapErrorCode() != KLDAP_SUCCESS) {
+            LDAPErr();
+            return;
+        }
+        if (ret == LdapOperation::RES_SEARCH_RESULT) {
+            break;
+        }
+        if (ret != LdapOperation::RES_SEARCH_ENTRY) {
+            continue;
+        }
+        qCDebug(KLDAP_LOG) << " ldap_result: " << ret;
+
+        total++;
+        uds.clear();
+
+        LDAPEntry2UDSEntry(mOp.object().dn(), uds, usrc);
+        listEntry(uds);
+//      processedSize( total );
+        qCDebug(KLDAP_LOG) << " total: " << total << " " << usrc.toDisplayString();
+
+        // publish the sub-directories (if dirmode==sub)
+        if (isSub) {
+            LdapDN dn = mOp.object().dn();
+            usrc2.setDn(dn);
+            usrc2.setScope(LdapUrl::One);
+            usrc2.setAttributes(saveatt);
+            usrc2.setFilter(usrc.filter());
+            qCDebug(KLDAP_LOG) << "search2 " << dn.toString();
+            if ((id2 = mOp.search(dn, LdapUrl::One, QString(), att)) != -1) {
+                while (true) {
+                    qCDebug(KLDAP_LOG) << " next result ";
+                    ret2 = mOp.waitForResult(id2, -1);
+                    if (ret2 == -1 || ret2 == LdapOperation::RES_SEARCH_RESULT) {
+                        break;
+                    }
+                    if (ret2 == LdapOperation::RES_SEARCH_ENTRY) {
+                        LDAPEntry2UDSEntry(dn, uds, usrc2, true);
+                        listEntry(uds);
+                        total++;
+                        mOp.abandon(id2);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+//  totalSize( total );
+
+    uds.clear();
+    // we are done
+    finished();
+}
diff --git a/kioslave/src/ldap/kio_ldap.h b/kioslave/src/ldap/kio_ldap.h
new file mode 100644
index 0000000..3e877fa
--- /dev/null
+++ b/kioslave/src/ldap/kio_ldap.h
@@ -0,0 +1,70 @@
+/*
+  Copyright (c) 2004-2007 Szombathelyi György <gyurco at freemail.hu>
+
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to deal
+  in the Software without restriction, including without limitation the rights
+  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+  copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included in
+  all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef __LDAP_H__
+#define __LDAP_H__
+
+#include <kio/slavebase.h>
+#include <kio/authinfo.h>
+
+#include <kldap/ldapdefs.h>
+#include <kldap/ldapurl.h>
+#include <kldap/ldapcontrol.h>
+#include <kldap/ldapconnection.h>
+#include <kldap/ldapdn.h>
+#include <kldap/ldapoperation.h>
+
+class LDAPProtocol : public KIO::SlaveBase
+{
+public:
+    LDAPProtocol(const QByteArray &protocol, const QByteArray &pool, const QByteArray &app);
+    virtual ~LDAPProtocol();
+
+    virtual void setHost(const QString &host, quint16 port,
+                         const QString &user, const QString &pass) Q_DECL_OVERRIDE;
+
+    void openConnection() Q_DECL_OVERRIDE;
+    void closeConnection() Q_DECL_OVERRIDE;
+
+    void get(const QUrl &url) Q_DECL_OVERRIDE;
+    void stat(const QUrl &url) Q_DECL_OVERRIDE;
+    void listDir(const QUrl &url) Q_DECL_OVERRIDE;
+    void del(const QUrl &url, bool isfile) Q_DECL_OVERRIDE;
+    void put(const QUrl &url, int permissions, KIO::JobFlags flags) Q_DECL_OVERRIDE;
+
+private:
+
+    KLDAP::LdapConnection mConn;
+    KLDAP::LdapOperation mOp;
+    KLDAP::LdapServer mServer;
+    bool mConnected;
+
+    void controlsFromMetaData(KLDAP::LdapControls &serverctrls,
+                              KLDAP::LdapControls &clientctrls);
+    void LDAPEntry2UDSEntry(const KLDAP::LdapDN &dn, KIO::UDSEntry &entry,
+                            const KLDAP::LdapUrl &usrc, bool dir = false);
+    int asyncSearch(KLDAP::LdapUrl &usrc, const QByteArray &cookie = "");
+
+    void LDAPErr(int err = KLDAP_SUCCESS);
+    void changeCheck(const KLDAP::LdapUrl &url);
+};
+
+#endif
diff --git a/kioslave/src/ldap/ldap.protocol b/kioslave/src/ldap/ldap.protocol
new file mode 100644
index 0000000..670ef7d
--- /dev/null
+++ b/kioslave/src/ldap/ldap.protocol
@@ -0,0 +1,17 @@
+[Protocol]
+exec=kf5/kio/ldap
+protocol=ldap
+input=none
+output=filesystem
+listing=Name,
+reading=true
+source=true
+writing=true
+#makedir=true
+deleting=true
+#linking=true
+#moving=true
+mimetype=text/plain
+determineMimetypeFromExtension=false
+X-DocPath=kioslave5/ldap/index.html
+Icon=office-address-book
diff --git a/kioslave/src/ldap/ldaps.protocol b/kioslave/src/ldap/ldaps.protocol
new file mode 100644
index 0000000..1952e81
--- /dev/null
+++ b/kioslave/src/ldap/ldaps.protocol
@@ -0,0 +1,17 @@
+[Protocol]
+exec=kf5/kio/ldap
+protocol=ldaps
+input=none
+output=filesystem
+listing=Name,
+reading=true
+source=true
+writing=true
+#makedir=true
+deleting=true
+#linking=true
+#moving=true
+mimetype=text/plain
+determineMimetypeFromExtension=false
+X-DocPath=kioslave5/ldap/index.html
+Icon=office-address-book
diff --git a/kldap.categories b/kldap.categories
new file mode 100644
index 0000000..f5262f5
--- /dev/null
+++ b/kldap.categories
@@ -0,0 +1,5 @@
+log_kldap kioslave (kldap)
+log_sieve kioslave (sieve)
+log_smtp kioslave (smtp)
+log_pop3 kioslave (pop3)
+


More information about the kde-doc-english mailing list