aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMontel Laurent <[email protected]>2016-04-03 20:38:27 +0200
committerMontel Laurent <[email protected]>2016-04-03 20:38:27 +0200
commitbe1dda4d707b81956431a09798c44a5b0f925cfc (patch)
tree86fd48755c03b82326876e940c5e5bda81eeeded
parent9def83a2c5d90b91a77f2e5b9cc88213f7716dff (diff)
Move kioslave ldap here
-rw-r--r--CMakeLists.txt12
-rw-r--r--kioslave/.krazy1
-rw-r--r--kioslave/.reviewboardrc5
-rw-r--r--kioslave/CMakeLists.txt4
-rw-r--r--kioslave/docs/CMakeLists.txt1
-rw-r--r--kioslave/docs/ldap/CMakeLists.txt3
-rw-r--r--kioslave/docs/ldap/index.docbook30
-rw-r--r--kioslave/kdepimlibs-kioslave.categories5
-rw-r--r--kioslave/src/CMakeLists.txt2
-rw-r--r--kioslave/src/common.h50
-rw-r--r--kioslave/src/ldap/CMakeLists.txt14
-rw-r--r--kioslave/src/ldap/Messages.sh2
-rw-r--r--kioslave/src/ldap/kio_ldap.cpp819
-rw-r--r--kioslave/src/ldap/kio_ldap.h70
-rw-r--r--kioslave/src/ldap/ldap.protocol17
-rw-r--r--kioslave/src/ldap/ldaps.protocol17
-rw-r--r--kldap.categories5
17 files changed, 1056 insertions, 1 deletions
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 <[email protected]>
+
+ 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 <[email protected]>
+
+ 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 <[email protected]>
+
+ 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)
+