[126340] trunk/dports/kde/kdelibs4
nicos at macports.org
nicos at macports.org
Wed Oct 8 04:03:41 PDT 2014
Revision: 126340
https://trac.macports.org/changeset/126340
Author: nicos at macports.org
Date: 2014-10-08 04:03:41 -0700 (Wed, 08 Oct 2014)
Log Message:
-----------
kdelibs4: update to 4.13.3
add patches
review dependencies
Modified Paths:
--------------
trunk/dports/kde/kdelibs4/Portfile
Added Paths:
-----------
trunk/dports/kde/kdelibs4/files/patch-KdePreferences.diff
trunk/dports/kde/kdelibs4/files/patch-authBackends.diff
trunk/dports/kde/kdelibs4/files/patch-fixKCrash.diff
trunk/dports/kde/kdelibs4/files/patch-nativeDialogs.diff
Removed Paths:
-------------
trunk/dports/kde/kdelibs4/files/patch-cmake-modules-KDE4Macros.cmake.diff
Modified: trunk/dports/kde/kdelibs4/Portfile
===================================================================
--- trunk/dports/kde/kdelibs4/Portfile 2014-10-08 10:38:21 UTC (rev 126339)
+++ trunk/dports/kde/kdelibs4/Portfile 2014-10-08 11:03:41 UTC (rev 126340)
@@ -5,8 +5,7 @@
PortGroup kde4 1.1
name kdelibs4
-version 4.12.5
-revision 3
+version 4.13.3
categories kde kde4
maintainers nicos
license LGPL-2+ GPL-2+ BSD
@@ -18,8 +17,8 @@
use_xz yes
distname kdelibs-${version}
-checksums rmd160 aa0bb8fb44d6c49ddd8787c4cb79c1f1bdd331b8 \
- sha256 9711c3a3d29387dc8b40425cc2957e9f1f2d747d83e9e0213bb8ff6638e68e09
+checksums rmd160 8db76ec77ed09d180223fb3a37b38e8ca8798d75 \
+ sha256 d291b4bc159a3f686ad93ff3dfbe90a0a7e33600357e8390c84154ec050efc82
#No binary links to openssl libraries, apart from libkio.dylib at
#runtime if required. As libkio.dylib code is purely LGPL, there is no
@@ -29,14 +28,12 @@
depends_build-append port:flex port:gmake port:docbook-xsl-ns
depends_lib-append port:bzip2 port:zlib \
- port:soprano port:cyrus-sasl2 \
+ port:soprano \
port:strigi port:gettext \
port:pcre port:shared-mime-info \
- lib:libgif:giflib port:tiff \
+ lib:libgif:giflib \
port:jpeg port:libpng \
port:jasper port:openexr \
- port:expat port:libart_lgpl \
- port:libidn port:libiconv \
path:lib/pkgconfig/glib-2.0.pc:glib2 \
port:openssl port:enchant \
port:aspell port:aspell-dict-en \
@@ -45,8 +42,9 @@
port:libxml2 port:libxslt \
port:dbusmenu-qt port:docbook-xml \
port:docbook-xsl port:grantlee \
- port:kerberos5 \
- port:shared-desktop-ontologies
+ port:kerberos5 port:bison \
+ port:shared-desktop-ontologies \
+ port:perl5
# the aspell dictionaries are just files
depends_skip_archcheck aspell-dict-en
@@ -59,8 +57,10 @@
#add-bundles-to-path: improve support for KIO slaves by adding a search path
#kapplications-raster: ensures that kde applications start in raster (faster) mode, but also provides a switch for non-working applications
#removeFindFlex: remove FindFlex.cmake which may hide the working one of cmake (ticket #44119)
-#patch-cmake-modules-FindKDE4-Internal.cmake: Fixes zlib detection (see ticket #24128)
-#patch-cmake-modules-KDE4Macros.cmake: Ensures that compiled objects are properly detected during build (see ticket #43720)
+#cmake-modules-FindKDE4-Internal.cmake: Fixes zlib detection (see ticket #24128)
+#fixKCrash: Fix issues in the KDE reporting system on OSX (see https://git.reviewboard.kde.org/r/119497/, committed upstream)
+#nativeDialogs: Use native mac dialogs (see https://reviewboard.kde.org/r/119243/)
+#KdePreferences: Handles menus to be closer to standard Mac layout (see https://reviewboard.kde.org/r/120149/)
patchfiles workaround-kdeinit4-crash.patch \
avoid-kwindowinfo-destructor.patch \
@@ -69,7 +69,9 @@
patch-kapplications-raster.diff \
patch-removeFindFlex.diff \
patch-cmake-modules-FindKDE4-Internal.cmake.diff \
- patch-cmake-modules-KDE4Macros.cmake.diff
+ patch-fixKCrash.diff \
+ patch-nativeDialogs.diff \
+ patch-KdePreferences.diff
patch.pre_args -p1
@@ -144,6 +146,12 @@
To start it run the following command:
launchctl load -w ${startup_root}/Library/LaunchAgents/org.macports.kdecache.plist"
+#patch-authBackends: make possible to use OS X keychain through kwallet (see https://git.reviewboard.kde.org/r/119838/, shipped)
+variant osxkeychain description {kwallet uses the OSX KeyChain} {
+ configure.args-append -DMAC_USE_OSXKEYCHAIN:BOOL=ON
+ patchfiles-append patch-authBackends.diff
+}
+
variant no_root description {Run the kde cache agent as MacPorts install user.} {
pre-fetch {
if { ${install.user}=="root" || ${install.group}=="wheel" } {
Added: trunk/dports/kde/kdelibs4/files/patch-KdePreferences.diff
===================================================================
--- trunk/dports/kde/kdelibs4/files/patch-KdePreferences.diff (rev 0)
+++ trunk/dports/kde/kdelibs4/files/patch-KdePreferences.diff 2014-10-08 11:03:41 UTC (rev 126340)
@@ -0,0 +1,113 @@
+diff -ur kdelibs-4.13.3-orig/kdeui/actions/kaction.cpp kdelibs-4.13.3/kdeui/actions/kaction.cpp
+--- kdelibs-4.13.3-orig/kdeui/actions/kaction.cpp 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kdeui/actions/kaction.cpp 2014-09-20 23:58:07.000000000 +0900
+@@ -142,11 +142,52 @@
+ d->init(this);
+ }
+
++#ifdef Q_OS_MAC
++
++#include <QMenuBar>
++#include <kaboutdata.h>
++
++static void setTextWithCorrectMenuRole( KAction *action, const QString &text )
++{
++ // texts containing "config, options, setup, settings or preferences" will get PreferencesRole
++ // from Qt unless they have a role set. We prevent that, because KDE has its own way of
++ // defining a the application preferences menu ("Configure <appName>") which should go under the OS X Preferences menu.
++ // But when a KAction is created with the standard preferences title ("Configure <appName>..."), this action
++ // is set to PreferencesRole .
++ // The compare actions using QMenuBar::tr are copied from Qt's own qmenu_mac.mm :
++ action->setText(text);
++ const KAboutData *aboutData = KGlobal::mainComponent().aboutData();
++ QString appName = i18n( "%1...", (aboutData) ? aboutData->programName() : qApp->applicationName() );
++ if( text.startsWith(QMenuBar::tr("Config").toLower()) || text.startsWith( "&" % QMenuBar::tr("Config").toLower()) ){
++ if( text.endsWith(appName) ){
++ kDebug() << "### Setting QAction::PreferencesRole from" << action->menuRole() << "for menuAction with text" << text;
++ action->setMenuRole(QAction::PreferencesRole);
++ }
++ else{
++ kDebug() << "### Setting QAction::NoRole from" << action->menuRole() << "for menuAction with text" << text;
++ action->setMenuRole(QAction::NoRole);
++ }
++ }
++ else if( text.contains(QMenuBar::tr("Options").toLower())
++ || text.contains(QMenuBar::tr("Setup").toLower())
++ || text.contains(QMenuBar::tr("Settings").toLower())
++ || text.contains(QMenuBar::tr("Preferences").toLower())
++ ){
++ kDebug() << "### Setting QAction::NoRole from" << action->menuRole() << "for menuAction with text" << text;
++ action->setMenuRole(QAction::NoRole);
++ }
++}
++#endif //Q_OS_MAC
++
+ KAction::KAction(const QString &text, QObject *parent)
+ : QWidgetAction(parent), d(new KActionPrivate)
+ {
+ d->init(this);
++#ifdef Q_OS_MAC
++ setTextWithCorrectMenuRole(this, text);
++#else
+ setText(text);
++#endif
+ }
+
+ KAction::KAction(const KIcon &icon, const QString &text, QObject *parent)
+@@ -154,7 +195,11 @@
+ {
+ d->init(this);
+ setIcon(icon);
++#ifdef Q_OS_MAC
++ setTextWithCorrectMenuRole(this, text);
++#else
+ setText(text);
++#endif
+ }
+
+ KAction::~KAction()
+diff -ur kdelibs-4.13.3-orig/kdeui/notifications/kstatusnotifieritem.cpp kdelibs-4.13.3/kdeui/notifications/kstatusnotifieritem.cpp
+--- kdelibs-4.13.3-orig/kdeui/notifications/kstatusnotifieritem.cpp 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kdeui/notifications/kstatusnotifieritem.cpp 2014-09-20 23:58:14.000000000 +0900
+@@ -683,6 +683,9 @@
+
+ return false;
+ }
++#else
++ Q_UNUSED(pos);
++ Q_UNUSED(perform);
+ #endif
+
+ return true;
+@@ -722,6 +725,10 @@
+ {
+ }
+
++#ifdef Q_OS_MAC
++# include <kconfiggroup.h>
++#endif
++
+ void KStatusNotifierItemPrivate::init(const QString &extraId)
+ {
+ // Ensure that closing the last KMainWindow doesn't exit the application
+@@ -745,8 +752,20 @@
+
+ //create a default menu, just like in KSystemtrayIcon
+ KMenu *m = new KMenu(associatedWidget);
++#ifdef Q_OS_MAC
++ // emulate addTitle/setTitle by adding an inactive menu item.
++ titleAction = m->addAction( qApp->windowIcon(), KGlobal::mainComponent().aboutData()->programName() );
++ titleAction->setEnabled(false);
++ titleAction->setIconVisibleInMenu(true);
++ m->addAction( titleAction );
++ m->addSeparator();
++ kDebug() << "### Added SystemTray titleAction=" << titleAction;
++ kDebug() << "### SystemTray for app" << qApp << "=" << KGlobal::mainComponent().aboutData()->programName()
++ << "/" << KGlobal::caption() << "with icon" << qApp->windowIcon().name();
++#else
+ titleAction = m->addTitle(qApp->windowIcon(), KGlobal::caption());
+ m->setTitle(KGlobal::mainComponent().aboutData()->programName());
++#endif
+ q->setContextMenu(m);
+
+ KStandardAction::quit(q, SLOT(maybeQuit()), actionCollection);
Added: trunk/dports/kde/kdelibs4/files/patch-authBackends.diff
===================================================================
--- trunk/dports/kde/kdelibs4/files/patch-authBackends.diff (rev 0)
+++ trunk/dports/kde/kdelibs4/files/patch-authBackends.diff 2014-10-08 11:03:41 UTC (rev 126340)
@@ -0,0 +1,4535 @@
+diff -urN kdelibs-4.13.3-orig/kdecore/auth/backends/mac/AuthServicesBackend.cpp kdelibs-4.13.3/kdecore/auth/backends/mac/AuthServicesBackend.cpp
+--- kdelibs-4.13.3-orig/kdecore/auth/backends/mac/AuthServicesBackend.cpp 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kdecore/auth/backends/mac/AuthServicesBackend.cpp 2014-09-22 19:46:01.000000000 +0900
+@@ -1,5 +1,6 @@
+ /*
+ * Copyright (C) 2008 Nicola Gigante <nicola.gigante at gmail.com>
++* Modifications (C) 2014 René Bertin <rjvbertin at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+@@ -21,6 +22,7 @@
+ #include <Security/Security.h>
+
+ #include <QtCore/qplugin.h>
++#include <QtCore/QtCore>
+
+ namespace KAuth
+ {
+@@ -34,14 +36,35 @@
+ if (!s_authRef) {
+ AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &s_authRef);
+ }
+-
+ return s_authRef;
+ }
+
++static OSStatus GetActionRights(const QString &action, AuthorizationFlags flags, AuthorizationRef auth=NULL)
++{
++ AuthorizationItem item;
++ item.name = action.toUtf8();
++ item.valueLength = 0;
++ item.value = NULL;
++ item.flags = 0;
++
++ AuthorizationRights rights;
++ rights.count = 1;
++ rights.items = &item;
++
++ OSStatus result = AuthorizationCopyRights( (auth)? auth : authRef(),
++ &rights,
++ kAuthorizationEmptyEnvironment,
++ flags, NULL);
++ return result;
++}
++
++// On OS X, the suggestion is to make the helper grant the actual privilege. The app does instead a
++// "pre-authorization", that's equivalent to look at isCallerAuthorized() in policykit.
++// RJVB: grab the privilege from here, the client.
+ AuthServicesBackend::AuthServicesBackend()
+ : AuthBackend()
+ {
+- setCapabilities(AuthorizeFromHelperCapability | CheckActionExistenceCapability);
++ setCapabilities(AuthorizeFromClientCapability | CheckActionExistenceCapability);
+ }
+
+ void AuthServicesBackend::setupAction(const QString&)
+@@ -51,29 +74,24 @@
+
+ // On OS X, the suggestion is to make the helper grant the actual privilege. The app does instead a
+ // "pre-authorization", that's equivalent to look at isCallerAuthorized() in policykit.
++// RJVB: grab the privilege from here, the client.
+ Action::AuthStatus AuthServicesBackend::authorizeAction(const QString &action)
+ {
+- return actionStatus(action);
++ OSStatus result = GetActionRights( action, kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed );
++// qWarning() << "AuthServicesBackend::authorizeAction(" << action << ") AuthorizationCopyRights returned" << result;
++ switch (result) {
++ case errAuthorizationSuccess:
++ return Action::Authorized;
++ case errAuthorizationInteractionNotAllowed:
++ default:
++ return Action::Denied;
++ }
+ }
+
+ Action::AuthStatus AuthServicesBackend::actionStatus(const QString &action)
+ {
+- AuthorizationItem item;
+- item.name = action.toUtf8();
+- item.valueLength = 0;
+- item.value = NULL;
+- item.flags = 0;
+-
+- AuthorizationRights rights;
+- rights.count = 1;
+- rights.items = &item;
+-
+- OSStatus result = AuthorizationCopyRights(authRef(),
+- &rights,
+- kAuthorizationEmptyEnvironment,
+- kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize,
+- NULL);
+-
++ OSStatus result = GetActionRights( action, kAuthorizationFlagExtendRights | kAuthorizationFlagPreAuthorize );
++// qWarning() << "AuthServicesBackend::actionStatus(" << action << ") AuthorizationCopyRights returned" << result;
+ switch (result) {
+ case errAuthorizationSuccess:
+ return Action::Authorized;
+@@ -101,35 +119,28 @@
+
+ AuthorizationRef auth;
+
+- if (AuthorizationCreateFromExternalForm(&ext, &auth) != noErr)
++ if (AuthorizationCreateFromExternalForm(&ext, &auth) != noErr){
++// qWarning() << "AuthorizationCreateFromExternalForm(" << action << "," << callerID.constData() << ") failed";
+ return false;
++ }
+
+- AuthorizationItem item;
+- item.name = action.toUtf8();
+- item.valueLength = 0;
+- item.value = NULL;
+- item.flags = 0;
+-
+- AuthorizationRights rights;
+- rights.count = 1;
+- rights.items = &item;
+-
+- OSStatus result = AuthorizationCopyRights(auth,
+- &rights,
+- kAuthorizationEmptyEnvironment,
+- kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed,
+- NULL);
++ OSStatus result = GetActionRights( action, kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed,
++ auth);
+
+ AuthorizationFree(auth, kAuthorizationFlagDefaults);
++// qWarning() << "AuthServicesBackend::isCallerAuthorized(" << action << "," << callerID.constData() << ") AuthorizationCopyRights returned" << result;
+
+ return result == errAuthorizationSuccess;
+ }
+
++// RJVB: OS X doesn't distinguish between "action doesn't exist" and "action not allowed". So the
++// best thing we can do is return true and hope that the action will be created if it didn't exist...
+ bool AuthServicesBackend::actionExists(const QString& action)
+ {
+ OSStatus exists = AuthorizationRightGet(action.toUtf8(), NULL);
++// qWarning() << "AuthServicesBackend::actionExists(" << action << ") AuthorizationRightGet returned" << exists;
+
+- return exists == errAuthorizationSuccess;
++ return true;//exists == errAuthorizationSuccess;
+ }
+
+ }; // namespace KAuth
+diff -urN kdelibs-4.13.3-orig/kdecore/auth/kauthaction.cpp kdelibs-4.13.3/kdecore/auth/kauthaction.cpp
+--- kdelibs-4.13.3-orig/kdecore/auth/kauthaction.cpp 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kdecore/auth/kauthaction.cpp 2014-09-22 19:46:01.000000000 +0900
+@@ -356,6 +356,13 @@
+ return executeActions(QList<Action>() << *this, NULL, helperID) ?
+ ActionReply::SuccessReply : ActionReply::AuthorizationDeniedReply;
+ } else {
++#if defined(Q_OS_MACX) || defined(__APPLE__) || defined(__MACH__)
++ if( BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability ){
++ // RJVB: authorisation through DBus seems to be flaky (at least when using the OSX keychain ... maybe because DBus
++ // isn't built with Keychain support in MacPorts?)
++ return ActionReply::SuccessReply;
++ }
++#endif //APPLE
+ if (hasHelper()) {
+ // Perform the pre auth here
+ if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) {
+diff -urN kdelibs-4.13.3-orig/kdeui/CMakeLists.txt kdelibs-4.13.3/kdeui/CMakeLists.txt
+--- kdelibs-4.13.3-orig/kdeui/CMakeLists.txt 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kdeui/CMakeLists.txt 2014-09-22 19:46:10.000000000 +0900
+@@ -309,11 +309,12 @@
+
+ if (Q_WS_MAC AND MAC_USE_OSXKEYCHAIN)
+ FIND_LIBRARY(SECURITY_LIBRARY Security)
+- set(kdeui_LIB_SRCS ${kdeui_LIB_SRCS} util/kwallet_mac.cpp)
++ set(kdeui_LIB_SRCS ${kdeui_LIB_SRCS} util/kwallet_mac.cpp util/qosxkeychain.cpp)
++ add_definitions(-DMAC_USE_OSXKEYCHAIN)
++ else(Q_WS_MAC AND MAC_USE_OSXKEYCHAIN)
++ set(kdeui_LIB_SRCS ${kdeui_LIB_SRCS} util/kwallet.cpp)
+ else(Q_WS_MAC AND MAC_USE_OSXKEYCHAIN)
+- set(kdeui_LIB_SRCS ${kdeui_LIB_SRCS} util/kwallet.cpp)
+-else(Q_WS_MAC AND MAC_USE_OSXKEYCHAIN)
+- set(kdeui_LIB_SRCS ${kdeui_LIB_SRCS} util/kwallet.cpp)
++ set(kdeui_LIB_SRCS ${kdeui_LIB_SRCS} util/kwallet.cpp)
+ endif(Q_WS_MAC AND MAC_USE_OSXKEYCHAIN)
+
+ if(NOT WINCE)
+diff -urN kdelibs-4.13.3-orig/kdeui/tests/CMakeLists.txt kdelibs-4.13.3/kdeui/tests/CMakeLists.txt
+--- kdelibs-4.13.3-orig/kdeui/tests/CMakeLists.txt 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kdeui/tests/CMakeLists.txt 2014-09-22 19:46:28.000000000 +0900
+@@ -7,6 +7,7 @@
+ # The alternative (which requires Qt>=4.6) is #include <QTestGui>
+ add_definitions(-DQT_GUI_LIB)
+
++option(MAC_USE_OSXKEYCHAIN "On OS X, use the keychain as backend for kwallet, instead of kwalletd.")
+
+ MACRO(KDEUI_UNIT_TESTS)
+ FOREACH(_testname ${ARGN})
+@@ -154,6 +155,11 @@
+ kpixmapsequenceoverlaypaintertest
+ )
+
++if (Q_WS_MAC AND MAC_USE_OSXKEYCHAIN)
++ set_source_files_properties(kwallettest.cpp PROPERTIES
++ COMPILE_FLAGS -DMAC_USE_OSXKEYCHAIN)
++endif(Q_WS_MAC AND MAC_USE_OSXKEYCHAIN)
++
+ if (NOT KDE_NO_DEPRECATED)
+ KDEUI_EXECUTABLE_TESTS(
+ keditlistboxtest
+diff -urN kdelibs-4.13.3-orig/kdeui/tests/kwallettest.cpp kdelibs-4.13.3/kdeui/tests/kwallettest.cpp
+--- kdelibs-4.13.3-orig/kdeui/tests/kwallettest.cpp 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kdeui/tests/kwallettest.cpp 2014-09-22 19:46:28.000000000 +0900
+@@ -32,11 +32,12 @@
+
+ void KWalletTest::testWallet()
+ {
+- QString testWallet = "kdewallet";
++ QString testWallet = "kwallettestWallet";
+ QString testFolder = "wallettestfolder";
+ QString testKeys[] = { "testKey", "account-302948", "\\", "/abc",
+ "a at b.c" };
+ QByteArray testValues[] = { "test", "@(!§\"%&", "", ".test", "\\" };
++ QMap<QString,QString> pwmap;
+ int numTests = 5;
+
+ // Start kdeinit4, so that the wallet damon is started in the background
+@@ -49,15 +50,24 @@
+
+ // open
+ Wallet *wallet = Wallet::openWallet( testWallet, w->winId(), Wallet::Synchronous );
+- if ( wallet == 0 )
+- kDebug() << "Couldn't open the wallet. Maybe the wallet daemon is not running?";
++ if ( wallet == 0 ){
++ kWarning() << "Couldn't open the wallet. Maybe the wallet daemon is not running?";
++ }
++ else{
++ kWarning() << "Opened wallet" << wallet->walletName();
++ }
+ QVERIFY( wallet != 0 );
+ QVERIFY( Wallet::isOpen( testWallet ) );
++ kWarning() << "Wallet list:" << Wallet::walletList();
++
++ // check on a couple of existing items, preferably at least 1 "internet account" and 1 "application password"
++ // OSXKeychain::readEntry( "existing name", "existing account", &value, NULL, NULL )
+
+ // create folder
+ wallet->createFolder( testFolder );
+ QVERIFY( wallet->hasFolder( testFolder ) );
+ wallet->setFolder( testFolder );
++ kWarning() << "Wallet's folder list:" << wallet->folderList();
+ QVERIFY( wallet->currentFolder() == testFolder );
+ QVERIFY( wallet->folderList().contains( testFolder ) );
+
+@@ -70,10 +80,36 @@
+ QVERIFY( readEntry == testValues[i] );
+ }
+
++ pwmap[QString("Bugzilla_login")] = QString("bugs at kde.org");
++ pwmap[QString("Bugzilla_password")] = QString("buggyPassw0rd");
++ kWarning() << "pwmap=" << pwmap;
++
++ QMap<QString,QString> v;
++ QVERIFY( !wallet->writeMap( "https://bugs.kde.org/#", pwmap ) );
++ QVERIFY( wallet->hasEntry("https://bugs.kde.org/#") );
++ QVERIFY( !wallet->readMap( "https://bugs.kde.org/#", v ) );
++ QVERIFY( v == pwmap );
++ // do it again
++ QVERIFY( !wallet->writeMap( "https://bugs.kde.org/#", pwmap ) );
++ QVERIFY( wallet->hasEntry("https://bugs.kde.org/#") );
++ QVERIFY( !wallet->readMap( "https://bugs.kde.org/#", v ) );
++ QVERIFY( v == pwmap );
++
++ QVERIFY( wallet->entryType( testKeys[0] ) == Wallet::Stream );
++ QVERIFY( wallet->entryType( "https://bugs.kde.org/#" ) == Wallet::Map );
++
++ QVERIFY( !wallet->renameEntry( "https://bugs.kde.org/#", "kdeBugs" ) );
++ QVERIFY( wallet->hasEntry("kdeBugs") );
++ QVERIFY( !wallet->readMap( "kdeBugs", v ) );
++ QVERIFY( v == pwmap );
++
+ // close
+ wallet->sync();
+- Wallet::closeWallet( "kdewallet", true );
+- QVERIFY( !Wallet::isOpen( "kdewallet" ) );
++ QStringList l = wallet->entryList();
++ kWarning() << "Entry list:" << l;
++ QVERIFY( l.size() == 6 );
++ Wallet::closeWallet( testWallet, true );
++ QVERIFY( !Wallet::isOpen( testWallet ) );
+
+ // test for key - closed wallet
+ for ( int i = 0; i < 5; i++ ) {
+@@ -108,13 +144,21 @@
+ QVERIFY( readEntry == testValues[i] );
+ }
+
++ // remove those many test keys
++ for ( int i = 0; i < numTests; i++ ) {
++ QVERIFY( !wallet->removeEntry( testKeys[i] ) );
++ }
++
++#ifndef MAC_USE_OSXKEYCHAIN
+ // delete folder
+ wallet->removeFolder( testFolder );
+ QVERIFY( !wallet->hasFolder( testFolder ) );
++#endif
+
+ // close
+- Wallet::closeWallet( "kdewallet", true );
+- QVERIFY( !Wallet::isOpen( "kdewallet" ) );
++ Wallet::closeWallet( testWallet, true );
++ QVERIFY( !Wallet::isOpen( testWallet ) );
++ QVERIFY( !Wallet::deleteWallet( testWallet ) );
+ }
+
+ QTEST_KDEMAIN(KWalletTest, GUI)
+diff -urN kdelibs-4.13.3-orig/kdeui/util/kwallet_mac.cpp kdelibs-4.13.3/kdeui/util/kwallet_mac.cpp
+--- kdelibs-4.13.3-orig/kdeui/util/kwallet_mac.cpp 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kdeui/util/kwallet_mac.cpp 2014-09-22 19:46:50.000000000 +0900
+@@ -1,8 +1,10 @@
+-/* This file is part of the KDE project
++/* @file kwallet_mac.cpp
++ * This file is part of the KDE project
+ *
+ * Copyright (C) 2002-2004 George Staikos <staikos at kde.org>
+ * Copyright (C) 2008 Michael Leupold <lemma at confuego.org>
+ * Copyright (C) 2010 Frank Osterfeld <osterfeld at kde.org>
++ * Copyright (C) 2014 René Bertin <rjvbertin at gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+@@ -26,7 +28,9 @@
+ #include <kdeversion.h>
+ #include <QtGui/QApplication>
+ #include <QtCore/QPointer>
++#include <QtCore/QSharedMemory>
+ #include <QtGui/QWidget>
++#include <QtCore/QTimer>
+ #include <ktoolinvocation.h>
+
+ #include <kglobal.h>
+@@ -36,11 +40,13 @@
+
+ #include <cassert>
+
+-#include <Carbon/Carbon.h>
+-#include <Security/Security.h>
+-#include <Security/SecKeychain.h>
++#include <sys/param.h>
+
+-using namespace KWallet;
++#include "qosxkeychain.h"
++
++#ifdef USE_KWALLETD
++# include "kwallet_interface.h"
++#endif
+
+ typedef QMap<QString, QString> StringStringMap;
+ Q_DECLARE_METATYPE(StringStringMap)
+@@ -49,30 +55,151 @@
+ typedef QMap<QString, QByteArray> StringByteArrayMap;
+ Q_DECLARE_METATYPE(StringByteArrayMap)
+
+-namespace {
+- template <typename T>
+- struct CFReleaser {
+- explicit CFReleaser( const T& r ) : ref( r ) {}
+- ~CFReleaser() { CFRelease( ref ); }
+- T ref;
+- };
+-}
++#include <mach/mach.h>
++#include <mach/mach_time.h>
++#include <mach/mach_init.h>
++#include <sys/sysctl.h>
+
+-static QString asQString( CFStringRef sr ) {
+- return QString::fromLatin1( CFStringGetCStringPtr( sr, NULL ) ); //TODO Latin1 correct?
+-}
++#define IDLETIMER_DEBUG
+
+-static QString errorString( OSStatus s ) {
+- const CFReleaser<CFStringRef> ref( SecCopyErrorMessageString( s, NULL ) );
+- return asQString( ref.ref );
++template <typename T>
++class QSharedValue : public QSharedMemory
++{
++public:
++ virtual bool attachOrCreate(QSharedMemory::AccessMode mode=QSharedMemory::ReadWrite)
++ { bool ret = attach(mode);
++ if( !ret ){
++ ret = create( sizeof(T), mode );
++ }
++ return ret;
++ }
++ virtual bool attachOrCreate(QString &key, QSharedMemory::AccessMode mode=QSharedMemory::ReadWrite)
++ {
++ setKey(key);
++ bool ret = attach(mode);
++ if( !ret ){
++ ret = create( sizeof(T), mode );
++ }
++ return ret;
++ }
++ virtual bool attachOrCreate(QString &key, T *initVal, QSharedMemory::AccessMode mode=QSharedMemory::ReadWrite)
++ {
++ setKey(key);
++ bool ret = attach(mode);
++ if( !ret ){
++ ret = create( sizeof(T), mode );
++ if( ret ){
++ setValue(initVal);
++ }
++ }
++ return ret;
++ }
++ virtual bool attachOrCreate(QString &key, T initVal, QSharedMemory::AccessMode mode=QSharedMemory::ReadWrite)
++ {
++ return attachOrCreate( key, &initVal, mode );
++ }
++ virtual bool getValue(T &val)
++ {
++ if( lock() ){
++ val = *((T*)data());
++ return unlock();
++ }
++ else{
++ return false;
++ }
++ }
++ virtual bool setValue(T *newVal)
++ {
++ if( lock() ){
++ *((T*)data()) = *newVal;
++ return unlock();
++ }
++ else{
++ return false;
++ }
++ }
++ virtual bool setValue(T newVal)
++ {
++ return setValue(&newVal);
++ }
++};
++
++static mach_timebase_info_data_t sTimebaseInfo;
++static double calibrator= 0, startTime = 0;
++static QSharedValue<double> sharedStartTime;
++
++double HRTime_Time()
++{
++ return mach_absolute_time() * calibrator - startTime;
+ }
+
+-static bool isError( OSStatus s, QString* errMsg ) {
+- if ( errMsg )
+- *errMsg = errorString( s );
+- return s != 0;
++void init_HRTime()
++{
++ if( !calibrator ){
++ mach_timebase_info(&sTimebaseInfo);
++ /* go from absolute time units to seconds (the timebase is calibrated in nanoseconds): */
++ calibrator= 1e-9 * sTimebaseInfo.numer / sTimebaseInfo.denom;
++ QString key = "kwalletWallClockStartTime";
++ sharedStartTime.attachOrCreate( key, HRTime_Time() );
++ sharedStartTime.getValue(startTime);
++ qDebug() << "init_HRTime(): connected to kwalletWallClock at t=" << HRTime_Time();
++ }
+ }
+
++namespace KWallet
++{
++
++#ifdef USE_KWALLETD
++class KWalletDLauncher
++{
++public:
++ KWalletDLauncher();
++ ~KWalletDLauncher();
++ org::kde::KWallet &getInterface();
++
++ org::kde::KWallet *m_wallet;
++ KConfigGroup m_cgroup;
++};
++
++K_GLOBAL_STATIC(KWalletDLauncher, walletLauncher)
++static const char s_kwalletdServiceName[] = "org.kde.kwalletd";
++
++#else
++
++/**
++ * maps wallet name to a map of app name to <wallet,pid> instances
++ */
++// deserialising the WalletUsersList from a QDataStream works only for a few WalletInstancePtr types
++// We could store the Wallet* in a QByteArray, but that would make it impossible to dump the WalletUsersList
++// to the console for debugging. So we use a QVariant.
++typedef QVariant WalletInstancePtr;
++// typedef QList<QPair<WalletInstancePtr,pid_t> > WalletUsersListEntryData;
++class WalletUsersListEntryData : public QList<QPair<WalletInstancePtr,pid_t> >
++{
++public:
++ static WalletUsersListEntryData create(QPair<WalletInstancePtr,pid_t> &head)
++ {
++ WalletUsersListEntryData self;
++ self.clear();
++ self.append(head);
++ return self;
++ }
++ static WalletUsersListEntryData create(QPair<WalletInstancePtr,pid_t> head)
++ {
++ WalletUsersListEntryData self;
++ self.clear();
++ self.append(head);
++ return self;
++ }
++};
++
++typedef QMap<QString,WalletUsersListEntryData> WalletUsersListEntry;
++typedef QMap<QString,WalletUsersListEntry> WalletUsersList;
++static WalletUsersList walletUsers;
++
++#endif //USE_KWALLETD
++
++
+ static QString appid()
+ {
+ KComponentData cData = KGlobal::mainComponent();
+@@ -86,27 +213,8 @@
+ return qApp->applicationName();
+ }
+
+-static OSStatus removeEntryImplementation(const QString& walletName, const QString& key) {
+- const QByteArray serviceName( walletName.toUtf8() );
+- const QByteArray accountName( key.toUtf8() );
+- SecKeychainItemRef itemRef;
+- QString errMsg;
+- OSStatus result = SecKeychainFindGenericPassword( NULL, serviceName.size(), serviceName.constData(), accountName.size(), accountName.constData(), NULL, NULL, &itemRef );
+- if ( isError( result, &errMsg ) ) {
+- qWarning() << "Could not retrieve password:" << qPrintable(errMsg);
+- return result;
+- }
+- const CFReleaser<SecKeychainItemRef> itemReleaser( itemRef );
+- result = SecKeychainItemDelete( itemRef );
+- if ( isError( result, &errMsg ) ) {
+- qWarning() << "Could not delete password:" << qPrintable(errMsg);
+- return result;
+- }
+- return result;
+-}
+-
+-
+-const QString Wallet::LocalWallet() {
++/*static*/ const QString Wallet::LocalWallet()
++{
+ KConfigGroup cfg(KSharedConfig::openConfig("kwalletrc")->group("Wallet"));
+ if (!cfg.readEntry("Use One Wallet", true)) {
+ QString tmp = cfg.readEntry("Local Wallet", "localwallet");
+@@ -123,7 +231,8 @@
+ return tmp;
+ }
+
+-const QString Wallet::NetworkWallet() {
++/*static*/ const QString Wallet::NetworkWallet()
++{
+ KConfigGroup cfg(KSharedConfig::openConfig("kwalletrc")->group("Wallet"));
+
+ QString tmp = cfg.readEntry("Default Wallet", "kdewallet");
+@@ -133,132 +242,440 @@
+ return tmp;
+ }
+
+-const QString Wallet::PasswordFolder() {
++/*static*/ const QString Wallet::PasswordFolder()
++{
+ return "Passwords";
+ }
+
+-const QString Wallet::FormDataFolder() {
++/*static*/ const QString Wallet::FormDataFolder()
++{
+ return "Form Data";
+ }
+
+-class Wallet::WalletPrivate
++static QStringList getUsersFromRegistry(QString &name)
++{ QString app = appid();
++ QStringList users;
++ users.clear();
++ if( walletUsers.contains(name) ){
++ WalletUsersListEntry entry = walletUsers[name];
++ for( WalletUsersListEntry::const_iterator it = entry.constBegin() ; it != entry.constEnd() ; ++it ){
++ if( !it.value().isEmpty() ){
++ users.append(it.key());
++ }
++ }
++ }
++ return users;
++}
++
++static void removeFromRegistry( QString app, QString &name, WalletUsersListEntryData &entries )
++{
++ for( WalletUsersListEntryData::const_iterator it = entries.constBegin() ; it != entries.constEnd() ; ++it ){
++ QPair<WalletInstancePtr,pid_t> wdat = *it;
++ if( walletUsers.contains(name) && walletUsers[name].contains(app) ){
++ WalletUsersListEntry entry = walletUsers[name];
++ WalletUsersListEntryData appInstances = entry[app];
++ if( appInstances.contains(wdat) ){
++ appInstances.removeAll(wdat);
++ qDebug() << "removing application instance" << wdat << "from registry";
++ }
++ if( appInstances.isEmpty() ){
++ entry.remove(app);
++ qDebug() << "removing application" << app << "from registry";
++ }
++ else{
++ entry[app] = appInstances;
++ }
++ if( entry[app].isEmpty() ){
++ walletUsers.remove(name);
++ qDebug() << "removing wallet" << name << "from registry";
++ }
++ else{
++ walletUsers[name] = entry;
++ }
++ }
++ }
++}
++
++#pragma mark ==== Wallet::WalletPrivate ====
++class Wallet::WalletPrivate : public OSXKeychain
+ {
+ public:
+- explicit WalletPrivate(const QString &n)
+- : name(n)
+- {}
++ explicit WalletPrivate(Wallet *wallet, const QString &n, int h)
++ : OSXKeychain(n, &isNew), q(wallet), handle(h)
++ , idleTimer(NULL), idleTimerTriggered(0), lastConfigCheckTime(-1)
++ {
++ isKDEChain = ( n == LocalWallet() || n == NetworkWallet() || n.contains( "wallet", Qt::CaseInsensitive ) );
++ if( !calibrator ){
++ init_HRTime();
++ }
++ if( isKDEChain ){
++ if( !lastAccessTime.attachOrCreate( (QString&)n, QSharedMemory::ReadWrite) ){
++ qDebug() << "Couldn't create shared lastAccessTime member for wallet" << n
++ << "; idle timeouts will be per-client. Error" << lastAccessTime.errorString();
++ }
++ handleIdleTiming(__FUNCTION__);
++ }
++ }
++ virtual ~WalletPrivate()
++ {
++ removeFromRegistry();
++ deleteIdleTimer();
++ }
++
++ void addToRegistry()
++ { QString app = appid();
++ QPair<WalletInstancePtr,pid_t> wdat = qMakePair(QVariant((qulonglong)q),getpid());
++ if( !walletUsers.contains(name) ){
++ // Unknown wallet name, so there ought not be an existing QMap<appName,walletInstanceList>
++ WalletUsersListEntryData detail;
++ detail.clear();
++ detail.append(wdat);
++ WalletUsersListEntry entry;
++ entry.clear();
++ entry[app] = detail;
++ walletUsers[name] = entry;
++ }
++ else{
++ WalletUsersListEntry entry = walletUsers[name];
++ WalletUsersListEntryData detail;
++ if( entry.contains(app) ){
++ detail = entry[app];
++ }
++ else{
++ detail.clear();
++ }
++ detail.append(wdat);
++ entry[app] = detail;
++ walletUsers[name] = entry;
++ }
++ QByteArray mapData;
++ QDataStream ds(&mapData, QIODevice::WriteOnly);
++ ds << walletUsers;
++ qDebug() << "@@@" << HRTime_Time() << "Added" << wdat << "for app" << app << "to wallet" << name << "in registry of len=" << mapData.length() << walletUsers;
++ }
++
++ void removeFromRegistry()
++ {
++ WalletUsersListEntryData entries = WalletUsersListEntryData::create(qMakePair(QVariant((qulonglong)q),getpid()));
++ KWallet::removeFromRegistry( appid(), name, entries );
++ }
++ QStringList getUsersFromRegistry()
++ {
++ return KWallet::getUsersFromRegistry(name);
++ }
++
++ virtual void close()
++ {
++// // close the keychain wallet but only if we get here through the kwalletmanager
++// // or TODO if wallets should be closed when the last client disconnects
++// // and we are the last client.
++// if( appid() == "KDE Wallet Manager" ){
++ deleteIdleTimer();
++ OSXKeychain::close();
++// }
++ }
++ OSStatus lock()
++ {
++ if( idleTimer ){
++ idleTimer->stop();
++ }
++ return Lock(reference());
++ }
+
+- // needed for compilation reasons
+- void walletServiceUnregistered() {
++ void walletServiceUnregistered()
++ {
++#ifdef USE_KWALLETD
++ if( handle >= 0 ){
++ q->slotWalletClosed(handle);
++ }
++#endif
+ }
+
+- QString name;
+- QString folder;
++ void deleteIdleTimer()
++ {
++ if( idleTimer ){
++ idleTimer->stop();
++ idleTimer->deleteLater();
++ idleTimer = NULL;
++ }
++ }
++ // This function is to be called at every operation that is supposed to launch or reset
++ // the idle timing.
++ void handleIdleTiming(const char *caller="", bool touchAccessTime=true)
++ {
++ if( !isKDEChain ){
++ return;
++ }
++ double now = HRTime_Time();
++ if( lastConfigCheckTime < 0 || (now - lastConfigCheckTime >= 10) ){
++ lastConfigCheckTime = now;
++ KConfigGroup cfg(KSharedConfig::openConfig("kwalletrc")->group("Wallet"));
++ if (cfg.readEntry("Close When Idle", true)) {
++ timeOut = cfg.readEntry( "Idle Timeout", ((int)0) );
++ if( caller && idleTimer ){
++ qDebug() << "###" << caller << "->handleIdleTiming: setting" << idleTimer << "for wallet" << name << "handle" << handle << "timeout to" << timeOut;
++ }
++ }
++ else{
++ timeOut = -1;
++ }
++ }
++ if( timeOut >= 0 ){
++ if( !idleTimer ){
++ idleTimer = new QTimer(0);
++ connect( idleTimer, SIGNAL(timeout()), this, SLOT(slotIdleTimedOut()), Qt::DirectConnection );
++ }
++ else{
++ idleTimer->stop();
++ }
++ // when the idle timer fires, the wallet is supposed to be closed. There is thus
++ // no reason to use a repeating timer.
++ idleTimer->setSingleShot(true);
++ if( touchAccessTime ){
++ if( !lastAccessTime.setValue(HRTime_Time()) ){
++ qDebug() << "Cannot set new lastAccessTime for wallet" << name << "error" << lastAccessTime.errorString();
++ }
++ }
++ idleTimer->start( timeOut * 60 * 1000 );
++ }
++ else{
++ timeOut = -1;
++ deleteIdleTimer();
++ }
++ }
++
++ void slotIdleTimedOut()
++ { double lastTime = 0;
++ // check the last time anyone accessed this wallet:
++ if( !lastAccessTime.getValue(lastTime) ){
++ qDebug() << "Cannot get lastAccessTime for wallet" << name << "error" << lastAccessTime.errorString();
++ }
++ // the time elapsed since that last access, in minutes:
++ double elapsed = (HRTime_Time() - lastTime) / 60;
++ #ifdef IDLETIMER_DEBUG
++ idleTimerTriggered += 1;
++ qDebug() << "###" << HRTime_Time() << appid() << "Idle timeout" << timeOut << "min. for" << q << name << "handle" << handle
++ << "; elapsed minutes=" << elapsed << "timer" << idleTimer << "triggered" << idleTimerTriggered << "times";
++ #endif //IDLETIMER_DEBUG
++ if( elapsed >= timeOut ){
++ // we have a true timeout, i.e. we didn't access the wallet in timeOut minutes, and no one else did either.
++ q->slotWalletClosed(handle);
++ }
++ else{
++ // false alarm, reset the timer, but there's no need to count this as an access!
++ handleIdleTiming(__FUNCTION__, false);
++ }
++ }
++
++public:
++ Wallet *q;
++ int handle;
++ bool isNew;
++ //! idle timeout in minutes
++ int timeOut;
++ QTimer *idleTimer;
++#ifdef IDLETIMER_DEBUG
++ size_t idleTimerTriggered;
++#endif
++ double lastConfigCheckTime;
++ QSharedValue<double> lastAccessTime;
+ };
+
+ Wallet::Wallet(int handle, const QString& name)
+- : QObject(0L), d(new WalletPrivate(name)) {
+- Q_UNUSED(handle);
++ : QObject(0L), d(new WalletPrivate(this, name, handle))
++{
++#ifdef USE_KWALLETD
++ QDBusServiceWatcher *watcher = new QDBusServiceWatcher(QString::fromLatin1(s_kwalletdServiceName), QDBusConnection::sessionBus(),
++ QDBusServiceWatcher::WatchForUnregistration, this);
++ connect(watcher, SIGNAL(serviceUnregistered(QString)),
++ this, SLOT(walletServiceUnregistered()));
++
++ connect(&walletLauncher->getInterface(), SIGNAL(walletClosed(int)), SLOT(slotWalletClosed(int)));
++ connect(&walletLauncher->getInterface(), SIGNAL(folderListUpdated(QString)), SLOT(slotFolderListUpdated(QString)));
++ connect(&walletLauncher->getInterface(), SIGNAL(folderUpdated(QString,QString)), SLOT(slotFolderUpdated(QString,QString)));
++ connect(&walletLauncher->getInterface(), SIGNAL(applicationDisconnected(QString,QString)), SLOT(slotApplicationDisconnected(QString,QString)));
++#else
++ d->addToRegistry();
++#endif // USE_KWALLETD
++ if( d->handle != handle ){
++ qDebug() << "Wallet::Wallet(" << name << ") handle changed from" << handle << "to" << d->handle;
++ }
+ }
+
+-Wallet::~Wallet() {
++Wallet::~Wallet()
++{
+ delete d;
+ }
+
+-
+-QStringList Wallet::walletList() {
++/*static*/ QStringList Wallet::walletList()
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ return walletLauncher->getInterface().wallets();
+ #else
+- return QStringList();
++ // RJVB: Mac OS X's Keychain supports multiple keychains, but they can only be accesses by full path, not
++ // found by name. That makes it cumbersome to map to multiple wallets when using only the wallet name.
++ // However, it would be perfectly possible to create OS X Keychains called Wallet::LocalWallet() and
++ // Wallet::NetworkWallet() in the equivalent of ~/.kde/share/apps/kwallet .
++ QStringList l;
++ OSXKeychain::KeychainList(l);
++ return l;
+ #endif
+ }
+
+
+-void Wallet::changePassword(const QString& name, WId w) {
++/*static*/ void Wallet::changePassword(const QString& name, WId w)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ if( w == 0 )
+ kDebug(285) << "Pass a valid window to KWallet::Wallet::changePassword().";
+ walletLauncher->getInterface().changePassword(name, (qlonglong)w, appid());
++#else
++ Q_UNUSED(w);
++ kWarning() << "Wallet::changePassword unimplemented '" << name << "'";
+ #endif
+ }
+
+
+-bool Wallet::isEnabled() {
++/*static*/ bool Wallet::isEnabled()
++{
+ //PENDING(frank) check
+ return true;
+ }
+
+
+-bool Wallet::isOpen(const QString& name) {
++/*static*/ bool Wallet::isOpen(const QString& name)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ return walletLauncher->getInterface().isOpen(name); // default is false
+ #else
+- return true;
++#ifdef USE_KWALLETD
++ walletLauncher->getInterface().isOpen(name);
++#endif // USE_KWALLETD
++ return OSXKeychain::IsOpen(name);
++#endif
++}
++
++bool Wallet::isOpen() const
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ return d->handle != -1;
++#else
++ d->handleIdleTiming(__FUNCTION__);
++
++#ifdef USE_KWALLETD
++ QDBusReply<bool> r = walletLauncher->getInterface().isOpen(d->name);
++#endif // USE_KWALLETD
++ return d->isOpen();
+ #endif
+ }
+
+
+-int Wallet::closeWallet(const QString& name, bool force) {
++/*static*/ int Wallet::closeWallet(const QString& name, bool force)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ QDBusReply<int> r = walletLauncher->getInterface().close(name, force);
+ return r.isValid() ? r : -1;
+ #else
+- return 0;
++ Q_UNUSED(force);
++#ifdef USE_KWALLETD
++ QDBusReply<int> r = walletLauncher->getInterface().close(name, force);
++#endif // USE_KWALLETD
++ // emit a signal that we just closed the wallet
++ Wallet(0, name).slotWalletClosed(0);
++ return OSXKeychain::IsOpen(name);
+ #endif
+ }
+
+
+-int Wallet::deleteWallet(const QString& name) {
++/*static*/ int Wallet::deleteWallet(const QString& name)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ QDBusReply<int> r = walletLauncher->getInterface().deleteWallet(name);
+ return r.isValid() ? r : -1;
+ #else
+- return -1;
++ return OSXKeychain::Destroy(name);
+ #endif
+ }
+
+
+-Wallet *Wallet::openWallet(const QString& name, WId w, OpenType ot) {
++/*static*/ Wallet *Wallet::openWallet(const QString& name, WId w, OpenType ot)
++{
+ Q_UNUSED(w);
+ Q_UNUSED(ot);
+- Wallet *wallet = new Wallet(-1, name);
+- QMetaObject::invokeMethod( wallet, "emitWalletOpened", Qt::QueuedConnection );
++ Wallet *wallet = new Wallet((int)w, name);
++ if( wallet ){
++#ifdef USE_KWALLETD
++ // connect the daemon's opened signal to the slot filtering the
++ // signals we need
++ connect(&walletLauncher->getInterface(), SIGNAL(walletAsyncOpened(int,int)),
++ wallet, SLOT(walletAsyncOpened(int,int)));
++#endif
++ OSStatus err = wallet->d->unLock();
++ if( !err && wallet->d->isKDEChain && wallet->d->isNew ){
++ wallet->d->setLockSettings( false, 0 );
++ }
++ kDebug() << "Opened wallet '" << name << "': " << wallet << " error=" << err;
++#ifdef USE_KWALLETD
++ wallet->emitWalletOpened();
++#else
++ QMetaObject::invokeMethod( wallet, "emitWalletOpened", Qt::QueuedConnection );
++#endif
++ }
+ return wallet;
+ }
+
+
+-bool Wallet::disconnectApplication(const QString& wallet, const QString& app) {
++/*static*/ bool Wallet::disconnectApplication(const QString& wallet, const QString& app)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ return walletLauncher->getInterface().disconnectApplication(wallet, app); // default is false
+ #else
+- return true;
++ kWarning() << "Wallet::disconnectApplication unimplemented, '" << app << "' from '" << wallet << "'"
++#ifdef USE_KWALLETD
++ << walletLauncher->getInterface().disconnectApplication(wallet, app)
++#endif // USE_KWALLETD
++ ;
++ // app disconnect is done/possible only when the app in question closes its wallet.
++ return false;
+ #endif
+ }
+
+
+-QStringList Wallet::users(const QString& name) {
++/*static*/ QStringList Wallet::users(const QString& name)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ return walletLauncher->getInterface().users(name); // default is QStringList()
+ #else
+- return QStringList();
++#ifdef USE_KWALLETD
++ QStringList ul = walletLauncher->getInterface().users(name);
++ kWarning() << "Wallet::users unimplemented, '" << name << "'" << ul;
++ return ul;
++#else
++ return KWallet::getUsersFromRegistry((QString&)name);
++#endif // USE_KWALLETD
+ #endif
+ }
+
+
+-int Wallet::sync() {
++int Wallet::sync()
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ if (d->handle == -1) {
+ return -1;
+ }
+
+- walletLauncher->getInterface().sync(d->handle, appid());
+ #endif
++ d->handleIdleTiming(__FUNCTION__);
++
++#ifdef USE_KWALLETD
++ walletLauncher->getInterface().sync(d->handle, appid());
++#endif // USE_KWALLETD
+ return 0;
+ }
+
+
+-int Wallet::lockWallet() {
++int Wallet::lockWallet()
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ if (d->handle == -1) {
+ return -1;
+@@ -271,26 +688,25 @@
+ if (r.isValid()) {
+ return r;
+ }
++#else
++ d->currentService.clear();
++ d->handle = -1;
+ #endif
+- return -1;
++ d->lock();
++ emit walletClosed();
++ return 1;
+ }
+
+
+-const QString& Wallet::walletName() const {
++const QString& Wallet::walletName() const
++{
++ d->handleIdleTiming(__FUNCTION__);
+ return d->name;
+ }
+
+
+-bool Wallet::isOpen() const {
+-#ifdef OSX_KEYCHAIN_PORT_DISABLED
+- return d->handle != -1;
+-#else
+- return true;
+-#endif
+-}
+-
+-
+-void Wallet::requestChangePassword(WId w) {
++void Wallet::requestChangePassword(WId w)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ if( w == 0 )
+ kDebug(285) << "Pass a valid window to KWallet::Wallet::requestChangePassword().";
+@@ -299,11 +715,16 @@
+ }
+
+ walletLauncher->getInterface().changePassword(d->name, (qlonglong)w, appid());
++#else
++ Q_UNUSED(w);
++ d->handleIdleTiming(__FUNCTION__);
++ kWarning() << "Wallet::requestChangePassword unimplemented '" << d->name << "'";
+ #endif
+ }
+
+
+-void Wallet::slotWalletClosed(int handle) {
++void Wallet::slotWalletClosed(int handle)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ if (d->handle == handle) {
+ d->handle = -1;
+@@ -311,11 +732,25 @@
+ d->name.clear();
+ emit walletClosed();
+ }
++#else
++// kWarning() << "Wallet::slotWalletClosed unimplemented '" << d->name << "'";
++ if( d->handle == handle ){
++ d->handle = -1;
++ d->currentService.clear();
++ kDebug() << "Wallet::slotWalletClosed '" << d->name << "'";
++ // TODO remove ourselves from the WalletUsersList here!
++ d->close();
++ emit walletClosed();
++ }
++ else{
++ qDebug() << "Wallet::slotWalletClosed '" << d->name << "' ignored because handle" << d->handle << "!=" << handle;
++ }
+ #endif
+ }
+
+
+-QStringList Wallet::folderList() {
++QStringList Wallet::folderList()
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ if (d->handle == -1) {
+ return QStringList();
+@@ -324,12 +759,14 @@
+ QDBusReply<QStringList> r = walletLauncher->getInterface().folderList(d->handle, appid());
+ return r;
+ #else
+- return QStringList();
++ d->handleIdleTiming(__FUNCTION__);
++ return QStringList(d->folderList());
+ #endif
+ }
+
+
+-QStringList Wallet::entryList() {
++QStringList Wallet::entryList()
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ if (d->handle == -1) {
+ return QStringList();
+@@ -338,12 +775,17 @@
+ QDBusReply<QStringList> r = walletLauncher->getInterface().entryList(d->handle, d->folder, appid());
+ return r;
+ #else
+- return QStringList();
++ d->handleIdleTiming(__FUNCTION__);
++
++ QStringList r = QStringList();
++ d->itemList(r);
++ return r;
+ #endif
+ }
+
+
+-bool Wallet::hasFolder(const QString& f) {
++bool Wallet::hasFolder(const QString& f)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ if (d->handle == -1) {
+ return false;
+@@ -352,12 +794,15 @@
+ QDBusReply<bool> r = walletLauncher->getInterface().hasFolder(d->handle, f, appid());
+ return r; // default is false
+ #else
+- return true;
++ d->handleIdleTiming(__FUNCTION__);
++ d->folderList();
++ return d->serviceList.contains(f);
+ #endif
+ }
+
+
+-bool Wallet::createFolder(const QString& f) {
++bool Wallet::createFolder(const QString& f)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ if (d->handle == -1) {
+ return false;
+@@ -370,12 +815,14 @@
+
+ return true; // folder already exists
+ #else
+- return true;
++ d->handleIdleTiming(__FUNCTION__);
++ return setFolder(f);
+ #endif
+ }
+
+
+-bool Wallet::setFolder(const QString& f) {
++bool Wallet::setFolder(const QString &f)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ bool rc = false;
+
+@@ -397,12 +844,22 @@
+
+ return rc;
+ #else
++ d->handleIdleTiming(__FUNCTION__);
++ // act as if we just changed folders even if we have no such things; the property
++ // is stored as the ServiceItemAttr (which shows up as the "Where" field in the Keychain Utility).
++ if( f.size() == 0 ){
++ d->currentService.clear();
++ }
++ else{
++ d->currentService = QString(f);
++ }
+ return true;
+ #endif
+ }
+
+
+-bool Wallet::removeFolder(const QString& f) {
++bool Wallet::removeFolder(const QString& f)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ if (d->handle == -1) {
+ return false;
+@@ -415,34 +872,38 @@
+
+ return r; // default is false
+ #else
++ d->handleIdleTiming(__FUNCTION__);
++ kWarning() << "Wallet::removeFolder unimplemented (returns true) '" << d->name << "'";
++ if( d->currentService == f ){
++ d->currentService.clear();
++ }
+ return true;
+ #endif
+ }
+
+
+-const QString& Wallet::currentFolder() const {
++const QString& Wallet::currentFolder() const
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
+ return d->folder;
++#else
++ d->handleIdleTiming(__FUNCTION__);
++ return d->currentService;
++#endif
+ }
+
+
+-int Wallet::readEntry(const QString& key, QByteArray& value) {
+- const QByteArray serviceName( walletName().toUtf8() );
+- const QByteArray accountName( key.toUtf8() );
+- UInt32 passwordSize = 0;
+- void* passwordData = 0;
+- QString errMsg;
+- if ( isError( SecKeychainFindGenericPassword( NULL, serviceName.size(), serviceName.constData(), accountName.size(), accountName.constData(), &passwordSize, &passwordData, NULL ), &errMsg ) ) {
+- qWarning() << "Could not retrieve password:" << qPrintable(errMsg);
+- return -1;
+- }
+-
+- value = QByteArray( reinterpret_cast<const char*>( passwordData ), passwordSize );
+- SecKeychainItemFreeContent( NULL, passwordData );
+- return 0;
++int Wallet::readEntry(const QString &key, QByteArray &value)
++{ OSStatus err;
++ d->handleIdleTiming(__FUNCTION__);
++ err = d->readItem( key, &value, NULL );
++ kDebug() << "Wallet::readEntry '" << key << "' from wallet " << d->name << ", error=" << ((err)? -1 : 0);
++ return (err)? -1 : 0;
+ }
+
+
+-int Wallet::readEntryList(const QString& key, QMap<QString, QByteArray>& value) {
++int Wallet::readEntryList(const QString& key, QMap<QString, QByteArray>& value)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ registerTypes();
+
+@@ -464,12 +925,17 @@
+
+ return rc;
+ #else
++ Q_UNUSED(key);
++ Q_UNUSED(value);
++ d->handleIdleTiming(__FUNCTION__);
++ kWarning() << "Wallet::readEntryList unimplemented (returns -1) '" << d->name << "'";
+ return -1;
+ #endif
+ }
+
+
+-int Wallet::renameEntry(const QString& oldName, const QString& newName) {
++int Wallet::renameEntry(const QString& oldName, const QString& newName)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ int rc = -1;
+
+@@ -484,25 +950,33 @@
+
+ return rc;
+ #else
+- return -1;
++ d->handleIdleTiming(__FUNCTION__);
++ return d->renameItem( oldName, newName );
+ #endif
+ }
+
+
+-int Wallet::readMap(const QString& key, QMap<QString,QString>& value) {
++int Wallet::readMap(const QString &key, QMap<QString,QString> &value)
++{
++ d->handleIdleTiming(__FUNCTION__);
++
+ QByteArray v;
+- const int ret = readEntry( key, v );
+- if ( ret != 0 )
++ const int ret = (d->readItem( key, &v, NULL ))? -1 : 0;
++ if( ret != 0 ){
+ return ret;
+- if ( !v.isEmpty() ) {
+- QDataStream ds( &v, QIODevice::ReadOnly );
++ }
++ if( !v.isEmpty() ){
++ QByteArray w = QByteArray::fromBase64(v);
++ QDataStream ds( &w, QIODevice::ReadOnly );
+ ds >> value;
+ }
++ kDebug() << "Wallet::readMap '" << key << "' from wallet " << d->name << ", error=0";
+ return 0;
+ }
+
+
+-int Wallet::readMapList(const QString& key, QMap<QString, QMap<QString, QString> >& value) {
++int Wallet::readMapList(const QString& key, QMap<QString, QMap<QString, QString> >& value)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ registerTypes();
+
+@@ -530,81 +1004,119 @@
+
+ return rc;
+ #else
++ Q_UNUSED(key);
++ Q_UNUSED(value);
++ d->handleIdleTiming(__FUNCTION__);
++ kWarning() << "Wallet::readMapList unimplemented (returns -1) '" << d->name << "'";
+ return -1;
+ #endif
+ }
+
+
+-int Wallet::readPassword(const QString& key, QString& value) {
++int Wallet::readPassword(const QString& key, QString& value)
++{
++ d->handleIdleTiming(__FUNCTION__);
++
+ QByteArray ba;
+- const int ret = readEntry( key, ba );
+- if ( ret == 0 )
++ const int ret = (d->readItem( key, &ba, NULL ))? -1 : 0;
++ if ( ret == 0 ){
+ value = QString::fromUtf8( ba.constData() );
++ }
++ kDebug() << "Wallet::readPassword '" << key << "' from wallet " << d->name << ", error=" << ret;
+ return ret;
+ }
+
+
+-int Wallet::readPasswordList(const QString& key, QMap<QString, QString>& value) {
++int Wallet::readPasswordList(const QString& key, QMap<QString, QString>& value)
++{
++ Q_UNUSED(key);
++ Q_UNUSED(value);
++ d->handleIdleTiming(__FUNCTION__);
++ kWarning() << "Wallet::readPasswordList unimplemented (returns -1) '" << d->name << "'";
+ return -1;
+ }
+
+-static OSStatus writeEntryImplementation( const QString& walletName, const QString& key, const QByteArray& value ) {
+- const QByteArray serviceName( walletName.toUtf8() );
+- const QByteArray accountName( key.toUtf8() );
+- QString errMsg;
+- OSStatus err = SecKeychainAddGenericPassword( NULL, serviceName.size(), serviceName.constData(), accountName.size(), accountName.constData(), value.size(), value.constData(), NULL );
+- if (err == errSecDuplicateItem) {
+- err = removeEntryImplementation( walletName, key );
+- if ( isError( err, &errMsg ) ) {
+- kWarning() << "Could not delete old key in keychain for replacing: " << qPrintable(errMsg);
+- return err;
+- }
+- }
+- if ( isError( err, &errMsg ) ) {
+- kWarning() << "Could not store password in keychain: " << qPrintable(errMsg);
+- return err;
+- }
+- kDebug() << "Succesfully written out key:" << key;
+- return err;
+-
+-}
+-
+-int Wallet::writeEntry(const QString& key, const QByteArray& password, EntryType entryType) {
+- Q_UNUSED( entryType )
+- return writeEntryImplementation( walletName(), key, password );
++int Wallet::writeEntry(const QString& key, const QByteArray& password )
++{ int ret;
++ d->handleIdleTiming(__FUNCTION__);
++ ret = d->writeItem( key, password );
++ kDebug() << "wrote entry '" << key << "' to wallet " << d->name << ", error=" << ret;
++ return ret;
+ }
+
++int Wallet::writeEntry(const QString& key, const QByteArray& password, EntryType entryType)
++{
++ d->handleIdleTiming(__FUNCTION__);
+
+-int Wallet::writeEntry(const QString& key, const QByteArray& value) {
+- return writeEntryImplementation( walletName(), key, value );
++ OSXKeychain::EntryType entryCode;
++ switch( entryType ){
++ case Wallet::Password:
++ entryCode = OSXKeychain::Password;
++ break;
++ case Wallet::Map:
++ entryCode = OSXKeychain::Map;
++ break;
++ case Wallet::Stream:
++ entryCode = OSXKeychain::Stream;
++ break;
++ default:
++ entryCode = OSXKeychain::Unknown;
++ break;
++ }
++ int ret = d->writeItem( key, password, &entryCode );
++ kDebug() << "wrote entry '" << key << "' of type=" << (int) entryType << "to wallet " << d->name << ", error=" << ret;
++ return ret;
+ }
+
++int Wallet::writeMap(const QString& key, const QMap<QString,QString>& value)
++{
++ d->handleIdleTiming(__FUNCTION__);
+
+-int Wallet::writeMap(const QString& key, const QMap<QString,QString>& value) {
+ QByteArray mapData;
+ QDataStream ds(&mapData, QIODevice::WriteOnly);
+ ds << value;
+- return writeEntry( key, mapData );
++ OSXKeychain::EntryType etype = OSXKeychain::Map;
++ int ret = d->writeItem( key, mapData.toBase64(),
++ "This is a KDE Wallet::Map item. Its password\n"
++ "cannot be read in the OS X Keychain Utility.\n"
++ "Use KDE's own kwalletmanager for that.", &etype );
++ kDebug() << "wrote map '" << key << "' to wallet " << d->name << ", error=" << ret;
++ return ret;
+ }
+
+
+-int Wallet::writePassword(const QString& key, const QString& value) {
+- return writeEntry( key, value.toUtf8() );
++int Wallet::writePassword(const QString &key, const QString& value)
++{ OSXKeychain::EntryType etype;
++
++ d->handleIdleTiming(__FUNCTION__);
++ etype = OSXKeychain::Password;
++ int ret = d->writeItem( key, value.toUtf8(), &etype );
++ kDebug() << "wrote password '" << key << "' to wallet " << d->name << ", error=" << ret;
++ return ret;
+ }
+
+
+-bool Wallet::hasEntry(const QString& key) {
+- const QByteArray serviceName( walletName().toUtf8() );
+- const QByteArray accountName( key.toUtf8() );
+- return !isError( SecKeychainFindGenericPassword( NULL, serviceName.size(), serviceName.constData(), accountName.size(), accountName.constData(), NULL, NULL, NULL ), 0 );
++bool Wallet::hasEntry(const QString &key)
++{ bool ret;
++
++ d->handleIdleTiming(__FUNCTION__);
++ ret = d->hasItem( key, NULL );
++ kDebug() << "wallet '" << d->name << "'" << ((ret)? " has" : " does not have") << " entry '" << key << "'";
++ return ret;
+ }
+
+-int Wallet::removeEntry(const QString& key) {
+- return removeEntryImplementation( walletName(), key );
++int Wallet::removeEntry(const QString& key)
++{ int ret;
++
++ d->handleIdleTiming(__FUNCTION__);
++ ret = d->removeItem( key );
++ kDebug() << "removed entry '" << key << "' from wallet " << d->name << ", error=" << ret;
++ return ret;
+ }
+
+
+-Wallet::EntryType Wallet::entryType(const QString& key) {
++Wallet::EntryType Wallet::entryType(const QString& key)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ int rc = 0;
+
+@@ -619,94 +1131,208 @@
+
+ return static_cast<EntryType>(rc);
+ #else
++ d->handleIdleTiming(NULL);
++
++ // RJVB: a priori, entries are always 'password' on OS X, but since we also do use them for storing
++ // maps, it may be best to return Wallet::Unknown to leave some uncertainty and not mislead our caller.
++ OSXKeychain::EntryType etype;
++ if( !d->itemType( key, &etype ) ){
++ switch( etype ){
++ case OSXKeychain::Password:
++ return Wallet::Password;
++ break;
++ case OSXKeychain::Map:
++ return Wallet::Map;
++ break;
++ case OSXKeychain::Stream:
++ return Wallet::Stream;
++ break;
++ }
++ }
+ return Wallet::Unknown;
+ #endif
+ }
+
+
+-void Wallet::slotFolderUpdated(const QString& wallet, const QString& folder) {
++void Wallet::slotFolderUpdated(const QString& wallet, const QString& folder)
++{
+ if (d->name == wallet) {
++ kDebug() << "emit folderUpdated" << folder;
+ emit folderUpdated(folder);
+ }
+ }
+
+
+-void Wallet::slotFolderListUpdated(const QString& wallet) {
++void Wallet::slotFolderListUpdated(const QString& wallet)
++{
+ if (d->name == wallet) {
++ kDebug() << "emit foldeListrUpdated" << wallet;
+ emit folderListUpdated();
+ }
+ }
+
+
+-void Wallet::slotApplicationDisconnected(const QString& wallet, const QString& application) {
+-#ifdef OSX_KEYCHAIN_PORT_DISABLED
+- if (d->handle >= 0
++void Wallet::slotApplicationDisconnected(const QString& wallet, const QString& application)
++{
++#ifdef USE_KWALLETD
++ qDebug() << "slotApplicationDisconnected(" << wallet << "," << application << "); handle="
++ << d->handle << "name=" << d->name << "appid=" << appid();
++ if( d->handle >= 0
+ && d->name == wallet
+- && application == appid()) {
++ && application == appid()
++ ){
+ slotWalletClosed(d->handle);
+ }
+-#endif
++#else
++ Q_UNUSED(wallet);
++ Q_UNUSED(application);
++#endif //USE_KWALLETD
+ }
+
+-void Wallet::walletAsyncOpened(int tId, int handle) {
++void Wallet::walletAsyncOpened(int tId, int handle)
++{
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ // ignore responses to calls other than ours
+ if (d->transactionId != tId || d->handle != -1) {
+ return;
+ }
+-
++
+ // disconnect the async signal
+ disconnect(this, SLOT(walletAsyncOpened(int,int)));
+-
++
+ d->handle = handle;
+ emit walletOpened(handle > 0);
++#else
++ Q_UNUSED(tId);
++ d->handleIdleTiming(__FUNCTION__);
++#ifdef USE_KWALLETD
++ // disconnect the async signal
++ disconnect(this, SLOT(walletAsyncOpened(int,int)));
++ qDebug() << "walletAsyncOpened: emit walletOpened(true), handle=" << handle;
++ emit walletOpened(true);
++#endif // USE_KWALLETD
++ d->handle = handle;
+ #endif
+ }
+
+-void Wallet::emitWalletAsyncOpenError() {
++void Wallet::emitWalletAsyncOpenError()
++{
++ d->handleIdleTiming(__FUNCTION__);
++ kDebug() << "emitWalletAsyncOpenError: emit walletOpened(false)";
+ emit walletOpened(false);
+ }
+
+-void Wallet::emitWalletOpened() {
+- emit walletOpened(true);
++void Wallet::emitWalletOpened()
++{
++ d->handleIdleTiming(__FUNCTION__);
++ kDebug() << "emitWalletOpened: emit walletOpened(true)";
++ emit walletOpened(true);
+ }
+
+
+-bool Wallet::folderDoesNotExist(const QString& wallet, const QString& folder)
++/*static*/ bool Wallet::folderDoesNotExist(const QString& wallet, const QString& folder)
+ {
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ QDBusReply<bool> r = walletLauncher->getInterface().folderDoesNotExist(wallet, folder);
+ return r;
+ #else
+- return false;
++ bool ret = true;
++ if( Wallet::walletList().contains(wallet) ){
++ ret = !Wallet(-1, wallet).hasFolder(folder);
++ }
++ return ret;
+ #endif
+ }
+
+
+-bool Wallet::keyDoesNotExist(const QString& wallet, const QString& folder, const QString& key)
++/*static*/ bool Wallet::keyDoesNotExist(const QString& wallet, const QString& folder, const QString& key)
+ {
+ #ifdef OSX_KEYCHAIN_PORT_DISABLED
+ QDBusReply<bool> r = walletLauncher->getInterface().keyDoesNotExist(wallet, folder, key);
+ return r;
+ #else
+- return false;
++ bool ret = true;
++ if( Wallet::walletList().contains(wallet) ){
++ Wallet w(-1, wallet);
++ if( w.hasFolder(folder) ){
++ ret = !w.hasEntry(key);
++ }
++ }
++ return ret;
+ #endif
+ }
+
+ void Wallet::slotCollectionStatusChanged(int status)
+ {
++ Q_UNUSED(status);
++ d->handleIdleTiming(__FUNCTION__);
++ kWarning() << "Wallet::slotCollectionStatusChanged unimplemented '" << d->name << "' status=" << status;
+ }
+
+ void Wallet::slotCollectionDeleted()
+ {
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
+ d->folder.clear();
+- d->name.clear();
++#else
++ d->currentService.clear();
++#endif
++ kDebug() << "Wallet::slotCollectionDeleted: closing private data '" << d->name;
++ // TODO remove ourselves from the WalletUsersList here!
++ d->close();
+ emit walletClosed();
+ }
+
+
+-void Wallet::virtual_hook(int, void*) {
++void Wallet::virtual_hook(int, void*)
++{
+ //BASE::virtual_hook( id, data );
+ }
+
++#ifdef USE_KWALLETD
++KWalletDLauncher::KWalletDLauncher()
++ : m_wallet(0),
++ m_cgroup(KSharedConfig::openConfig("kwalletrc", KConfig::NoGlobals)->group("Wallet"))
++{
++ m_wallet = new org::kde::KWallet(QString::fromLatin1(s_kwalletdServiceName), "/modules/kwalletd", QDBusConnection::sessionBus());
++}
++
++KWalletDLauncher::~KWalletDLauncher()
++{
++ delete m_wallet;
++}
++
++org::kde::KWallet &KWalletDLauncher::getInterface()
++{
++ Q_ASSERT(m_wallet != 0);
++
++ // check if kwalletd is already running
++ if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1(s_kwalletdServiceName)))
++ {
++ // not running! check if it is enabled.
++ bool walletEnabled = m_cgroup.readEntry("Enabled", true);
++ if (walletEnabled) {
++ // wallet is enabled! try launching it
++ QString error;
++ int ret = KToolInvocation::startServiceByDesktopPath("kwalletd.desktop", QStringList(), &error);
++ if (ret > 0){
++ kError(285) << "Couldn't start kwalletd: " << error << endl;
++ }
++
++ if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QString::fromLatin1(s_kwalletdServiceName))) {
++ kDebug(285) << "The kwalletd service is still not registered";
++ } else {
++ kDebug(285) << "The kwalletd service has been registered";
++ }
++ } else {
++ kError(285) << "The kwalletd service has been disabled";
++ }
++ }
++
++ return *m_wallet;
++}
++#endif //USE_KWALLETD
++
++} // namespace KWallet
++
++#include "qosxkeychain.moc"
+ #include "kwallet.moc"
+diff -urN kdelibs-4.13.3-orig/kdeui/util/kwallet_mac.cpp.orig kdelibs-4.13.3/kdeui/util/kwallet_mac.cpp.orig
+--- kdelibs-4.13.3-orig/kdeui/util/kwallet_mac.cpp.orig 1970-01-01 09:00:00.000000000 +0900
++++ kdelibs-4.13.3/kdeui/util/kwallet_mac.cpp.orig 2014-09-22 19:46:10.000000000 +0900
+@@ -0,0 +1,809 @@
++/* @file kwallet_mac.cpp
++ * This file is part of the KDE project
++ *
++ * Copyright (C) 2002-2004 George Staikos <staikos at kde.org>
++ * Copyright (C) 2008 Michael Leupold <lemma at confuego.org>
++ * Copyright (C) 2010 Frank Osterfeld <osterfeld at kde.org>
++ * Copyright (C) 2014 René Bertin <rjvbertin at gmail.com>
++ *
++ * 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 "kwallet.h"
++#include <ksharedconfig.h>
++#include <kdebug.h>
++#include <kdeversion.h>
++#include <QtGui/QApplication>
++#include <QtCore/QPointer>
++#include <QtGui/QWidget>
++#include <ktoolinvocation.h>
++
++#include <kglobal.h>
++#include <kcomponentdata.h>
++#include <kaboutdata.h>
++#include <kconfiggroup.h>
++
++#include <cassert>
++
++#include <sys/param.h>
++
++#include "qosxkeychain.h"
++
++using namespace KWallet;
++
++typedef QMap<QString, QString> StringStringMap;
++Q_DECLARE_METATYPE(StringStringMap)
++typedef QMap<QString, StringStringMap> StringToStringStringMapMap;
++Q_DECLARE_METATYPE(StringToStringStringMapMap)
++typedef QMap<QString, QByteArray> StringByteArrayMap;
++Q_DECLARE_METATYPE(StringByteArrayMap)
++
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++static QString appid()
++{
++ KComponentData cData = KGlobal::mainComponent();
++ if (cData.isValid()) {
++ const KAboutData* aboutData = cData.aboutData();
++ if (aboutData) {
++ return aboutData->programName();
++ }
++ return cData.componentName();
++ }
++ return qApp->applicationName();
++}
++#endif
++
++/*static*/ const QString Wallet::LocalWallet()
++{
++ KConfigGroup cfg(KSharedConfig::openConfig("kwalletrc")->group("Wallet"));
++ if (!cfg.readEntry("Use One Wallet", true)) {
++ QString tmp = cfg.readEntry("Local Wallet", "localwallet");
++ if (tmp.isEmpty()) {
++ return "localwallet";
++ }
++ return tmp;
++ }
++
++ QString tmp = cfg.readEntry("Default Wallet", "kdewallet");
++ if (tmp.isEmpty()) {
++ return "kdewallet";
++ }
++ return tmp;
++}
++
++/*static*/ const QString Wallet::NetworkWallet()
++{
++ KConfigGroup cfg(KSharedConfig::openConfig("kwalletrc")->group("Wallet"));
++
++ QString tmp = cfg.readEntry("Default Wallet", "kdewallet");
++ if (tmp.isEmpty()) {
++ return "kdewallet";
++ }
++ return tmp;
++}
++
++/*static*/ const QString Wallet::PasswordFolder()
++{
++ return "Passwords";
++}
++
++/*static*/ const QString Wallet::FormDataFolder()
++{
++ return "Form Data";
++}
++
++#pragma mark ==== Wallet::WalletPrivate ====
++class Wallet::WalletPrivate : public OSXKeychain
++{
++public:
++ explicit WalletPrivate(const QString &n)
++ : OSXKeychain(n)
++ {
++ isKDEChain = ( n == LocalWallet() || n == NetworkWallet() || n.contains( "wallet", Qt::CaseInsensitive ) );
++ }
++
++ // needed for compilation reasons
++ void walletServiceUnregistered()
++ {
++ }
++};
++
++Wallet::Wallet(int handle, const QString& name)
++ : QObject(0L), d(new WalletPrivate(name))
++{
++ Q_UNUSED(handle);
++}
++
++Wallet::~Wallet()
++{
++ delete d;
++}
++
++/*static*/ QStringList Wallet::walletList()
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ return walletLauncher->getInterface().wallets();
++#else
++ // RJVB: Mac OS X's Keychain supports multiple keychains, but they can only be accesses by full path, not
++ // found by name. That makes it cumbersome to map to multiple wallets when using only the wallet name.
++ // However, it would be perfectly possible to create OS X Keychains called Wallet::LocalWallet() and
++ // Wallet::NetworkWallet() in the equivalent of ~/.kde/share/apps/kwallet .
++ QStringList l;
++ OSXKeychain::KeychainList(l);
++ return l;
++#endif
++}
++
++
++/*static*/ void Wallet::changePassword(const QString& name, WId w)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ if( w == 0 )
++ kDebug(285) << "Pass a valid window to KWallet::Wallet::changePassword().";
++ walletLauncher->getInterface().changePassword(name, (qlonglong)w, appid());
++#else
++ Q_UNUSED(w);
++ kWarning() << "Wallet::changePassword unimplemented '" << name << "'";
++#endif
++}
++
++
++/*static*/ bool Wallet::isEnabled()
++{
++ //PENDING(frank) check
++ return true;
++}
++
++
++/*static*/ bool Wallet::isOpen(const QString& name)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ return walletLauncher->getInterface().isOpen(name); // default is false
++#else
++ return OSXKeychain::IsOpen(name);
++#endif
++}
++
++bool Wallet::isOpen() const
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ return d->handle != -1;
++#else
++ return d->isOpen();
++#endif
++}
++
++
++/*static*/ int Wallet::closeWallet(const QString& name, bool force)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ QDBusReply<int> r = walletLauncher->getInterface().close(name, force);
++ return r.isValid() ? r : -1;
++#else
++ Q_UNUSED(force);
++ return OSXKeychain::Lock(name);
++#endif
++}
++
++
++/*static*/ int Wallet::deleteWallet(const QString& name)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ QDBusReply<int> r = walletLauncher->getInterface().deleteWallet(name);
++ return r.isValid() ? r : -1;
++#else
++ return OSXKeychain::Destroy(name);
++#endif
++}
++
++
++/*static*/ Wallet *Wallet::openWallet(const QString& name, WId w, OpenType ot)
++{
++ Q_UNUSED(w);
++ Q_UNUSED(ot);
++ Wallet *wallet = new Wallet(-1, name);
++ QMetaObject::invokeMethod( wallet, "emitWalletOpened", Qt::QueuedConnection );
++ OSStatus err = wallet->d->unLock();
++ kDebug() << "Opened wallet '" << name << "': " << wallet << " error=" << err;
++ return wallet;
++}
++
++
++/*static*/ bool Wallet::disconnectApplication(const QString& wallet, const QString& app)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ return walletLauncher->getInterface().disconnectApplication(wallet, app); // default is false
++#else
++ kWarning() << "Wallet::disconnectApplication unimplemented, '" << app << "' from '" << wallet << "'";
++ return true;
++#endif
++}
++
++
++/*static*/ QStringList Wallet::users(const QString& name)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ return walletLauncher->getInterface().users(name); // default is QStringList()
++#else
++ kWarning() << "Wallet::users unimplemented, '" << name << "'";
++ return QStringList();
++#endif
++}
++
++
++int Wallet::sync()
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ if (d->handle == -1) {
++ return -1;
++ }
++
++ walletLauncher->getInterface().sync(d->handle, appid());
++#endif
++ return 0;
++}
++
++
++int Wallet::lockWallet()
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ if (d->handle == -1) {
++ return -1;
++ }
++
++ QDBusReply<int> r = walletLauncher->getInterface().close(d->handle, true, appid());
++ d->handle = -1;
++ d->folder.clear();
++ d->name.clear();
++ if (r.isValid()) {
++ return r;
++ }
++#else
++ d->currentService.clear();
++#endif
++ return d->lock();
++}
++
++
++const QString& Wallet::walletName() const
++{
++ return d->name;
++}
++
++
++void Wallet::requestChangePassword(WId w)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ if( w == 0 )
++ kDebug(285) << "Pass a valid window to KWallet::Wallet::requestChangePassword().";
++ if (d->handle == -1) {
++ return;
++ }
++
++ walletLauncher->getInterface().changePassword(d->name, (qlonglong)w, appid());
++#else
++ Q_UNUSED(w);
++ kWarning() << "Wallet::requestChangePassword unimplemented '" << d->name << "'";
++#endif
++}
++
++
++void Wallet::slotWalletClosed(int handle)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ if (d->handle == handle) {
++ d->handle = -1;
++ d->folder.clear();
++ d->name.clear();
++ emit walletClosed();
++ }
++#else
++ Q_UNUSED(handle);
++ kWarning() << "Wallet::slotWalletClosed unimplemented '" << d->name << "'";
++ d->currentService.clear();
++#endif
++}
++
++
++QStringList Wallet::folderList()
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ if (d->handle == -1) {
++ return QStringList();
++ }
++
++ QDBusReply<QStringList> r = walletLauncher->getInterface().folderList(d->handle, appid());
++ return r;
++#else
++ return QStringList(d->folderList());
++#endif
++}
++
++
++QStringList Wallet::entryList()
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ if (d->handle == -1) {
++ return QStringList();
++ }
++
++ QDBusReply<QStringList> r = walletLauncher->getInterface().entryList(d->handle, d->folder, appid());
++ return r;
++#else
++ QStringList r = QStringList();
++ d->itemList(r);
++ return r;
++#endif
++}
++
++
++bool Wallet::hasFolder(const QString& f)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ if (d->handle == -1) {
++ return false;
++ }
++
++ QDBusReply<bool> r = walletLauncher->getInterface().hasFolder(d->handle, f, appid());
++ return r; // default is false
++#else
++ d->folderList();
++ return d->serviceList.contains(f);
++#endif
++}
++
++
++bool Wallet::createFolder(const QString& f)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ if (d->handle == -1) {
++ return false;
++ }
++
++ if (!hasFolder(f)) {
++ QDBusReply<bool> r = walletLauncher->getInterface().createFolder(d->handle, f, appid());
++ return r;
++ }
++
++ return true; // folder already exists
++#else
++ return setFolder(f);
++#endif
++}
++
++
++bool Wallet::setFolder(const QString &f)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ bool rc = false;
++
++ if (d->handle == -1) {
++ return rc;
++ }
++
++ // Don't do this - the folder could have disappeared?
++#if 0
++ if (f == d->folder) {
++ return true;
++ }
++#endif
++
++ if (hasFolder(f)) {
++ d->folder = f;
++ rc = true;
++ }
++
++ return rc;
++#else
++ // act as if we just changed folders even if we have no such things; the property
++ // is stored as the ServiceItemAttr (which shows up as the "Where" field in the Keychain Utility).
++ if( f.size() == 0 ){
++ d->currentService.clear();
++ }
++ else{
++ d->currentService = QString(f);
++ }
++ return true;
++#endif
++}
++
++
++bool Wallet::removeFolder(const QString& f)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ if (d->handle == -1) {
++ return false;
++ }
++
++ QDBusReply<bool> r = walletLauncher->getInterface().removeFolder(d->handle, f, appid());
++ if (d->folder == f) {
++ setFolder(QString());
++ }
++
++ return r; // default is false
++#else
++ kWarning() << "Wallet::removeFolder unimplemented (returns true) '" << d->name << "'";
++ if( d->currentService == f ){
++ d->currentService.clear();
++ }
++ return true;
++#endif
++}
++
++
++const QString& Wallet::currentFolder() const
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ return d->folder;
++#else
++ return d->currentService;
++#endif
++}
++
++
++int Wallet::readEntry(const QString &key, QByteArray &value)
++{ OSStatus err = d->readItem( key, &value, NULL );
++ kDebug() << "Wallet::readEntry '" << key << "' from wallet " << d->name << ", error=" << ((err)? -1 : 0);
++ return (err)? -1 : 0;
++}
++
++
++int Wallet::readEntryList(const QString& key, QMap<QString, QByteArray>& value)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ registerTypes();
++
++ int rc = -1;
++
++ if (d->handle == -1) {
++ return rc;
++ }
++
++ QDBusReply<QVariantMap> r = walletLauncher->getInterface().readEntryList(d->handle, d->folder, key, appid());
++ if (r.isValid()) {
++ rc = 0;
++ // convert <QString, QVariant> to <QString, QByteArray>
++ const QVariantMap val = r.value();
++ for( QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it ) {
++ value.insert(it.key(), it.value().toByteArray());
++ }
++ }
++
++ return rc;
++#else
++ Q_UNUSED(key);
++ Q_UNUSED(value);
++ kWarning() << "Wallet::readEntryList unimplemented (returns -1) '" << d->name << "'";
++ return -1;
++#endif
++}
++
++
++int Wallet::renameEntry(const QString& oldName, const QString& newName)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ int rc = -1;
++
++ if (d->handle == -1) {
++ return rc;
++ }
++
++ QDBusReply<int> r = walletLauncher->getInterface().renameEntry(d->handle, d->folder, oldName, newName, appid());
++ if (r.isValid()) {
++ rc = r;
++ }
++
++ return rc;
++#else
++ return d->renameItem( oldName, newName );
++#endif
++}
++
++
++int Wallet::readMap(const QString &key, QMap<QString,QString> &value)
++{
++ QByteArray v;
++ const int ret = (d->readItem( key, &v, NULL ))? -1 : 0;
++ if( ret != 0 ){
++ return ret;
++ }
++ if( !v.isEmpty() ){
++ QByteArray w = QByteArray::fromBase64(v);
++ QDataStream ds( &w, QIODevice::ReadOnly );
++ ds >> value;
++ }
++ kDebug() << "Wallet::readMap '" << key << "' from wallet " << d->name << ", error=0";
++ return 0;
++}
++
++
++int Wallet::readMapList(const QString& key, QMap<QString, QMap<QString, QString> >& value)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ registerTypes();
++
++ int rc = -1;
++
++ if (d->handle == -1) {
++ return rc;
++ }
++
++ QDBusReply<QVariantMap> r =
++ walletLauncher->getInterface().readMapList(d->handle, d->folder, key, appid());
++ if (r.isValid()) {
++ rc = 0;
++ const QVariantMap val = r.value();
++ for( QVariantMap::const_iterator it = val.begin(); it != val.end(); ++it ) {
++ QByteArray mapData = it.value().toByteArray();
++ if (!mapData.isEmpty()) {
++ QDataStream ds(&mapData, QIODevice::ReadOnly);
++ QMap<QString,QString> v;
++ ds >> v;
++ value.insert(it.key(), v);
++ }
++ }
++ }
++
++ return rc;
++#else
++ Q_UNUSED(key);
++ Q_UNUSED(value);
++ kWarning() << "Wallet::readMapList unimplemented (returns -1) '" << d->name << "'";
++ return -1;
++#endif
++}
++
++
++int Wallet::readPassword(const QString& key, QString& value)
++{
++ QByteArray ba;
++ const int ret = (d->readItem( key, &ba, NULL ))? -1 : 0;
++ if ( ret == 0 ){
++ value = QString::fromUtf8( ba.constData() );
++ }
++ kDebug() << "Wallet::readPassword '" << key << "' from wallet " << d->name << ", error=" << ret;
++ return ret;
++}
++
++
++int Wallet::readPasswordList(const QString& key, QMap<QString, QString>& value)
++{
++ Q_UNUSED(key);
++ Q_UNUSED(value);
++ kWarning() << "Wallet::readPasswordList unimplemented (returns -1) '" << d->name << "'";
++ return -1;
++}
++
++int Wallet::writeEntry(const QString& key, const QByteArray& password )
++{ int ret = d->writeItem( key, password );
++ kDebug() << "wrote entry '" << key << "' to wallet " << d->name << ", error=" << ret;
++ return ret;
++}
++
++int Wallet::writeEntry(const QString& key, const QByteArray& password, EntryType entryType)
++{
++ OSXKeychain::EntryType entryCode;
++ switch( entryType ){
++ case Wallet::Password:
++ entryCode = OSXKeychain::Password;
++ break;
++ case Wallet::Map:
++ entryCode = OSXKeychain::Map;
++ break;
++ case Wallet::Stream:
++ entryCode = OSXKeychain::Stream;
++ break;
++ default:
++ entryCode = OSXKeychain::Unknown;
++ break;
++ }
++ int ret = d->writeItem( key, password, &entryCode );
++ kDebug() << "wrote entry '" << key << "' of type=" << (int) entryType << "to wallet " << d->name << ", error=" << ret;
++ return ret;
++}
++
++int Wallet::writeMap(const QString& key, const QMap<QString,QString>& value)
++{
++ QByteArray mapData;
++ QDataStream ds(&mapData, QIODevice::WriteOnly);
++ ds << value;
++ OSXKeychain::EntryType etype = OSXKeychain::Map;
++ int ret = d->writeItem( key, mapData.toBase64(),
++ "This is a KDE Wallet::Map item. Its password\n"
++ "cannot be read in the OS X Keychain Utility.\n"
++ "Use KDE's own kwalletmanager for that.", &etype );
++ kDebug() << "wrote map '" << key << "' to wallet " << d->name << ", error=" << ret;
++ return ret;
++}
++
++
++int Wallet::writePassword(const QString &key, const QString& value)
++{ OSXKeychain::EntryType etype = OSXKeychain::Password;
++ int ret = d->writeItem( key, value.toUtf8(), &etype );
++ kDebug() << "wrote password '" << key << "' to wallet " << d->name << ", error=" << ret;
++ return ret;
++}
++
++
++bool Wallet::hasEntry(const QString &key)
++{ bool ret = d->hasItem( key, NULL );
++ kDebug() << "wallet '" << d->name << "'" << ((ret)? " has" : " does not have") << " entry '" << key << "'";
++ return ret;
++}
++
++int Wallet::removeEntry(const QString& key)
++{ int ret = d->removeItem( key );
++ kDebug() << "removed entry '" << key << "' from wallet " << d->name << ", error=" << ret;
++ return ret;
++}
++
++
++Wallet::EntryType Wallet::entryType(const QString& key)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ int rc = 0;
++
++ if (d->handle == -1) {
++ return Wallet::Unknown;
++ }
++
++ QDBusReply<int> r = walletLauncher->getInterface().entryType(d->handle, d->folder, key, appid());
++ if (r.isValid()) {
++ rc = r;
++ }
++
++ return static_cast<EntryType>(rc);
++#else
++ // RJVB: a priori, entries are always 'password' on OS X, but since we also do use them for storing
++ // maps, it may be best to return Wallet::Unknown to leave some uncertainty and not mislead our caller.
++ OSXKeychain::EntryType etype;
++ if( !d->itemType( key, &etype ) ){
++ switch( etype ){
++ case OSXKeychain::Password:
++ return Wallet::Password;
++ break;
++ case OSXKeychain::Map:
++ return Wallet::Map;
++ break;
++ case OSXKeychain::Stream:
++ return Wallet::Stream;
++ break;
++ }
++ }
++ return Wallet::Unknown;
++#endif
++}
++
++
++void Wallet::slotFolderUpdated(const QString& wallet, const QString& folder)
++{
++ if (d->name == wallet) {
++ emit folderUpdated(folder);
++ }
++}
++
++
++void Wallet::slotFolderListUpdated(const QString& wallet)
++{
++ if (d->name == wallet) {
++ emit folderListUpdated();
++ }
++}
++
++
++void Wallet::slotApplicationDisconnected(const QString& wallet, const QString& application)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ if (d->handle >= 0
++ && d->name == wallet
++ && application == appid()) {
++ slotWalletClosed(d->handle);
++ }
++#else
++ Q_UNUSED(wallet);
++ Q_UNUSED(application);
++ kWarning() << "Wallet::slotApplicationDisconnected unimplemented '" << d->name << "'";
++#endif
++}
++
++void Wallet::walletAsyncOpened(int tId, int handle)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ // ignore responses to calls other than ours
++ if (d->transactionId != tId || d->handle != -1) {
++ return;
++ }
++
++ // disconnect the async signal
++ disconnect(this, SLOT(walletAsyncOpened(int,int)));
++
++ d->handle = handle;
++ emit walletOpened(handle > 0);
++#else
++ Q_UNUSED(tId);
++ Q_UNUSED(handle);
++ kWarning() << "Wallet::walletAsyncOpened unimplemented '" << d->name << "'";
++#endif
++}
++
++void Wallet::emitWalletAsyncOpenError()
++{
++ emit walletOpened(false);
++}
++
++void Wallet::emitWalletOpened()
++{
++ emit walletOpened(true);
++}
++
++
++bool Wallet::folderDoesNotExist(const QString& wallet, const QString& folder)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ QDBusReply<bool> r = walletLauncher->getInterface().folderDoesNotExist(wallet, folder);
++ return r;
++#else
++ bool ret = true;
++ if( Wallet::walletList().contains(wallet) ){
++ ret = !Wallet(-1, wallet).hasFolder(folder);
++ }
++ return ret;
++#endif
++}
++
++
++bool Wallet::keyDoesNotExist(const QString& wallet, const QString& folder, const QString& key)
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ QDBusReply<bool> r = walletLauncher->getInterface().keyDoesNotExist(wallet, folder, key);
++ return r;
++#else
++ bool ret = true;
++ if( Wallet::walletList().contains(wallet) ){
++ Wallet w(-1, wallet);
++ if( w.hasFolder(folder) ){
++ ret = !w.hasEntry(key);
++ }
++ }
++ return ret;
++#endif
++}
++
++void Wallet::slotCollectionStatusChanged(int status)
++{
++ Q_UNUSED(status);
++ kWarning() << "Wallet::slotCollectionStatusChanged unimplemented '" << d->name << "' status=" << status;
++}
++
++void Wallet::slotCollectionDeleted()
++{
++#ifdef OSX_KEYCHAIN_PORT_DISABLED
++ d->folder.clear();
++#else
++ d->currentService.clear();
++#endif
++ kDebug() << "Wallet::slotCollectionDeleted: closing private data '" << d->name;
++ d->close();
++ emit walletClosed();
++}
++
++
++void Wallet::virtual_hook(int, void*)
++{
++ //BASE::virtual_hook( id, data );
++}
++
++#include "kwallet.moc"
+diff -urN kdelibs-4.13.3-orig/kdeui/util/qosxkeychain.cpp kdelibs-4.13.3/kdeui/util/qosxkeychain.cpp
+--- kdelibs-4.13.3-orig/kdeui/util/qosxkeychain.cpp 1970-01-01 09:00:00.000000000 +0900
++++ kdelibs-4.13.3/kdeui/util/qosxkeychain.cpp 2014-09-22 19:46:57.000000000 +0900
+@@ -0,0 +1,776 @@
++/*
++ * @file qosxkeychain.cpp
++ * This file is part of the KDE project
++ *
++ * Created by René J.V. Bertin on 20140809.
++ * Copyright (C) 2014 René Bertin <rjvbertin at gmail.com>
++ *
++ * 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 <cassert>
++#include <sys/param.h>
++
++#include <QtGui/QApplication>
++#include <QtCore/QtCore>
++#include <QtCore/QPointer>
++#include <QtGui/QWidget>
++
++#include "kwallet.h"
++#include <kdebug.h>
++using namespace KWallet;
++#include "qosxkeychain.h"
++
++#include <CoreServices/CoreServices.h>
++
++//! Define INTERNET_TOO=1 in order to build read-access to the kSecInternetPasswordItemClass items
++#define INTERNET_TOO 0
++
++// #undef kWarning
++// #undef kDebug
++// #define kWarning qWarning
++// #define kDebug qDebug
++
++// returns the textual representation of a FourCharCode (e.g. 'JPEG')
++static QString OSTStr( FourCharCode etype )
++{ union OSTStr {
++ struct {
++ char startquote;
++ uint32_t four;
++ char endquote;
++ } __attribute__ ((packed)) value;
++ char representation[7];
++ } __attribute__ ((packed)) ltype;
++ ltype.value.four = EndianU32_BtoN(etype);
++ ltype.representation[0] = ltype.representation[5] = '\'';
++ ltype.representation[6] = '\0';
++ return QString::fromAscii(ltype.representation);
++}
++
++static SecKeychainRef defaultChain()
++{ QString errMsg;
++ SecKeychainRef keychain;
++ if( isError( SecKeychainCopyDefault(&keychain), &errMsg ) ){
++ kWarning() << "Could not retrieve reference to default keychain:" << qPrintable(errMsg);
++ keychain = NULL;
++ }
++ return keychain;
++}
++
++/*! Return a name for @p keychain, and possibly the full path to its file
++ * The name will be the equivalent of the `basename path .keychain` shell
++ * command.
++ */
++static QString keyChainName( SecKeychainRef keychain, QString *path=NULL )
++{ QFileInfo keyFile;
++ QString p = OSXKeychain::Path(keychain);
++ int ext = p.lastIndexOf(".keychain");
++ keyFile = QFileInfo( ((ext > 0)? p.left(ext) : p) );
++ if( path ){
++ *path = QString(p);
++ }
++ return keyFile.fileName();
++}
++
++/*! Open an OS X keychain with name @p n.
++ * OS X keychains can be created without a full path (say, "kdewallet"), in which case they
++ * are stored e.g. as ~/Library/Keychains/kdewallet . However, opening a preexisting keychain like "login"
++ * without using the full path seems to fail even if e.g. ~/Library/Keychains/login exists.
++ * We try to work around that issue by matching @p n against the known keychain names.
++ */
++static OSStatus openKeychain( const QString &n, SecKeychainRef *keychain )
++{ OSStatus err;
++ CFArrayRef list = NULL;
++
++ *keychain = NULL;
++ err = SecKeychainCopySearchList( &list );
++ if( !err && list ){
++ CFIndex len = CFArrayGetCount(list), i;
++ for( i = 0 ; i < len && !*keychain ; ++i ){
++ SecKeychainRef kr = (SecKeychainRef) CFArrayGetValueAtIndex( list, i );
++ QString path, name = keyChainName( kr, &path );
++ if( name == n ){
++ // a hit, try to open it!
++ err = SecKeychainOpen( path.toUtf8(), keychain );
++ if( err ){
++ kWarning() << "openKeychain(" << n << ") error" << err << "opening matching" << path;
++ }
++ else{
++ kDebug() << "openKeychain(" << n << ") opened matching" << path;
++ }
++ }
++ }
++ CFRelease(list);
++ }
++ if( !*keychain ){
++ err = SecKeychainOpen( n.toUtf8(), keychain );
++ }
++ // we actually need to query the keychain's status to know if we succeeded
++ // in opening an existing keychain!
++ if( !err ){
++ SecKeychainStatus status;
++ err = SecKeychainGetStatus( *keychain, &status );
++ }
++ return err;
++}
++
++static OSStatus basicWriteItem( const QByteArray *serviceName, const QByteArray &accountName, const QByteArray &value,
++ const SecKeychainRef keychain, SecKeychainItemRef *itemRef=NULL )
++{ OSStatus err;
++ QString errMsg;
++ if( serviceName ){
++ err = SecKeychainAddGenericPassword( keychain, serviceName->size(), serviceName->constData(),
++ accountName.size(), accountName.constData(),
++ value.size(), value.constData(), itemRef );
++ }
++ else{
++ err = SecKeychainAddGenericPassword( keychain, 0, NULL,
++ accountName.size(), accountName.constData(),
++ value.size(), value.constData(), itemRef );
++ }
++ if( err != errSecDuplicateItem && isError( err, &errMsg ) ){
++ kWarning() << "Could not store password in keychain: " << qPrintable(errMsg);
++ }
++ return err;
++}
++
++OSXKeychain::OSXKeychain()
++ : name("default")
++{ QString errMsg;
++ keyChainRef = defaultChain();
++ if( keyChainRef ){
++ keyChainPath = OSXKeychain::Path(keyChainRef);
++ kDebug() << "Retrieved reference to default keychain" << (void*) keyChainRef << "in " << keyChainPath;
++ name = keyChainName(keyChainRef);
++ isDefaultKeychain = true;
++ }
++ else{
++ keyChainPath = QString::fromUtf8("<undefined>");
++ }
++ serviceList.clear();
++ serviceList.append("");
++}
++
++OSXKeychain::OSXKeychain(const QString &n, bool *isNew)
++ : name(n)
++{ QString errMsg;
++ OSStatus err = openKeychain( n, &keyChainRef );
++
++ if( err == errSecNoSuchKeychain ){
++ kWarning() << "Keychain '" << n << "' does not exist: attempting to create it";
++ err = SecKeychainCreate( n.toUtf8(), 0, NULL, true, NULL, &keyChainRef );
++ isKDEChain = true;
++ if( !err && isNew ){
++ *isNew = true;
++ }
++ }
++ else if( !err && isNew ){
++ *isNew = false;
++ }
++
++ if( isError( err, &errMsg ) ){
++ // the protocol cannot handle failure to open a keychain, so we have to return the default.
++ keyChainRef = defaultChain();
++ kWarning() << "Error opening keychain '" << n << "' (falling back to default keychain): " << qPrintable(errMsg);
++ name = keyChainName(keyChainRef);
++ isDefaultKeychain = true;
++ }
++ else{
++ isDefaultKeychain = false;
++ }
++
++ if( keyChainRef ){
++ keyChainPath = OSXKeychain::Path(keyChainRef);
++ kDebug() << "Retrieved reference to keychain" << name << (void*) keyChainRef << "in " << keyChainPath;
++ }
++ else{
++ keyChainPath = QString::fromUtf8("<undefined>");
++ }
++ serviceList.clear();
++ serviceList.append("");
++}
++
++void OSXKeychain::close()
++{
++ if( keyChainRef ){
++ Lock(keyChainRef);
++ CFRelease(keyChainRef);
++ keyChainRef = NULL;
++ serviceList.clear();
++ }
++}
++
++OSXKeychain::~OSXKeychain()
++{
++ if( keyChainRef ){
++ CFRelease(keyChainRef);
++ keyChainRef = NULL;
++ }
++ serviceList.clear();
++}
++
++OSStatus OSXKeychain::lockSettings(int &closeWhenIdle, unsigned int &idleTimeoutMin)
++{ QString errMsg;
++ SecKeychainSettings kcSettings= { SEC_KEYCHAIN_SETTINGS_VERS1, 0, 0, INT_MAX };
++ OSStatus err = SecKeychainCopySettings( keyChainRef, &kcSettings );
++ if( isError( err, &errMsg ) ){
++ kWarning() << "Error getting settings for" << name << err << "=" << qPrintable(errMsg);
++ }
++ else{
++ closeWhenIdle = kcSettings.useLockInterval;
++ idleTimeoutMin = (int)(kcSettings.lockInterval / 60 + 0.5);
++ }
++ return err;
++}
++
++OSStatus OSXKeychain::setLockSettings(int closeWhenIdle, unsigned int idleTimeoutMin)
++{ QString errMsg;
++ SecKeychainSettings kcSettings = { SEC_KEYCHAIN_SETTINGS_VERS1, 0, 0, INT_MAX };
++ OSStatus err;
++
++ // to switch (or keep) off idle timeout locking set useLockInterval=false and lockInterval=INT_MAX
++ // if lockInterval has any other value, SecKeychainSetSettings() will force useLockInterval=true
++ if( closeWhenIdle ){
++ kcSettings.useLockInterval = 1;
++ kcSettings.lockInterval = idleTimeoutMin * 60;
++ }
++ err = SecKeychainSetSettings( keyChainRef, &kcSettings );
++// if( !err ){
++// SecKeychainSettings ks = { SEC_KEYCHAIN_SETTINGS_VERS1, 0, 0, INT_MAX };
++// ks.useLockInterval = !closeWhenIdle;
++// SecKeychainCopySettings( keyChainRef, &ks );
++// qDebug() << "Keychain settings set to useLockInterval=" << ks.useLockInterval << "lockInterval=" << ks.lockInterval;
++// }
++// else{
++// qDebug() << "Error setting keychain settings:" << err;
++// }
++ return err;
++}
++
++OSStatus OSXKeychain::renameItem(const QString ¤tKey, const QString &newKey)
++{ OSStatus err;
++ SecKeychainItemRef itemRef = NULL;
++ err = ReadItem( currentKey, NULL, keyChainRef, &itemRef, this );
++ if( !err && itemRef ){
++ const QByteArray accountName( newKey.toUtf8() );
++ // store the new key in the account and label attributes
++ SecKeychainAttribute attr[] = { { kSecAccountItemAttr, accountName.size(), (void*) accountName.constData() },
++ { kSecLabelItemAttr, accountName.size(), (void*) accountName.constData() } };
++ SecKeychainAttributeList attrList = { 2, &attr[0] };
++ QString errMsg;
++ if( isError( (err = SecKeychainItemModifyAttributesAndData( itemRef, &attrList, 0, NULL )), &errMsg ) ){
++ kWarning() << "OSXKeychain::renameItem(" << currentKey << ") couldn't change name & label to" << accountName
++ << ":" << err << "=" << qPrintable(errMsg);
++ }
++ CFRelease(itemRef);
++ }
++ return err;
++}
++
++#pragma mark ========= static member functions =========
++
++OSStatus OSXKeychain::KeychainList(QStringList &theList)
++{ CFArrayRef list = NULL;
++ OSStatus err = SecKeychainCopySearchList( &list );
++ theList.clear();
++ if( !err && list ){
++ CFIndex len = CFArrayGetCount(list), i;
++ for( i = 0 ; i < len ; ++i ){
++ SecKeychainRef keychain = (SecKeychainRef) CFArrayGetValueAtIndex( list, i );
++ QString name = keyChainName(keychain);
++ if( name.size() > 0 ){
++ theList.append(name);
++ }
++ }
++ CFRelease(list);
++ }
++ return err;
++}
++
++QString OSXKeychain::Path(const SecKeychainRef keychain)
++{ char pathName[MAXPATHLEN];
++ UInt32 plen = MAXPATHLEN;
++ if( SecKeychainGetPath( (keychain)? keychain : OSXKeychain().reference(), &plen, pathName ) == errSecSuccess ){
++ return QString::fromUtf8(pathName);
++ }
++ else{
++ return QString();
++ }
++}
++
++bool OSXKeychain::IsOpen(const SecKeychainRef keychain)
++{ bool isOpen = false;
++ SecKeychainStatus status;
++ QString errMsg;
++ if( isError( SecKeychainGetStatus( keychain, &status ), &errMsg ) ){
++ if( keychain ){
++ kDebug() << "Could not get the status of keychain" << OSXKeychain::Path(keychain) << ":" << qPrintable(errMsg);
++ }
++ else{
++ kWarning() << "Could not get the default keychain's status:" << qPrintable(errMsg);
++ }
++ }
++ else{
++ if( (status & kSecUnlockStateStatus) && (status & kSecReadPermStatus) ){
++ isOpen = true;
++ }
++ else{
++ kDebug() << "Keychain" << OSXKeychain::Path(keychain) << " has status" << status;
++ }
++ }
++ return isOpen;
++}
++
++bool OSXKeychain::IsOpen(const QString &walletName)
++{ SecKeychainRef keychain = NULL;
++ OSStatus err = openKeychain( walletName.toUtf8(), &keychain );
++ bool ret = false;
++ if( !err && keychain ){
++ ret = IsOpen(keychain);
++ CFRelease(keychain);
++ }
++ return ret;
++}
++
++OSStatus OSXKeychain::UnLock(const SecKeychainRef keychain)
++{ QString errMsg;
++ OSStatus err;
++ err = SecKeychainUnlock( keychain, 0, NULL, false );
++ if( isError( err, &errMsg ) ){
++ if( keychain ){
++ kDebug() << "Could not unlock the keychain at '" << OSXKeychain::Path(keychain) << "': " << qPrintable(errMsg);
++ }
++ else{
++ kDebug() << "Could not unlock the default keychain:" << qPrintable(errMsg);
++ }
++ }
++ return err;
++}
++
++OSStatus OSXKeychain::Lock(const SecKeychainRef keychain)
++{ QString errMsg;
++ OSStatus err;
++ if( keychain ){
++ err = SecKeychainLock(keychain);
++ if( isError( err, &errMsg ) ){
++ kDebug() << "Could not lock the keychain at '" << OSXKeychain::Path(keychain) << "': " << qPrintable(errMsg);
++ }
++ }
++ else{
++ err = SecKeychainLockAll();
++ if( isError( err, &errMsg ) ){
++ kDebug() << "Could not lock all keychains:" << qPrintable(errMsg);
++ }
++ }
++ return err;
++}
++
++OSStatus OSXKeychain::Lock(const QString &walletName)
++{ SecKeychainRef keychain = NULL;
++ OSStatus err = openKeychain( walletName, &keychain );
++ if( !err && keychain ){
++ err = Lock(keychain);
++ CFRelease(keychain);
++ }
++ return err;
++}
++
++/** use the keychain search functions to find the first matching item, if any, @return returning True if found.
++ The OS X error code is returned through @p errReturn when not NULL, the item itself through @p itemRef.
++ This reference will have to be released with CFRelease() when done with it (when @p itemRef==NULL the
++ function does this release itself).
++ */
++bool OSXKeychain::HasItem(const QString &key,
++ const SecKeychainRef keychain, OSStatus *errReturn, SecKeychainItemRef *itemRef)
++{ const QByteArray accountName( key.toUtf8() );
++ OSStatus err;
++ SecKeychainSearchRef searchRef;
++ SecKeychainAttribute attrs = { kSecAccountItemAttr, accountName.size(), (void*) accountName.constData() };
++ SecKeychainAttributeList attrList = { 1, &attrs };
++ err = SecKeychainSearchCreateFromAttributes( keychain, kSecGenericPasswordItemClass,
++ (const SecKeychainAttributeList*) &attrList, &searchRef );
++ const CFReleaser<SecKeychainSearchRef> releaseSR(searchRef);
++ bool found;
++ SecKeychainItemRef item;
++ QString errMsg;
++ if( err ){
++ found = false;
++ errMsg = errorString(err);
++ kDebug() << "OSXKeychain::HasItem(" << key << "," << (void*) keychain << "): SecKeychainSearchCreateFromAttributes failed";
++ }
++ else{
++ if( !(err = SecKeychainSearchCopyNext( searchRef, &item )) ){
++ found = true;
++ if( itemRef ){
++ *itemRef = item;
++ }
++ else if( item ){
++ CFRelease(item);
++ }
++ errMsg = QString();
++ }
++ else{
++ found = false;
++ errMsg = errorString(err);
++ }
++ if( errReturn ){
++ *errReturn = err;
++ }
++ }
++ kDebug() << "item '" << key << ((found)? "found" : "not found") << "' in keychain " << (void*) keychain << ", error=" << err << " " << qPrintable(errMsg);
++ return found;
++}
++
++OSStatus OSXKeychain::ReadItem(const QString &key, QByteArray *value,
++ const SecKeychainRef keychain, SecKeychainItemRef *itemRef, OSXKeychain *osxKeyChain)
++{ const QByteArray accountName( key.toUtf8() );
++ UInt32 passwordSize = 0;
++ void* passwordData = 0;
++ QString errMsg;
++ SecKeychainItemRef theItem;
++ OSStatus err = SecKeychainFindGenericPassword( keychain, 0, NULL,
++ accountName.size(), accountName.constData(),
++ &passwordSize, &passwordData, &theItem );
++ if( isError( err, &errMsg ) ){
++ kDebug() << "Error" << err << "retrieving password for '" << accountName << "' :" << qPrintable(errMsg);
++#if INTERNET_TOO
++ if( SecKeychainFindInternetPassword( keychain, 0, NULL,
++ 0, NULL,
++ accountName.size(), accountName.constData(),
++ 0, NULL, 0,
++ kSecProtocolTypeAny, kSecAuthenticationTypeDefault,
++ &passwordSize, &passwordData, &theItem ) ){
++ // just to be sure:
++ theItem = NULL;
++ }
++ else{
++ err = 0;
++ errMsg = QString();
++ }
++#else
++ theItem = NULL;
++#endif
++ }
++ if( !err && theItem ){
++ if( value ){
++ *value = QByteArray( reinterpret_cast<const char*>( passwordData ), passwordSize );
++ }
++ SecKeychainItemFreeContent( NULL, passwordData );
++ if( osxKeyChain && osxKeyChain->isKDEChain ){
++ SecKeychainAttribute attr = { kSecServiceItemAttr, 0, NULL };
++ SecKeychainAttributeList attrList = { 1, &attr };
++ UInt32 len = 0;
++ // try to fetch the item's ServiceItem attribute
++ if( !SecKeychainItemCopyContent( theItem, NULL, &attrList, &len, NULL ) ){
++ if( attr.length > 0 ){
++ osxKeyChain->lastReadService.clear();
++ osxKeyChain->lastReadService = QString::fromUtf8( (char*)attr.data, attr.length );
++ }
++ SecKeychainItemFreeContent( &attrList, NULL );
++ }
++ }
++ if( itemRef ){
++ *itemRef = theItem;
++ }
++ else if( theItem ){
++ CFRelease(theItem);
++ }
++ }
++ kDebug() << "OSXKeychain::ReadItem '" << key << "' from keychain " << OSXKeychain::Path(keychain) << ", error=" << err;
++ return err;
++}
++
++OSStatus OSXKeychain::ItemType(const QString &key, EntryType *entryType,
++ const SecKeychainRef keychain)
++{ const QByteArray accountName( key.toUtf8() );
++ QString errMsg;
++ EntryType etype = (EntryType) 0;
++ SecKeychainItemRef itemRef;
++#if INTERNET_TOO
++ bool isInternetPW = false;
++#endif
++ OSStatus err = SecKeychainFindGenericPassword( keychain, 0, NULL,
++ accountName.size(), accountName.constData(),
++ NULL, NULL, &itemRef );
++ if( isError( err, &errMsg ) ){
++ kDebug() << "Error" << err << "retrieving type for '" << accountName << "' :" << qPrintable(errMsg);
++#if INTERNET_TOO
++ if( SecKeychainFindInternetPassword( keychain, 0, NULL,
++ 0, NULL,
++ accountName.size(), accountName.constData(),
++ 0, NULL, 0,
++ kSecProtocolTypeAny, kSecAuthenticationTypeDefault,
++ 0, NULL, &itemRef ) ){
++ // just to be sure:
++ itemRef = NULL;
++ }
++ else{
++ isInternetPW = true;
++ err = 0;
++ errMsg = QString();
++ }
++#else
++ itemRef = NULL;
++#endif
++ }
++ if( itemRef ){
++ UInt32 tags[] = { kSecTypeItemAttr };
++ UInt32 formats[] = { CSSM_DB_ATTRIBUTE_FORMAT_STRING };
++ SecKeychainAttributeInfo attrGet = { 1, tags, formats };
++ SecKeychainAttributeList *attrList = NULL;
++ err = SecKeychainItemCopyAttributesAndData( itemRef, &attrGet, NULL, &attrList, NULL, NULL );
++ if( !err ){
++ if( attrList->attr[0].length == sizeof(EntryType) ){
++ memcpy( &etype, attrList->attr[0].data, sizeof(EntryType) );
++ }
++ else if( attrList->attr[0].length ){
++ kDebug() << "Error: key" << key << "item type retrieved is of size" << attrList->attr[0].length << "!=" << sizeof(EntryType);
++ }
++#if INTERNET_TOO
++ else if( isInternetPW ){
++ // this is just a wild guess ...
++ etype = Password;
++ }
++#endif
++ if( entryType ){
++ *entryType = etype;
++ }
++ }
++ SecKeychainItemFreeAttributesAndData( attrList, NULL );
++ CFRelease(itemRef);
++ }
++ kDebug() << "OSXKeychain::ItemType '" << key << "' from keychain " << OSXKeychain::Path(keychain) << "=" << OSTStr(etype) << ", error=" << err;
++ return err;
++}
++
++OSStatus OSXKeychain::RemoveItem(const QString &key, const SecKeychainRef keychain)
++{ const QByteArray accountName( key.toUtf8() );
++ SecKeychainItemRef itemRef;
++ QString errMsg;
++ OSStatus result = SecKeychainFindGenericPassword( keychain, 0, NULL,
++ accountName.size(), accountName.constData(), NULL, NULL, &itemRef );
++ if( isError( result, &errMsg ) ){
++ kDebug() << "Could not find entry" << key << ":" << qPrintable(errMsg);
++ }
++ else{
++ const CFReleaser<SecKeychainItemRef> itemReleaser(itemRef);
++ result = SecKeychainItemDelete(itemRef);
++ if( isError( result, &errMsg ) ){
++ kWarning() << "Could not delete entry" << key << ":" << qPrintable(errMsg);
++ }
++ }
++ return result;
++}
++
++OSStatus OSXKeychain::WriteItem( const QString &key, const QByteArray &value,
++ const SecKeychainRef keychain, SecKeychainItemRef *itemRef, EntryType *entryType, OSXKeychain *osxKeyChain )
++{ const QByteArray accountName( key.toUtf8() );
++ OSStatus err;
++ QString errMsg;
++ SecKeychainItemRef theItem = NULL;
++ bool saveLabel;
++ if( osxKeyChain && osxKeyChain->currentService.size() ){
++ const QByteArray serviceName( osxKeyChain->currentService.toUtf8() );
++ // save the "GenericPassword" item using the service name, which appears to be the only way to write
++ // to the "Where" field shown in the Keychain Utility.
++ err = basicWriteItem( &serviceName, accountName, value, keychain, &theItem );
++ // the service (folder!) string will also appear on the "Name" field, which however can be changed
++ // independently, via the Label attribute.
++ saveLabel = true;
++ }
++ else{
++ err = basicWriteItem( NULL, accountName, value, keychain, &theItem );
++ saveLabel = false;
++ }
++ if( err == errSecDuplicateItem ){
++ // RJVB: the previous implementation was wrong. errSecDuplicateItem means the write failed because of an existing item.
++ // So we have to find that item, and modify it.
++ if( !(err = ReadItem( key, NULL, keychain, &theItem )) ){
++ err = SecKeychainItemModifyAttributesAndData( theItem, NULL, value.size(), value.constData() );
++ if( isError( err, &errMsg ) ){
++ kDebug() << "Key '" << key
++ << "'already exists in keychain but error modifying the existing item: " << qPrintable(errMsg);
++ }
++ }
++ if( !err ){
++ kDebug() << "Key '" << key << "'already existed in keychain: modified the existing item";
++ }
++ }
++ if( !err && saveLabel ){
++ // store the desired text in the label attribute
++ SecKeychainAttribute attr = { kSecLabelItemAttr, accountName.size(), (void*) accountName.constData() };
++ SecKeychainAttributeList attrList = { 1, &attr };
++ QString errMsg;
++ if( isError( (err = SecKeychainItemModifyAttributesAndData( theItem, &attrList, 0, NULL )), &errMsg ) ){
++ kWarning() << "OSXKeychain::WriteItem(" << key << ") couldn't set the desired name/label" << accountName
++ << ":" << err << "=" << qPrintable(errMsg);
++ }
++ }
++ if( !err ){
++ EntryType defType = Stream;
++ if( !entryType ){
++ entryType = &defType;
++ }
++ SecKeychainAttribute attr = { kSecTypeItemAttr, sizeof(EntryType), (void*) entryType };
++ SecKeychainAttributeList attrList = { 1, &attr };
++ QString errMsg;
++ if( isError( (err = SecKeychainItemModifyAttributesAndData( theItem, &attrList, 0, NULL )), &errMsg ) ){
++ kWarning() << "OSXKeychain::WriteItem(" << key << ") couldn't set type to" << OSTStr(*entryType)
++ << ":" << qPrintable(errMsg);
++ }
++ }
++ if( itemRef ){
++ *itemRef = theItem;
++ }
++ else if( theItem ){
++ CFRelease(theItem);
++ }
++ kDebug() << "OSXKeychain::WriteItem '" << key << "' to keychain " << (void*) keychain << ", error=" << err;
++ return err;
++}
++
++OSStatus OSXKeychain::WriteItem( const QString &key, const QByteArray &value,
++ const QString &comment, const SecKeychainRef keychain, EntryType *entryType, OSXKeychain *osxKeyChain )
++{ SecKeychainItemRef itemRef = NULL;
++ OSStatus err = WriteItem( key, value, keychain, &itemRef, entryType, osxKeyChain );
++ if( !err && itemRef ){
++ const QByteArray commentString(comment.toUtf8());
++ if( commentString.size() ){
++ SecKeychainAttribute attr = { kSecCommentItemAttr, commentString.size(), (void*) commentString.constData() };
++ SecKeychainAttributeList attrList = { 1, &attr };
++ QString errMsg;
++ if( isError( (err = SecKeychainItemModifyAttributesAndData( itemRef, &attrList, 0, NULL )), &errMsg ) ){
++ kWarning() << "OSXKeychain::WriteItem(" << key << ") couldn't add comment" << comment
++ << ":" << qPrintable(errMsg);
++ }
++ }
++ CFRelease(itemRef);
++ }
++ return err;
++}
++
++// returns the kSecAccountItemAttr's of all items in the keychain
++OSStatus OSXKeychain::ItemList( SecKeychainRef keychain, QStringList &keyList, OSXKeychain *osxKeyChain )
++{ OSStatus err;
++ SecKeychainSearchRef searchRef[2];
++ bool generateFolderList = ( osxKeyChain && osxKeyChain->isKDEChain && osxKeyChain->generateFolderList );
++
++ keyList.clear();
++ if( generateFolderList ){
++ osxKeyChain->serviceList.clear();
++ if( osxKeyChain->currentService.size() > 0 ){
++ osxKeyChain->serviceList.append(osxKeyChain->currentService);
++ }
++ }
++
++ err = SecKeychainSearchCreateFromAttributes( keychain, kSecGenericPasswordItemClass, NULL, &searchRef[0] );
++#if INTERNET_TOO
++ if( SecKeychainSearchCreateFromAttributes( keychain, kSecInternetPasswordItemClass, NULL, &searchRef[1] ) ){
++ searchRef[1] = NULL;
++ }
++#else
++ searchRef[1] = NULL;
++#endif
++ SecKeychainItemRef item;
++ QString errMsg;
++ if( isError(err, &errMsg) ){
++ kDebug() << "OSXKeychain::ItemList(" << (void*) keychain << "): SecKeychainSearchCreateFromAttributes failed" << qPrintable(errMsg);
++ }
++ else{
++ for( size_t i = 0 ; i < sizeof(searchRef)/sizeof(SecKeychainSearchRef) && !err ; ++i ){
++ if( searchRef[i] ){
++ while( !(err = SecKeychainSearchCopyNext( searchRef[i], &item )) ){
++ if( item ){
++ // whether the item will be listed in the keyList we return: by default it is
++ // (better an item shows up multiple times than not at all).
++ bool listItem = true;
++ SecKeychainAttribute attr = { kSecAccountItemAttr, 0, NULL };
++ SecKeychainAttributeList attrList = { 1, &attr };
++ UInt32 len = 0;
++ if( osxKeyChain && osxKeyChain->isKDEChain ){
++ // try to fetch the item's ServiceItem attribute
++ attr.tag = kSecServiceItemAttr;
++ if( !SecKeychainItemCopyContent( item, NULL, &attrList, &len, NULL ) ){
++ QString lbl = QString::fromUtf8( (char*)attr.data, attr.length );
++ // we got a service item attribute, which is where we store the kwallet folder info.
++ // If we disallow empty attributes, keychain items without service item attribute will
++ // appear in each folder that has a non-empty name. In other words, we allow a folder without name.
++ if( generateFolderList ){
++ // add the "folder" to the list if not already listed
++ if( !osxKeyChain->serviceList.contains(lbl) ){
++ osxKeyChain->serviceList.append(lbl);
++ }
++ }
++ else{
++ // only list the item if it's in the current "folder"
++ listItem = (lbl == osxKeyChain->currentService);
++ }
++ SecKeychainItemFreeContent( &attrList, NULL );
++ }
++ }
++ else{
++ // errors retrieving the service item attribute are ignored
++ }
++ if( listItem ){
++ attr.tag = kSecAccountItemAttr;
++ if( !(err = SecKeychainItemCopyContent( item, NULL, &attrList, &len, NULL )) ){
++ if( attr.length > 0 ){
++ keyList.append(QString::fromUtf8( (char*)attr.data, attr.length ));
++ }
++ SecKeychainItemFreeContent( &attrList, NULL );
++ }
++ else{
++ errMsg = errorString(err);
++ kDebug() << "SecKeychainItemCopyContent returned" << err << "=" << qPrintable(errMsg);
++ }
++ }
++ CFRelease(item);
++ }
++ }
++ if( err ){
++ errMsg = errorString(err);
++ }
++ CFRelease(searchRef[i]);
++ }
++ }
++ }
++ return err;
++}
++
++OSStatus OSXKeychain::Destroy( SecKeychainRef *keychain )
++{ OSStatus err = SecKeychainDelete(*keychain);
++ QString errMsg;
++ if( isError( err, &errMsg ) ){
++ kWarning() << "OSXKeychain::Destroy " << (void*) *keychain << ", error " << qPrintable(errMsg);
++ }
++ else{
++ kWarning() << "OSXKeychain::Destroy " << (void*) *keychain << ", error=" << err;
++ }
++ if( keychain ){
++ CFRelease(*keychain);
++ *keychain = NULL;
++ }
++ return err;
++}
++
++OSStatus OSXKeychain::Destroy( const QString &walletName )
++{ SecKeychainRef keychain;
++ OSStatus err = openKeychain( walletName, &keychain );
++ if( !err && keychain ){
++ err = Destroy(&keychain);
++ }
++ return err;
++}
+diff -urN kdelibs-4.13.3-orig/kdeui/util/qosxkeychain.cpp.orig kdelibs-4.13.3/kdeui/util/qosxkeychain.cpp.orig
+--- kdelibs-4.13.3-orig/kdeui/util/qosxkeychain.cpp.orig 1970-01-01 09:00:00.000000000 +0900
++++ kdelibs-4.13.3/kdeui/util/qosxkeychain.cpp.orig 2014-09-22 19:46:10.000000000 +0900
+@@ -0,0 +1,726 @@
++/*
++ * @file qosxkeychain.cpp
++ * This file is part of the KDE project
++ *
++ * Created by René J.V. Bertin on 20140809.
++ * Copyright (C) 2014 René Bertin <rjvbertin at gmail.com>
++ *
++ * 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 <cassert>
++#include <sys/param.h>
++
++#include <QtGui/QApplication>
++#include <QtCore/QtCore>
++#include <QtCore/QPointer>
++#include <QtGui/QWidget>
++
++#include "kwallet.h"
++#include <kdebug.h>
++using namespace KWallet;
++#include "qosxkeychain.h"
++
++#include <CoreServices/CoreServices.h>
++
++//! Define INTERNET_TOO=1 in order to build read-access to the kSecInternetPasswordItemClass items
++#define INTERNET_TOO 0
++
++// #undef kWarning
++// #undef kDebug
++// #define kWarning qWarning
++// #define kDebug qDebug
++
++// returns the textual representation of a FourCharCode (e.g. 'JPEG')
++static QString OSTStr( FourCharCode etype )
++{ union OSTStr {
++ struct {
++ char startquote;
++ uint32_t four;
++ char endquote;
++ } __attribute__ ((packed)) value;
++ char representation[7];
++ } __attribute__ ((packed)) ltype;
++ ltype.value.four = EndianU32_BtoN(etype);
++ ltype.representation[0] = ltype.representation[5] = '\'';
++ ltype.representation[6] = '\0';
++ return QString::fromAscii(ltype.representation);
++}
++
++static SecKeychainRef defaultChain()
++{ QString errMsg;
++ SecKeychainRef keychain;
++ if( isError( SecKeychainCopyDefault(&keychain), &errMsg ) ){
++ kWarning() << "Could not retrieve reference to default keychain:" << qPrintable(errMsg);
++ keychain = NULL;
++ }
++ return keychain;
++}
++
++/*! Return a name for @p keychain, and possibly the full path to its file
++ * The name will be the equivalent of the `basename path .keychain` shell
++ * command.
++ */
++static QString keyChainName( SecKeychainRef keychain, QString *path=NULL )
++{ QFileInfo keyFile;
++ QString p = OSXKeychain::Path(keychain);
++ int ext = p.lastIndexOf(".keychain");
++ keyFile = QFileInfo( ((ext > 0)? p.left(ext) : p) );
++ if( path ){
++ *path = QString(p);
++ }
++ return keyFile.fileName();
++}
++
++/*! Open an OS X keychain with name @p n.
++ * OS X keychains can be created without a full path (say, "kdewallet"), in which case they
++ * are stored e.g. as ~/Library/Keychains/kdewallet . However, opening a preexisting keychain like "login"
++ * without using the full path seems to fail even if e.g. ~/Library/Keychains/login exists.
++ * We try to work around that issue by matching @p n against the known keychain names.
++ */
++static OSStatus openKeychain( const QString &n, SecKeychainRef *keychain )
++{ OSStatus err;
++ CFArrayRef list = NULL;
++
++ *keychain = NULL;
++ err = SecKeychainCopySearchList( &list );
++ if( !err && list ){
++ CFIndex len = CFArrayGetCount(list), i;
++ for( i = 0 ; i < len && !*keychain ; ++i ){
++ SecKeychainRef kr = (SecKeychainRef) CFArrayGetValueAtIndex( list, i );
++ QString path, name = keyChainName( kr, &path );
++ if( name == n ){
++ // a hit, try to open it!
++ err = SecKeychainOpen( path.toUtf8(), keychain );
++ if( err ){
++ kWarning() << "openKeychain(" << n << ") error" << err << "opening matching" << path;
++ }
++ else{
++ kDebug() << "openKeychain(" << n << ") opened matching" << path;
++ }
++ }
++ }
++ CFRelease(list);
++ }
++ if( !*keychain ){
++ err = SecKeychainOpen( n.toUtf8(), keychain );
++ }
++ // we actually need to query the keychain's status to know if we succeeded
++ // in opening an existing keychain!
++ if( !err ){
++ SecKeychainStatus status;
++ err = SecKeychainGetStatus( *keychain, &status );
++ }
++ return err;
++}
++
++static OSStatus basicWriteItem( const QByteArray *serviceName, const QByteArray &accountName, const QByteArray &value,
++ const SecKeychainRef keychain, SecKeychainItemRef *itemRef=NULL )
++{ OSStatus err;
++ QString errMsg;
++ if( serviceName ){
++ err = SecKeychainAddGenericPassword( keychain, serviceName->size(), serviceName->constData(),
++ accountName.size(), accountName.constData(),
++ value.size(), value.constData(), itemRef );
++ }
++ else{
++ err = SecKeychainAddGenericPassword( keychain, 0, NULL,
++ accountName.size(), accountName.constData(),
++ value.size(), value.constData(), itemRef );
++ }
++ if( err != errSecDuplicateItem && isError( err, &errMsg ) ){
++ kWarning() << "Could not store password in keychain: " << qPrintable(errMsg);
++ }
++ return err;
++}
++
++OSXKeychain::OSXKeychain()
++ : name("default")
++{ QString errMsg;
++ keyChainRef = defaultChain();
++ if( keyChainRef ){
++ keyChainPath = OSXKeychain::Path(keyChainRef);
++ kDebug() << "Retrieved reference to default keychain" << (void*) keyChainRef << "in " << keyChainPath;
++ name = keyChainName(keyChainRef);
++ isDefaultKeychain = true;
++ }
++ else{
++ keyChainPath = QString::fromUtf8("<undefined>");
++ }
++ serviceList.clear();
++ serviceList.append("");
++}
++
++OSXKeychain::OSXKeychain(const QString &n)
++ : name(n)
++{ QString errMsg;
++ OSStatus err = openKeychain( n, &keyChainRef );
++
++ if( err == errSecNoSuchKeychain ){
++ kWarning() << "Keychain '" << n << "' does not exist: attempting to create it";
++ err = SecKeychainCreate( n.toUtf8(), 0, NULL, true, NULL, &keyChainRef );
++ isKDEChain = true;
++ }
++
++ if( isError( err, &errMsg ) ){
++ // the protocol cannot handle failure to open a keychain, so we have to return the default.
++ keyChainRef = defaultChain();
++ kWarning() << "Error opening keychain '" << n << "' (falling back to default keychain): " << qPrintable(errMsg);
++ name = keyChainName(keyChainRef);
++ isDefaultKeychain = true;
++ }
++ else{
++ isDefaultKeychain = false;
++ }
++
++ if( keyChainRef ){
++ keyChainPath = OSXKeychain::Path(keyChainRef);
++ kDebug() << "Retrieved reference to keychain" << name << (void*) keyChainRef << "in " << keyChainPath;
++ }
++ else{
++ keyChainPath = QString::fromUtf8("<undefined>");
++ }
++ serviceList.clear();
++ serviceList.append("");
++}
++
++void OSXKeychain::close()
++{
++ if( keyChainRef ){
++ CFRelease(keyChainRef);
++ keyChainRef = NULL;
++ }
++}
++
++OSXKeychain::~OSXKeychain()
++{
++ close();
++}
++
++OSStatus OSXKeychain::renameItem(const QString ¤tKey, const QString &newKey)
++{ OSStatus err;
++ SecKeychainItemRef itemRef = NULL;
++ err = ReadItem( currentKey, NULL, keyChainRef, &itemRef, this );
++ if( !err && itemRef ){
++ const QByteArray accountName( newKey.toUtf8() );
++ // store the new key in the account and label attributes
++ SecKeychainAttribute attr[] = { { kSecAccountItemAttr, accountName.size(), (void*) accountName.constData() },
++ { kSecLabelItemAttr, accountName.size(), (void*) accountName.constData() } };
++ SecKeychainAttributeList attrList = { 2, &attr[0] };
++ QString errMsg;
++ if( isError( (err = SecKeychainItemModifyAttributesAndData( itemRef, &attrList, 0, NULL )), &errMsg ) ){
++ kWarning() << "OSXKeychain::renameItem(" << currentKey << ") couldn't change name & label to" << accountName
++ << ":" << err << "=" << qPrintable(errMsg);
++ }
++ CFRelease(itemRef);
++ }
++ return err;
++}
++
++#pragma mark ========= static member functions =========
++
++OSStatus OSXKeychain::KeychainList(QStringList &theList)
++{ CFArrayRef list = NULL;
++ OSStatus err = SecKeychainCopySearchList( &list );
++ theList.clear();
++ if( !err && list ){
++ CFIndex len = CFArrayGetCount(list), i;
++ for( i = 0 ; i < len ; ++i ){
++ SecKeychainRef keychain = (SecKeychainRef) CFArrayGetValueAtIndex( list, i );
++ QString name = keyChainName(keychain);
++ if( name.size() > 0 ){
++ theList.append(name);
++ }
++ }
++ CFRelease(list);
++ }
++ return err;
++}
++
++QString OSXKeychain::Path(const SecKeychainRef keychain)
++{ char pathName[MAXPATHLEN];
++ UInt32 plen = MAXPATHLEN;
++ if( SecKeychainGetPath( (keychain)? keychain : OSXKeychain().reference(), &plen, pathName ) == errSecSuccess ){
++ return QString::fromUtf8(pathName);
++ }
++ else{
++ return QString();
++ }
++}
++
++bool OSXKeychain::IsOpen(const SecKeychainRef keychain)
++{ bool isOpen = false;
++ SecKeychainStatus status;
++ QString errMsg;
++ if( isError( SecKeychainGetStatus( keychain, &status ), &errMsg ) ){
++ if( keychain ){
++ kDebug() << "Could not get the status of keychain" << OSXKeychain::Path(keychain) << ":" << qPrintable(errMsg);
++ }
++ else{
++ kWarning() << "Could not get the default keychain's status:" << qPrintable(errMsg);
++ }
++ }
++ else{
++ if( (status & kSecUnlockStateStatus) && (status & kSecReadPermStatus) ){
++ isOpen = true;
++ }
++ else{
++ kDebug() << "Keychain" << OSXKeychain::Path(keychain) << " has status" << status;
++ }
++ }
++ return isOpen;
++}
++
++bool OSXKeychain::IsOpen(const QString &walletName)
++{ SecKeychainRef keychain = NULL;
++ OSStatus err = openKeychain( walletName.toUtf8(), &keychain );
++ bool ret = false;
++ if( !err && keychain ){
++ ret = IsOpen(keychain);
++ CFRelease(keychain);
++ }
++ return ret;
++}
++
++OSStatus OSXKeychain::UnLock(const SecKeychainRef keychain)
++{ QString errMsg;
++ OSStatus err;
++ err = SecKeychainUnlock( keychain, 0, NULL, false );
++ if( isError( err, &errMsg ) ){
++ if( keychain ){
++ kDebug() << "Could not unlock the keychain at '" << OSXKeychain::Path(keychain) << "': " << qPrintable(errMsg);
++ }
++ else{
++ kDebug() << "Could not unlock the default keychain:" << qPrintable(errMsg);
++ }
++ }
++ return err;
++}
++
++OSStatus OSXKeychain::Lock(const SecKeychainRef keychain)
++{ QString errMsg;
++ OSStatus err;
++ if( keychain ){
++ err = SecKeychainLock(keychain);
++ if( isError( err, &errMsg ) ){
++ kDebug() << "Could not lock the keychain at '" << OSXKeychain::Path(keychain) << "': " << qPrintable(errMsg);
++ }
++ }
++ else{
++ err = SecKeychainLockAll();
++ if( isError( err, &errMsg ) ){
++ kDebug() << "Could not lock all keychains:" << qPrintable(errMsg);
++ }
++ }
++ return err;
++}
++
++OSStatus OSXKeychain::Lock(const QString &walletName)
++{ SecKeychainRef keychain = NULL;
++ OSStatus err = openKeychain( walletName, &keychain );
++ if( !err && keychain ){
++ err = Lock(keychain);
++ CFRelease(keychain);
++ }
++ return err;
++}
++
++/** use the keychain search functions to find the first matching item, if any, @return returning True if found.
++ The OS X error code is returned through @p errReturn when not NULL, the item itself through @p itemRef.
++ This reference will have to be released with CFRelease() when done with it (when @p itemRef==NULL the
++ function does this release itself).
++ */
++bool OSXKeychain::HasItem(const QString &key,
++ const SecKeychainRef keychain, OSStatus *errReturn, SecKeychainItemRef *itemRef)
++{ const QByteArray accountName( key.toUtf8() );
++ OSStatus err;
++ SecKeychainSearchRef searchRef;
++ SecKeychainAttribute attrs = { kSecAccountItemAttr, accountName.size(), (void*) accountName.constData() };
++ SecKeychainAttributeList attrList = { 1, &attrs };
++ err = SecKeychainSearchCreateFromAttributes( keychain, kSecGenericPasswordItemClass,
++ (const SecKeychainAttributeList*) &attrList, &searchRef );
++ const CFReleaser<SecKeychainSearchRef> releaseSR(searchRef);
++ bool found;
++ SecKeychainItemRef item;
++ QString errMsg;
++ if( err ){
++ found = false;
++ errMsg = errorString(err);
++ kDebug() << "OSXKeychain::HasItem(" << key << "," << (void*) keychain << "): SecKeychainSearchCreateFromAttributes failed";
++ }
++ else{
++ if( !(err = SecKeychainSearchCopyNext( searchRef, &item )) ){
++ found = true;
++ if( itemRef ){
++ *itemRef = item;
++ }
++ else if( item ){
++ CFRelease(item);
++ }
++ errMsg = QString();
++ }
++ else{
++ found = false;
++ errMsg = errorString(err);
++ }
++ if( errReturn ){
++ *errReturn = err;
++ }
++ }
++ kDebug() << ((found)? "Found" : "Did not find") << "item '" << key << "' in keychain " << (void*) keychain << ", error=" << err << " " << qPrintable(errMsg);
++ return found;
++}
++
++OSStatus OSXKeychain::ReadItem(const QString &key, QByteArray *value,
++ const SecKeychainRef keychain, SecKeychainItemRef *itemRef, OSXKeychain *osxKeyChain)
++{ const QByteArray accountName( key.toUtf8() );
++ UInt32 passwordSize = 0;
++ void* passwordData = 0;
++ QString errMsg;
++ SecKeychainItemRef theItem;
++ OSStatus err = SecKeychainFindGenericPassword( keychain, 0, NULL,
++ accountName.size(), accountName.constData(),
++ &passwordSize, &passwordData, &theItem );
++ if( isError( err, &errMsg ) ){
++ kDebug() << "Error" << err << "retrieving password for '" << accountName << "' :" << qPrintable(errMsg);
++#if INTERNET_TOO
++ if( SecKeychainFindInternetPassword( keychain, 0, NULL,
++ 0, NULL,
++ accountName.size(), accountName.constData(),
++ 0, NULL, 0,
++ kSecProtocolTypeAny, kSecAuthenticationTypeDefault,
++ &passwordSize, &passwordData, &theItem ) ){
++ // just to be sure:
++ theItem = NULL;
++ }
++ else{
++ err = 0;
++ errMsg = QString();
++ }
++#else
++ theItem = NULL;
++#endif
++ }
++ if( !err && theItem ){
++ if( value ){
++ *value = QByteArray( reinterpret_cast<const char*>( passwordData ), passwordSize );
++ }
++ SecKeychainItemFreeContent( NULL, passwordData );
++ if( osxKeyChain && osxKeyChain->isKDEChain ){
++ SecKeychainAttribute attr = { kSecServiceItemAttr, 0, NULL };
++ SecKeychainAttributeList attrList = { 1, &attr };
++ UInt32 len = 0;
++ // try to fetch the item's ServiceItem attribute
++ if( !SecKeychainItemCopyContent( theItem, NULL, &attrList, &len, NULL ) ){
++ if( attr.length > 0 ){
++ osxKeyChain->lastReadService.clear();
++ osxKeyChain->lastReadService = QString::fromUtf8( (char*)attr.data, attr.length );
++ }
++ SecKeychainItemFreeContent( &attrList, NULL );
++ }
++ }
++ if( itemRef ){
++ *itemRef = theItem;
++ }
++ else if( theItem ){
++ CFRelease(theItem);
++ }
++ }
++ kDebug() << "OSXKeychain::ReadItem '" << key << "' from keychain " << OSXKeychain::Path(keychain) << ", error=" << err;
++ return err;
++}
++
++OSStatus OSXKeychain::ItemType(const QString &key, EntryType *entryType,
++ const SecKeychainRef keychain)
++{ const QByteArray accountName( key.toUtf8() );
++ QString errMsg;
++ EntryType etype = (EntryType) 0;
++ SecKeychainItemRef itemRef;
++#if INTERNET_TOO
++ bool isInternetPW = false;
++#endif
++ OSStatus err = SecKeychainFindGenericPassword( keychain, 0, NULL,
++ accountName.size(), accountName.constData(),
++ NULL, NULL, &itemRef );
++ if( isError( err, &errMsg ) ){
++ kDebug() << "Error" << err << "retrieving type for '" << accountName << "' :" << qPrintable(errMsg);
++#if INTERNET_TOO
++ if( SecKeychainFindInternetPassword( keychain, 0, NULL,
++ 0, NULL,
++ accountName.size(), accountName.constData(),
++ 0, NULL, 0,
++ kSecProtocolTypeAny, kSecAuthenticationTypeDefault,
++ 0, NULL, &itemRef ) ){
++ // just to be sure:
++ itemRef = NULL;
++ }
++ else{
++ isInternetPW = true;
++ err = 0;
++ errMsg = QString();
++ }
++#else
++ itemRef = NULL;
++#endif
++ }
++ if( itemRef ){
++ UInt32 tags[] = { kSecTypeItemAttr };
++ UInt32 formats[] = { CSSM_DB_ATTRIBUTE_FORMAT_STRING };
++ SecKeychainAttributeInfo attrGet = { 1, tags, formats };
++ SecKeychainAttributeList *attrList = NULL;
++ err = SecKeychainItemCopyAttributesAndData( itemRef, &attrGet, NULL, &attrList, NULL, NULL );
++ if( !err ){
++ if( attrList->attr[0].length == sizeof(EntryType) ){
++ memcpy( &etype, attrList->attr[0].data, sizeof(EntryType) );
++ }
++ else if( attrList->attr[0].length ){
++ kDebug() << "Error: key" << key << "item type retrieved is of size" << attrList->attr[0].length << "!=" << sizeof(EntryType);
++ }
++#if INTERNET_TOO
++ else if( isInternetPW ){
++ // this is just a wild guess ...
++ etype = Password;
++ }
++#endif
++ if( entryType ){
++ *entryType = etype;
++ }
++ }
++ SecKeychainItemFreeAttributesAndData( attrList, NULL );
++ CFRelease(itemRef);
++ }
++ kDebug() << "OSXKeychain::ItemType '" << key << "' from keychain " << OSXKeychain::Path(keychain) << "=" << OSTStr(etype) << ", error=" << err;
++ return err;
++}
++
++OSStatus OSXKeychain::RemoveItem(const QString &key, const SecKeychainRef keychain)
++{ const QByteArray accountName( key.toUtf8() );
++ SecKeychainItemRef itemRef;
++ QString errMsg;
++ OSStatus result = SecKeychainFindGenericPassword( keychain, 0, NULL,
++ accountName.size(), accountName.constData(), NULL, NULL, &itemRef );
++ if( isError( result, &errMsg ) ){
++ kDebug() << "Could not find entry" << key << ":" << qPrintable(errMsg);
++ }
++ else{
++ const CFReleaser<SecKeychainItemRef> itemReleaser(itemRef);
++ result = SecKeychainItemDelete(itemRef);
++ if( isError( result, &errMsg ) ){
++ kWarning() << "Could not delete entry" << key << ":" << qPrintable(errMsg);
++ }
++ }
++ return result;
++}
++
++OSStatus OSXKeychain::WriteItem( const QString &key, const QByteArray &value,
++ const SecKeychainRef keychain, SecKeychainItemRef *itemRef, EntryType *entryType, OSXKeychain *osxKeyChain )
++{ const QByteArray accountName( key.toUtf8() );
++ OSStatus err;
++ QString errMsg;
++ SecKeychainItemRef theItem = NULL;
++ bool saveLabel;
++ if( osxKeyChain && osxKeyChain->currentService.size() ){
++ const QByteArray serviceName( osxKeyChain->currentService.toUtf8() );
++ // save the "GenericPassword" item using the service name, which appears to be the only way to write
++ // to the "Where" field shown in the Keychain Utility.
++ err = basicWriteItem( &serviceName, accountName, value, keychain, &theItem );
++ // the service (folder!) string will also appear on the "Name" field, which however can be changed
++ // independently, via the Label attribute.
++ saveLabel = true;
++ }
++ else{
++ err = basicWriteItem( NULL, accountName, value, keychain, &theItem );
++ saveLabel = false;
++ }
++ if( err == errSecDuplicateItem ){
++ // RJVB: the previous implementation was wrong. errSecDuplicateItem means the write failed because of an existing item.
++ // So we have to find that item, and modify it.
++ if( !(err = ReadItem( key, NULL, keychain, &theItem )) ){
++ err = SecKeychainItemModifyAttributesAndData( theItem, NULL, value.size(), value.constData() );
++ if( isError( err, &errMsg ) ){
++ kDebug() << "Key '" << key
++ << "'already exists in keychain but error modifying the existing item: " << qPrintable(errMsg);
++ }
++ }
++ if( !err ){
++ kDebug() << "Key '" << key << "'already existed in keychain: modified the existing item";
++ }
++ }
++ if( !err && saveLabel ){
++ // store the desired text in the label attribute
++ SecKeychainAttribute attr = { kSecLabelItemAttr, accountName.size(), (void*) accountName.constData() };
++ SecKeychainAttributeList attrList = { 1, &attr };
++ QString errMsg;
++ if( isError( (err = SecKeychainItemModifyAttributesAndData( theItem, &attrList, 0, NULL )), &errMsg ) ){
++ kWarning() << "OSXKeychain::WriteItem(" << key << ") couldn't set the desired name/label" << accountName
++ << ":" << err << "=" << qPrintable(errMsg);
++ }
++ }
++ if( !err ){
++ EntryType defType = Stream;
++ if( !entryType ){
++ entryType = &defType;
++ }
++ SecKeychainAttribute attr = { kSecTypeItemAttr, sizeof(EntryType), (void*) entryType };
++ SecKeychainAttributeList attrList = { 1, &attr };
++ QString errMsg;
++ if( isError( (err = SecKeychainItemModifyAttributesAndData( theItem, &attrList, 0, NULL )), &errMsg ) ){
++ kWarning() << "OSXKeychain::WriteItem(" << key << ") couldn't set type to" << OSTStr(*entryType)
++ << ":" << qPrintable(errMsg);
++ }
++ }
++ if( itemRef ){
++ *itemRef = theItem;
++ }
++ else if( theItem ){
++ CFRelease(theItem);
++ }
++ kDebug() << "OSXKeychain::WriteItem '" << key << "' to keychain " << (void*) keychain << ", error=" << err;
++ return err;
++}
++
++OSStatus OSXKeychain::WriteItem( const QString &key, const QByteArray &value,
++ const QString &comment, const SecKeychainRef keychain, EntryType *entryType, OSXKeychain *osxKeyChain )
++{ SecKeychainItemRef itemRef = NULL;
++ OSStatus err = WriteItem( key, value, keychain, &itemRef, entryType, osxKeyChain );
++ if( !err && itemRef ){
++ const QByteArray commentString(comment.toUtf8());
++ if( commentString.size() ){
++ SecKeychainAttribute attr = { kSecCommentItemAttr, commentString.size(), (void*) commentString.constData() };
++ SecKeychainAttributeList attrList = { 1, &attr };
++ QString errMsg;
++ if( isError( (err = SecKeychainItemModifyAttributesAndData( itemRef, &attrList, 0, NULL )), &errMsg ) ){
++ kWarning() << "OSXKeychain::WriteItem(" << key << ") couldn't add comment" << comment
++ << ":" << qPrintable(errMsg);
++ }
++ }
++ CFRelease(itemRef);
++ }
++ return err;
++}
++
++// returns the kSecAccountItemAttr's of all items in the keychain
++OSStatus OSXKeychain::ItemList( SecKeychainRef keychain, QStringList &keyList, OSXKeychain *osxKeyChain )
++{ OSStatus err;
++ SecKeychainSearchRef searchRef[2];
++ bool generateFolderList = ( osxKeyChain && osxKeyChain->isKDEChain && osxKeyChain->generateFolderList );
++
++ keyList.clear();
++ if( generateFolderList ){
++ osxKeyChain->serviceList.clear();
++ if( osxKeyChain->currentService.size() > 0 ){
++ osxKeyChain->serviceList.append(osxKeyChain->currentService);
++ }
++ }
++
++ err = SecKeychainSearchCreateFromAttributes( keychain, kSecGenericPasswordItemClass, NULL, &searchRef[0] );
++#if INTERNET_TOO
++ if( SecKeychainSearchCreateFromAttributes( keychain, kSecInternetPasswordItemClass, NULL, &searchRef[1] ) ){
++ searchRef[1] = NULL;
++ }
++#else
++ searchRef[1] = NULL;
++#endif
++ SecKeychainItemRef item;
++ QString errMsg;
++ if( isError(err, &errMsg) ){
++ kDebug() << "OSXKeychain::ItemList(" << (void*) keychain << "): SecKeychainSearchCreateFromAttributes failed" << qPrintable(errMsg);
++ }
++ else{
++ for( size_t i = 0 ; i < sizeof(searchRef)/sizeof(SecKeychainSearchRef) && !err ; ++i ){
++ if( searchRef[i] ){
++ while( !(err = SecKeychainSearchCopyNext( searchRef[i], &item )) ){
++ if( item ){
++ // whether the item will be listed in the keyList we return: by default it is
++ // (better an item shows up multiple times than not at all).
++ bool listItem = true;
++ SecKeychainAttribute attr = { kSecAccountItemAttr, 0, NULL };
++ SecKeychainAttributeList attrList = { 1, &attr };
++ UInt32 len = 0;
++ if( osxKeyChain && osxKeyChain->isKDEChain ){
++ // try to fetch the item's ServiceItem attribute
++ attr.tag = kSecServiceItemAttr;
++ if( !SecKeychainItemCopyContent( item, NULL, &attrList, &len, NULL ) ){
++ QString lbl = QString::fromUtf8( (char*)attr.data, attr.length );
++ // we got a service item attribute, which is where we store the kwallet folder info.
++ // If we disallow empty attributes, keychain items without service item attribute will
++ // appear in each folder that has a non-empty name. In other words, we allow a folder without name.
++ if( generateFolderList ){
++ // add the "folder" to the list if not already listed
++ if( !osxKeyChain->serviceList.contains(lbl) ){
++ osxKeyChain->serviceList.append(lbl);
++ }
++ }
++ else{
++ // only list the item if it's in the current "folder"
++ listItem = (lbl == osxKeyChain->currentService);
++ }
++ SecKeychainItemFreeContent( &attrList, NULL );
++ }
++ }
++ else{
++ // errors retrieving the service item attribute are ignored
++ }
++ if( listItem ){
++ attr.tag = kSecAccountItemAttr;
++ if( !(err = SecKeychainItemCopyContent( item, NULL, &attrList, &len, NULL )) ){
++ if( attr.length > 0 ){
++ keyList.append(QString::fromUtf8( (char*)attr.data, attr.length ));
++ }
++ SecKeychainItemFreeContent( &attrList, NULL );
++ }
++ else{
++ errMsg = errorString(err);
++ kDebug() << "SecKeychainItemCopyContent returned" << err << "=" << qPrintable(errMsg);
++ }
++ }
++ CFRelease(item);
++ }
++ }
++ if( err ){
++ errMsg = errorString(err);
++ }
++ CFRelease(searchRef[i]);
++ }
++ }
++ }
++ return err;
++}
++
++OSStatus OSXKeychain::Destroy( SecKeychainRef *keychain )
++{ OSStatus err = SecKeychainDelete(*keychain);
++ QString errMsg;
++ if( isError( err, &errMsg ) ){
++ kWarning() << "OSXKeychain::Destroy " << (void*) *keychain << ", error " << qPrintable(errMsg);
++ }
++ else{
++ kWarning() << "OSXKeychain::Destroy " << (void*) *keychain << ", error=" << err;
++ }
++ if( keychain ){
++ CFRelease(*keychain);
++ *keychain = NULL;
++ }
++ return err;
++}
++
++OSStatus OSXKeychain::Destroy( const QString &walletName )
++{ SecKeychainRef keychain;
++ OSStatus err = openKeychain( walletName, &keychain );
++ if( !err && keychain ){
++ err = Destroy(&keychain);
++ }
++ return err;
++}
+diff -urN kdelibs-4.13.3-orig/kdeui/util/qosxkeychain.h kdelibs-4.13.3/kdeui/util/qosxkeychain.h
+--- kdelibs-4.13.3-orig/kdeui/util/qosxkeychain.h 1970-01-01 09:00:00.000000000 +0900
++++ kdelibs-4.13.3/kdeui/util/qosxkeychain.h 2014-09-22 19:47:04.000000000 +0900
+@@ -0,0 +1,278 @@
++/*
++ * @file qosxkeychain.h
++ * This file is part of the KDE project
++ *
++ * Created by René J.V. Bertin on 20140809.
++ * Copyright 2014 RJVB.
++ *
++ * 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 _QOSXKEYCHAIN_H
++
++#include <Security/Security.h>
++#include <Security/SecKeychain.h>
++
++namespace {
++ template <typename T>
++ struct CFReleaser {
++ explicit CFReleaser( const T& r ) : ref( r ) {}
++ ~CFReleaser() { if( ref ){ CFRelease( ref ); } }
++ T ref;
++ };
++
++ template <typename T>
++ struct CPPDeleter {
++ explicit CPPDeleter( const T& r ) : ptr( r ) {}
++ ~CPPDeleter() { if( ptr ){ delete ptr; } }
++ T ptr;
++ };
++
++ template <typename T>
++ struct CPPArrayDeleter {
++ explicit CPPArrayDeleter( const T& r ) : ptr( r ) {}
++ ~CPPArrayDeleter() { if( ptr ){ delete[] ptr; } }
++ T ptr;
++ };
++
++ template <typename T>
++ struct CacheOldValue {
++ explicit CacheOldValue( T &var, const T newVal )
++ : oldVal(var), varRef(var)
++ {
++ var = newVal;
++ }
++ ~CacheOldValue()
++ {
++ varRef = oldVal;
++ }
++ T oldVal, &varRef;
++ };
++}
++
++static inline QString asQString( CFStringRef sr )
++{
++ if( sr ){
++ CFIndex len = CFStringGetLength(sr)*2;
++ const CPPArrayDeleter<char*> buff(new char[len]);
++ if( CFStringGetCString( sr, buff.ptr, len, kCFStringEncodingUTF8 ) ){
++ return QString::fromUtf8(buff.ptr); //RJVB: use UTF8
++ }
++ else if( CFStringGetCString( sr, buff.ptr, len, kCFStringEncodingNonLossyASCII ) ){
++ return QString::fromLocal8Bit(buff.ptr);
++ }
++ else{
++ CFStringGetCString( sr, buff.ptr, len, NULL );
++ return QString::fromLatin1(buff.ptr);
++ }
++ }
++ else{
++ return QString();
++ }
++}
++
++static inline QString errorString( OSStatus s )
++{
++ const CFReleaser<CFStringRef> ref( SecCopyErrorMessageString( s, NULL ) );
++ return asQString( ref.ref );
++}
++
++static inline bool isError( OSStatus s, QString *errMsg )
++{
++ if( errMsg ){
++ *errMsg = errorString(s);
++ }
++ return s != 0;
++}
++
++class OSXKeychain : public QObject
++{
++ Q_OBJECT
++private:
++ SecKeychainRef keyChainRef;
++ QString keyChainPath;
++ bool isDefaultKeychain, generateFolderList;
++
++public:
++ enum EntryType { Unknown='K\?\?\?', Password='KPWD', Map='KMAP', Stream='KSTR' };
++ QString name;
++ QString currentService, lastReadService;
++ QStringList serviceList;
++ bool isKDEChain;
++
++ OSXKeychain();
++ OSXKeychain(const QString &name, bool *isNew=NULL);
++ virtual ~OSXKeychain();
++
++ inline SecKeychainRef reference()
++ {
++ return keyChainRef;
++ }
++ inline QString &path()
++ {
++ return keyChainPath;
++ }
++ inline bool isDefault()
++ {
++ return isDefaultKeychain;
++ }
++ inline bool isOpen()
++ {
++ // we're either a KDE wallet/keychain and we have a valid keyChainRef,
++ // or we're not KDE and IsOpen will return the state of the default
++ // keychain if keyChainRef==NULL.
++ if( !isKDEChain || keyChainRef ){
++ return IsOpen(keyChainRef);
++ }
++ else{
++ return false;
++ }
++ }
++ inline OSStatus lock()
++ {
++ if( !isKDEChain || keyChainRef ){
++ return Lock(keyChainRef);
++ }
++ else{
++ return 0;
++ }
++ }
++ inline OSStatus unLock()
++ {
++ if( !isKDEChain || keyChainRef ){
++ return UnLock(keyChainRef);
++ }
++ else{
++ return 0;
++ }
++ }
++ virtual void close();
++ OSStatus lockSettings(int &closeWhenIdle, unsigned int &idleTimeoutMin);
++ OSStatus setLockSettings(int closeWhenIdle, unsigned int idleTimeoutMin);
++ inline bool hasItem(const QString &key, OSStatus *errReturn, SecKeychainItemRef *itemRef=NULL)
++ {
++ if( !isKDEChain || keyChainRef ){
++ return OSXKeychain::HasItem( key, keyChainRef, errReturn, itemRef );
++ }
++ else{
++ return false;
++ }
++ }
++ inline OSStatus readItem(const QString &key, QByteArray *value, SecKeychainItemRef *itemRef=NULL)
++ {
++ if( !isKDEChain || keyChainRef ){
++ return ReadItem( key, value, keyChainRef, itemRef, this );
++ }
++ else{
++ return 0;
++ }
++ }
++ inline OSStatus itemType(const QString &key, EntryType *entryType)
++ {
++ if( !isKDEChain || keyChainRef ){
++ return ItemType( key, entryType, keyChainRef );
++ }
++ else{
++ return 0;
++ }
++ }
++ inline OSStatus removeItem(const QString &key)
++ {
++ if( !isKDEChain || keyChainRef ){
++ return RemoveItem( key, keyChainRef );
++ }
++ else{
++ return 0;
++ }
++ }
++ inline OSStatus writeItem( const QString &key, const QByteArray &value, EntryType *entryType=NULL )
++ {
++ if( !isKDEChain || keyChainRef ){
++ return WriteItem( key, value, keyChainRef, NULL, entryType, this );
++ }
++ else{
++ return 0;
++ }
++ }
++ inline OSStatus writeItem( const QString &key, const QByteArray &value, const QString &comment,
++ EntryType *entryType=NULL )
++ {
++ if( !isKDEChain || keyChainRef ){
++ return WriteItem( key, value, comment, keyChainRef, entryType, this );
++ }
++ else{
++ return 0;
++ }
++ }
++ inline OSStatus itemList( QStringList &keyList )
++ {
++ if( !isKDEChain || keyChainRef ){
++ return ItemList( keyChainRef, keyList, this );
++ }
++ else{
++ return 0;
++ }
++ }
++ inline QStringList folderList()
++ {
++ if( !isKDEChain || keyChainRef ){
++ QStringList r;
++ CacheOldValue<bool> gFL(generateFolderList, true);
++ ItemList( keyChainRef, r, this );
++ r.clear();
++ return serviceList;
++ }
++ else{
++ return QStringList();
++ }
++ }
++ OSStatus renameItem(const QString ¤tKey, const QString &newKey);
++
++#pragma mark ==== class methods aka static member functions ====
++ static OSStatus KeychainList(QStringList &theList);
++ static QString Path(const SecKeychainRef keychain);
++ static bool IsOpen(const SecKeychainRef keychain);
++ static bool IsOpen(const QString& name);
++ static OSStatus UnLock(const SecKeychainRef keychain);
++ static OSStatus Lock(const SecKeychainRef keychain);
++ static OSStatus Lock(const QString &walletName);
++ /** use the keychain search functions to find the first matching item, if any, returning True if found.
++ The OS X error code is returned through @p errReturn when not NULL, the item itself through @p itemRef.
++ This reference will have to be released with CFRelease() when done with it (when @p itemRef==NULL the
++ function does this release itself).
++ */
++ static bool HasItem(const QString &key,
++ const SecKeychainRef keychain, OSStatus *errReturn, SecKeychainItemRef *itemRef);
++ static OSStatus ReadItem(const QString &key, QByteArray *value,
++ const SecKeychainRef keychain, SecKeychainItemRef *itemRef=NULL, OSXKeychain *osxKeyChain=NULL);
++ static OSStatus ItemType(const QString &key, EntryType *entryType,
++ const SecKeychainRef keychain);
++ static OSStatus RemoveItem(const QString &key, const SecKeychainRef keychain);
++ static OSStatus WriteItem( const QString &key, const QByteArray &value,
++ const SecKeychainRef keychain, SecKeychainItemRef *itemRef=NULL, EntryType *entryType=NULL, OSXKeychain *osxKeyChain=NULL );
++ static OSStatus WriteItem( const QString& key, const QByteArray& value,
++ const QString& comment, const SecKeychainRef keychain, EntryType *entryType, OSXKeychain *osxKeyChain=NULL );
++ static OSStatus ItemList( const SecKeychainRef keychain, QStringList &keyList, OSXKeychain *osxKeyChain=NULL );
++ static OSStatus Destroy( SecKeychainRef *keychain );
++ static OSStatus Destroy( const QString &walletName );
++
++private Q_SLOTS:
++ virtual void slotIdleTimedOut()
++ {}
++};
++
++#define _QOSXKEYCHAIN_H
++#endif
+\ No newline at end of file
+diff -urN kdelibs-4.13.3-orig/kdeui/util/qosxkeychain.h.orig kdelibs-4.13.3/kdeui/util/qosxkeychain.h.orig
+--- kdelibs-4.13.3-orig/kdeui/util/qosxkeychain.h.orig 1970-01-01 09:00:00.000000000 +0900
++++ kdelibs-4.13.3/kdeui/util/qosxkeychain.h.orig 2014-09-22 19:46:10.000000000 +0900
+@@ -0,0 +1,203 @@
++/*
++ * @file qosxkeychain.h
++ * This file is part of the KDE project
++ *
++ * Created by René J.V. Bertin on 20140809.
++ * Copyright 2014 RJVB.
++ *
++ * 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 <Security/Security.h>
++#include <Security/SecKeychain.h>
++
++namespace {
++ template <typename T>
++ struct CFReleaser {
++ explicit CFReleaser( const T& r ) : ref( r ) {}
++ ~CFReleaser() { if( ref ){ CFRelease( ref ); } }
++ T ref;
++ };
++
++ template <typename T>
++ struct CPPDeleter {
++ explicit CPPDeleter( const T& r ) : ptr( r ) {}
++ ~CPPDeleter() { if( ptr ){ delete ptr; } }
++ T ptr;
++ };
++
++ template <typename T>
++ struct CPPArrayDeleter {
++ explicit CPPArrayDeleter( const T& r ) : ptr( r ) {}
++ ~CPPArrayDeleter() { if( ptr ){ delete[] ptr; } }
++ T ptr;
++ };
++
++ template <typename T>
++ struct CacheOldValue {
++ explicit CacheOldValue( T &var, const T newVal )
++ : oldVal(var), varRef(var)
++ {
++ var = newVal;
++ }
++ ~CacheOldValue()
++ {
++ varRef = oldVal;
++ }
++ T oldVal, &varRef;
++ };
++}
++
++static inline QString asQString( CFStringRef sr )
++{ CFIndex len = CFStringGetLength(sr)*2;
++ const CPPArrayDeleter<char*> buff(new char[len]);
++ if( CFStringGetCString( sr, buff.ptr, len, kCFStringEncodingUTF8 ) ){
++ return QString::fromUtf8(buff.ptr); //RJVB: use UTF8
++ }
++ else if( CFStringGetCString( sr, buff.ptr, len, kCFStringEncodingNonLossyASCII ) ){
++ return QString::fromLocal8Bit(buff.ptr);
++ }
++ else{
++ CFStringGetCString( sr, buff.ptr, len, NULL );
++ return QString::fromLatin1(buff.ptr);
++ }
++}
++
++static inline QString errorString( OSStatus s )
++{
++ const CFReleaser<CFStringRef> ref( SecCopyErrorMessageString( s, NULL ) );
++ return asQString( ref.ref );
++}
++
++static inline bool isError( OSStatus s, QString *errMsg )
++{
++ if( errMsg ){
++ *errMsg = errorString(s);
++ }
++ return s != 0;
++}
++
++class OSXKeychain
++{
++private:
++ SecKeychainRef keyChainRef;
++ QString keyChainPath;
++ bool isDefaultKeychain, generateFolderList;
++
++public:
++ enum EntryType { Unknown='K\?\?\?', Password='KPWD', Map='KMAP', Stream='KSTR' };
++ QString name;
++ QString currentService, lastReadService;
++ QStringList serviceList;
++ bool isKDEChain;
++
++ OSXKeychain();
++ OSXKeychain(const QString &name);
++ virtual ~OSXKeychain();
++
++ inline SecKeychainRef reference()
++ {
++ return keyChainRef;
++ }
++ inline QString &path()
++ {
++ return keyChainPath;
++ }
++ inline bool isDefault()
++ {
++ return isDefaultKeychain;
++ }
++ inline bool isOpen()
++ {
++ return IsOpen(keyChainRef);
++ }
++ inline OSStatus lock()
++ {
++ return Lock(keyChainRef);
++ }
++ inline OSStatus unLock()
++ {
++ return UnLock(keyChainRef);
++ }
++ void close();
++ inline bool hasItem(const QString &key, OSStatus *errReturn, SecKeychainItemRef *itemRef=NULL)
++ {
++ // qDebug() << "OSXKeychain::hasItem(" << key << "): scanning '" << name << "'=" << (void*) keyChainRef;
++ return OSXKeychain::HasItem( key, keyChainRef, errReturn, itemRef );
++ }
++ inline OSStatus readItem(const QString &key, QByteArray *value, SecKeychainItemRef *itemRef=NULL)
++ {
++ return ReadItem( key, value, keyChainRef, itemRef, this );
++ }
++ inline OSStatus itemType(const QString &key, EntryType *entryType)
++ {
++ return ItemType( key, entryType, keyChainRef );
++ }
++ inline OSStatus removeItem(const QString &key)
++ {
++ return RemoveItem( key, keyChainRef );
++ }
++ inline OSStatus writeItem( const QString &key, const QByteArray &value, EntryType *entryType=NULL )
++ {
++ return WriteItem( key, value, keyChainRef, NULL, entryType, this );
++ }
++ inline OSStatus writeItem( const QString &key, const QByteArray &value, const QString &comment,
++ EntryType *entryType=NULL )
++ {
++ return WriteItem( key, value, comment, keyChainRef, entryType, this );
++ }
++ inline OSStatus itemList( QStringList &keyList )
++ {
++ return ItemList( keyChainRef, keyList, this );
++ }
++ inline QStringList folderList()
++ {
++ QStringList r;
++ CacheOldValue<bool> gFL(generateFolderList, true);
++ ItemList( keyChainRef, r, this );
++ r.clear();
++ return serviceList;
++ }
++ OSStatus renameItem(const QString ¤tKey, const QString &newKey);
++
++#pragma mark ==== class methods aka static member functions ====
++ static OSStatus KeychainList(QStringList &theList);
++ static QString Path(const SecKeychainRef keychain);
++ static bool IsOpen(const SecKeychainRef keychain);
++ static bool IsOpen(const QString& name);
++ static OSStatus UnLock(const SecKeychainRef keychain);
++ static OSStatus Lock(const SecKeychainRef keychain);
++ static OSStatus Lock(const QString &walletName);
++ /** use the keychain search functions to find the first matching item, if any, returning True if found.
++ The OS X error code is returned through @p errReturn when not NULL, the item itself through @p itemRef.
++ This reference will have to be released with CFRelease() when done with it (when @p itemRef==NULL the
++ function does this release itself).
++ */
++ static bool HasItem(const QString &key,
++ const SecKeychainRef keychain, OSStatus *errReturn, SecKeychainItemRef *itemRef);
++ static OSStatus ReadItem(const QString &key, QByteArray *value,
++ const SecKeychainRef keychain, SecKeychainItemRef *itemRef=NULL, OSXKeychain *osxKeyChain=NULL);
++ static OSStatus ItemType(const QString &key, EntryType *entryType,
++ const SecKeychainRef keychain);
++ static OSStatus RemoveItem(const QString &key, const SecKeychainRef keychain);
++ static OSStatus WriteItem( const QString &key, const QByteArray &value,
++ const SecKeychainRef keychain, SecKeychainItemRef *itemRef=NULL, EntryType *entryType=NULL, OSXKeychain *osxKeyChain=NULL );
++ static OSStatus WriteItem( const QString& key, const QByteArray& value,
++ const QString& comment, const SecKeychainRef keychain, EntryType *entryType, OSXKeychain *osxKeyChain=NULL );
++ static OSStatus ItemList( const SecKeychainRef keychain, QStringList &keyList, OSXKeychain *osxKeyChain=NULL );
++ static OSStatus Destroy( SecKeychainRef *keychain );
++ static OSStatus Destroy( const QString &walletName );
++};
Deleted: trunk/dports/kde/kdelibs4/files/patch-cmake-modules-KDE4Macros.cmake.diff
===================================================================
--- trunk/dports/kde/kdelibs4/files/patch-cmake-modules-KDE4Macros.cmake.diff 2014-10-08 10:38:21 UTC (rev 126339)
+++ trunk/dports/kde/kdelibs4/files/patch-cmake-modules-KDE4Macros.cmake.diff 2014-10-08 11:03:41 UTC (rev 126340)
@@ -1,14 +0,0 @@
---- kdelibs-4.12.5/cmake/modules/KDE4Macros.cmake.orig 2014-04-28 13:37:51.000000000 +0900
-+++ kdelibs-4.12.5/cmake/modules/KDE4Macros.cmake 2014-05-16 21:32:41.000000000 +0900
-@@ -829,9 +829,9 @@
-
- if (Q_WS_MAC)
- list(FIND _SRCS *.icns _icon_position)
-- if(NOT _res_position EQUAL -1)
-+ if(NOT _icon_position EQUAL -1)
- list(GET _SRCS ${_icon_position} _resourcefile)
-- endif(NOT _res_position EQUAL -1)
-+ endif(NOT _icon_position EQUAL -1)
- endif (Q_WS_MAC)
- kde4_add_executable(${_target_NAME} "${_nogui}" ${CMAKE_CURRENT_BINARY_DIR}/${_target_NAME}_dummy.cpp ${_resourcefile})
- target_link_libraries(${_target_NAME} kdeinit_${_target_NAME})
Added: trunk/dports/kde/kdelibs4/files/patch-fixKCrash.diff
===================================================================
--- trunk/dports/kde/kdelibs4/files/patch-fixKCrash.diff (rev 0)
+++ trunk/dports/kde/kdelibs4/files/patch-fixKCrash.diff 2014-10-08 11:03:41 UTC (rev 126340)
@@ -0,0 +1,41 @@
+diff -ur kdelibs-4.13.3-orig/kdeui/util/kcrash.cpp kdelibs-4.13.3/kdeui/util/kcrash.cpp
+--- kdelibs-4.13.3-orig/kdeui/util/kcrash.cpp 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kdeui/util/kcrash.cpp 2014-09-20 15:20:58.000000000 +0900
+@@ -313,7 +313,13 @@
+ crashRecursionCounter++;
+ }
+
+-#if !defined(Q_OS_WIN)
++ // On Apple OS X, closing all FDs now will cause a second (SIGILL) crash,
++ // ending with "Unable to start Dr. Konqi". This is because the libdispatch
++ // library, which can manage multi-threading, has some FDs of its own.
++ //
++ // Note: KCrash closes FDs unconditionally later on if it forks to Dr Konqi
++ // and this program's FDs do not matter if kdeinit starts Dr Konqi.
++#if !defined(Q_OS_WIN) and !defined(Q_OS_MAC)
+ if (!(s_flags & KeepFDs))
+ closeAllFDs();
+ # if defined(Q_WS_X11)
+@@ -520,9 +526,12 @@
+ // This is done because it is dangerous to use fork() in the crash handler
+ // (there can be functions registered to be performed before fork(), for example handling
+ // of malloc locking, which doesn't work when malloc crashes because of heap corruption).
++#ifndef Q_OS_MAC
++ // Fails on Apple OSX+KDE4, because kdeinit4 is using the wrong socket name.
+ if (!(s_flags & AlwaysDirectly)) {
+ startDirectly = !startProcessInternal(argc, argv, waitAndExit, false);
+ }
++#endif
+
+ // If we can't reach kdeinit, we can still at least try to fork()
+ if (startDirectly) {
+@@ -805,7 +814,8 @@
+
+ server.sun_family = AF_UNIX;
+ strcpy(server.sun_path, sock_file);
+- printf("sock_file=%s\n", sock_file);
++ // Use stderr, to make the message visible on the Apple OS X Console log.
++ fprintf(stderr, "KCrash: Connect sock_file=%s\n", sock_file);
+ socklen = sizeof(server);
+ if(connect(s, (struct sockaddr *)&server, socklen) == -1)
+ {
Added: trunk/dports/kde/kdelibs4/files/patch-nativeDialogs.diff
===================================================================
--- trunk/dports/kde/kdelibs4/files/patch-nativeDialogs.diff (rev 0)
+++ trunk/dports/kde/kdelibs4/files/patch-nativeDialogs.diff 2014-10-08 11:03:41 UTC (rev 126340)
@@ -0,0 +1,77 @@
+diff -ur kdelibs-4.13.3-orig/kdeui/widgets/kmainwindow.cpp kdelibs-4.13.3/kdeui/widgets/kmainwindow.cpp
+--- kdelibs-4.13.3-orig/kdeui/widgets/kmainwindow.cpp 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kdeui/widgets/kmainwindow.cpp 2014-09-20 18:52:54.000000000 +0900
+@@ -241,6 +241,8 @@
+
+ q->setAttribute( Qt::WA_DeleteOnClose );
+
++ q->setUnifiedTitleAndToolBarOnMac(true);
++
+ // We handle this functionality (quitting the app) ourselves, with KGlobal::ref/deref.
+ // This makes apps stay alive even if they only have a systray icon visible, or
+ // a progress widget with "keep open" checked, for instance.
+diff -ur kdelibs-4.13.3-orig/kio/kfile/kfiledialog.cpp kdelibs-4.13.3/kio/kfile/kfiledialog.cpp
+--- kdelibs-4.13.3-orig/kio/kfile/kfiledialog.cpp 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kio/kfile/kfiledialog.cpp 2014-09-20 18:52:54.000000000 +0900
+@@ -44,8 +44,8 @@
+ #include "krecentdirs.h"
+ #include "kservice.h"
+
+-/** File dialogs are native by default on Windows. */
+-#if defined(Q_WS_WIN) || defined(Q_WS_MAEMO_5)
++/** File dialogs are native by default on Windows and Mac. */
++#if defined(Q_WS_WIN) || defined(Q_WS_MAEMO_5) || defined(Q_WS_MAC)
+ const bool NATIVE_FILEDIALOGS_BY_DEFAULT = true;
+ #else
+ const bool NATIVE_FILEDIALOGS_BY_DEFAULT = false;
+@@ -252,7 +252,7 @@
+
+ KFileDialog::KFileDialog( const KUrl& startDir, const QString& filter,
+ QWidget *parent, QWidget* customWidget)
+-#ifdef Q_WS_WIN
++#if (defined Q_WS_WIN || defined Q_WS_MAC )
+ : KDialog( parent , Qt::WindowMinMaxButtonsHint),
+ #else
+ : KDialog( parent ),
+@@ -312,8 +312,8 @@
+ connect(fileQWidget, SIGNAL(accepted()), SLOT(accept()));
+ //connect(fileQWidget, SIGNAL(canceled()), SLOT(slotCancel()));
+
+- if (customWidget)
+- d->w->setCustomWidget(QString(), customWidget);
++ if (customWidget){}
++ //d->w->setCustomWidget(QString(), customWidget);
+ }
+
+
+@@ -961,7 +961,7 @@
+ return d->w;
+ }
+
+-#ifdef Q_WS_WIN
++#if (defined Q_WS_WIN || defined Q_WS_MAC)
+ int KFileDialog::exec()
+ {
+ if (!d->native || !KFileDialogPrivate::Native::s_allowNative) {
+@@ -1051,7 +1051,7 @@
+
+ return res;
+ }
+-#endif // Q_WS_WIN
++#endif // Q_WS_WIN || Q_WS_MAC
+
+ #ifdef Q_WS_WIN
+ #define KF_EXTERN extern __declspec(dllimport)
+diff -ur kdelibs-4.13.3-orig/kio/kfile/kfiledialog.h kdelibs-4.13.3/kio/kfile/kfiledialog.h
+--- kdelibs-4.13.3-orig/kio/kfile/kfiledialog.h 2014-07-11 15:42:13.000000000 +0900
++++ kdelibs-4.13.3/kio/kfile/kfiledialog.h 2014-09-20 18:52:54.000000000 +0900
+@@ -749,7 +749,8 @@
+ */
+ static void setStartDir( const KUrl& directory );
+
+-#ifdef Q_WS_WIN
++#if (defined Q_WS_WIN || defined Q_WS_MAC )
++ /** File dialogs are native by default on Windows and MAC. */
+ public Q_SLOTS:
+ int exec();
+ #endif
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/macports-changes/attachments/20141008/fd6083ce/attachment-0001.html>
More information about the macports-changes
mailing list