diff --git a/src/common/config.py b/src/common/config.py
index d4d6a7baca5af290ec618a98c5796f3deb297735..884da1df55a06551e8413c5b4568bef9843503b2 100644
--- a/src/common/config.py
+++ b/src/common/config.py
@@ -247,6 +247,7 @@ class Config:
 		'confirm_metacontacts': [ opt_str, '', _('Should we show the confirm metacontacts creation dialog or not? Empty string means we never show the dialog.')],
 		'enable_negative_priority': [ opt_bool, False, _('If True, you will be able to set a negative priority to your account in account modification window. BE CAREFUL, when you are logged in with a negative priority, you will NOT receive any message from your server.')],
 		'use_gnomekeyring': [opt_bool, True, _('If True, Gajim will use Gnome Keyring (if available) to store account passwords.')],
+		'use_kwalletcli': [opt_bool, True, _('If True, Gajim will use KDE Wallet (if kwalletcli is available) to store account passwords.')],
 		'show_contacts_number': [opt_bool, True, _('If True, Gajim will show number of online and total contacts in account and group rows.')],
 		'treat_incoming_messages': [ opt_str, '', _('Can be empty, \'chat\' or \'normal\'. If not empty, treat all incoming messages as if they were of this type')],
 		'scroll_roster_to_last_message': [opt_bool, True, _('If True, Gajim will scroll and select the contact who sent you the last message, if chat window is not already opened.')],
diff --git a/src/common/kwalletbinding.py b/src/common/kwalletbinding.py
new file mode 100644
index 0000000000000000000000000000000000000000..a2562352cffe83310b60fcf93d9117acd0cdf9e5
--- /dev/null
+++ b/src/common/kwalletbinding.py
@@ -0,0 +1,75 @@
+# -*- coding:utf-8 -*-
+## src/common/kwalletbinding.py
+##
+## Copyright (c) 2009 Thorsten Glaser <t.glaser AT tarent.de>
+##
+## This file is part of Gajim.
+##
+## Gajim is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published
+## by the Free Software Foundation; version 3 only. This file is
+## also available under the terms of The MirOS Licence.
+##
+## Gajim is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
+##
+
+__all__ = ['kwallet_available', 'kwallet_get', 'kwallet_put']
+
+import subprocess
+
+
+def kwallet_available():
+	"""Return True if kwalletcli can be run, False otherwise."""
+	p = subprocess.Popen(["kwalletcli", "-qV"])
+	p.communicate()
+	if p.returncode == 0:
+		return True
+	return False
+
+
+def kwallet_get(folder, entry):
+	"""Retrieve a passphrase from the KDE Wallet via kwalletcli.
+
+	Arguments:
+	• folder: The top-level category to use (normally the programme name)
+	• entry: The key of the entry to retrieve
+
+	Returns the passphrase as unicode, False if it cannot be found,
+	or None if an error occured.
+
+	"""
+	p = subprocess.Popen(["kwalletcli", "-q", "-f", folder.encode('utf-8'),
+	 "-e", entry.encode('utf-8')], stdout=subprocess.PIPE)
+	pw = p.communicate()[0]
+	if p.returncode == 0:
+		return unicode(pw.decode('utf-8'))
+	if p.returncode == 1 or p.returncode == 4:
+		# ENOENT
+		return False
+	# error
+	return None
+
+
+def kwallet_put(folder, entry, passphrase):
+	"""Store a passphrase into the KDE Wallet via kwalletcli.
+
+	Arguments:
+	• folder: The top-level category to use (normally the programme name)
+	• entry: The key of the entry to store
+	• passphrase: The value to store
+
+	Returns True on success, False otherwise.
+
+	"""
+	p = subprocess.Popen(["kwalletcli", "-q", "-f", folder.encode('utf-8'),
+	 "-e", entry.encode('utf-8'), "-P"], stdin=subprocess.PIPE)
+	p.communicate(passphrase.encode('utf-8'))
+	if p.returncode == 0:
+		return True
+	return False
diff --git a/src/common/passwords.py b/src/common/passwords.py
index a236b3c1ef78d4a11b680f2ee7e76bd99a71dd14..98a7f61d975b8eae8dd873218e92749cb30081a6 100644
--- a/src/common/passwords.py
+++ b/src/common/passwords.py
@@ -7,6 +7,7 @@
 ## Copyright (C) 2007 Jean-Marie Traissard <jim AT lapin.org>
 ##                    Julien Pivotto <roidelapluie AT gmail.com>
 ## Copyright (C) 2008 Stephan Erb <steve-e AT h3c.de>
+## Copyright (c) 2009 Thorsten Glaser <t.glaser AT tarent.de>
 ##
 ## This file is part of Gajim.
 ##
@@ -27,9 +28,11 @@ __all__ = ['get_password', 'save_password']
 
 import warnings
 from common import gajim
+from common import kwalletbinding
 
 USER_HAS_GNOMEKEYRING = False
 USER_USES_GNOMEKEYRING = False
+USER_HAS_KWALLETCLI = False
 gnomekeyring = None
 
 class PasswordStorage(object):
@@ -42,8 +45,11 @@ class PasswordStorage(object):
 class SimplePasswordStorage(PasswordStorage):
 	def get_password(self, account_name):
 		passwd = gajim.config.get_per('accounts', account_name, 'password')
-		if passwd and passwd.startswith('gnomekeyring:'):
-			return None # this is not a real password, it's a gnome keyring token
+		if passwd and (passwd.startswith('gnomekeyring:') or \
+		 passwd == '<kwallet>'):
+			# this is not a real password, it's either a gnome
+			# keyring token or stored in the KDE wallet
+			return None
 		else:
 			return passwd
 
@@ -65,7 +71,7 @@ class GnomePasswordStorage(PasswordStorage):
 
 	def get_password(self, account_name):
 		conf = gajim.config.get_per('accounts', account_name, 'password')
-		if conf is None:
+		if conf is None or conf == '<kwallet>':
 			return None
 		if not conf.startswith('gnomekeyring:'):
 			password = conf
@@ -129,6 +135,45 @@ class GnomePasswordStorage(PasswordStorage):
 		if account_name in gajim.connections:
 			gajim.connections[account_name].password = password
 
+class KWalletPasswordStorage(PasswordStorage):
+	def get_password(self, account_name):
+		pw = gajim.config.get_per('accounts', account_name, 'password')
+		if not pw or pw.startswith('gnomekeyring:'):
+			# unset, empty or not ours
+			return None
+		if pw != '<kwallet>':
+			# migrate the password
+			if kwalletbinding.kwallet_put('gajim', account_name, pw):
+				gajim.config.set_per('accounts', account_name, 'password',
+				 '<kwallet>')
+			else:
+				# stop using the KDE Wallet
+				set_storage(SimplePasswordStorage())
+			return pw
+		pw = kwalletbinding.kwallet_get('gajim', account_name)
+		if pw is None:
+			# stop using the KDE Wallet
+			set_storage(SimplePasswordStorage())
+		if not pw:
+			# False, None, or the empty string
+			return None
+		return pw
+
+	def save_password(self, account_name, password):
+		if not kwalletbinding.kwallet_put('gajim', account_name, password):
+			# stop using the KDE Wallet
+			set_storage(SimplePasswordStorage())
+			storage.save_password(account_name, password)
+			return
+		pwtoken = '<kwallet>'
+		if not password:
+			# no sense in looking up the empty string in the KWallet
+			pwtoken = ''
+		gajim.config.set_per('accounts', account_name, 'password', pwtoken)
+		if account_name in gajim.connections:
+			gajim.connections[account_name].password = password
+
+
 storage = None
 def get_storage():
 	global storage
@@ -150,11 +195,16 @@ def get_storage():
 		if USER_USES_GNOMEKEYRING:
 			try:
 				storage = GnomePasswordStorage()
-			except gnomekeyring.NoKeyringDaemonError:
-				storage = SimplePasswordStorage()
-			except gnomekeyring.DeniedError:
-				storage = SimplePasswordStorage()
-		else:
+			except (gnomekeyring.NoKeyringDaemonError, gnomekeyring.DeniedError):
+				storage = None
+		if storage is None:
+			if gajim.config.get('use_kwalletcli'):
+				global USER_HAS_KWALLETCLI
+				if kwalletbinding.kwallet_available():
+					USER_HAS_KWALLETCLI = True
+				if USER_HAS_KWALLETCLI:
+					storage = KWalletPasswordStorage()
+		if storage is None:
 			storage = SimplePasswordStorage()
 	return storage
 
diff --git a/src/features_window.py b/src/features_window.py
index e402339d1dd8ff3c25b9e6d7095692f408133658..ebe00155808d24ca5142ebf044968044b0129fe2 100644
--- a/src/features_window.py
+++ b/src/features_window.py
@@ -30,6 +30,7 @@ import gtkgui_helpers
 
 from common import gajim
 from common import helpers
+from common import kwalletbinding
 
 class FeaturesWindow:
 	'''Class for features window'''
@@ -66,9 +67,9 @@ class FeaturesWindow:
 				_('Gajim session is stored on logout and restored on login.'),
 				_('Requires python-gnome2.'),
 				_('Feature not available under Windows.')),
-			_('Password encryption'): (self.gnome_keyring_available,
+			_('Password encryption'): (self.some_keyring_available,
 				_('Passwords can be stored securely and not just in plaintext.'),
-				_('Requires gnome-keyring and python-gnome2-desktop.'),
+				_('Requires gnome-keyring and python-gnome2-desktop, or kwalletcli.'),
 				_('Feature not available under Windows.')),
 			_('SRV'): (self.srv_available,
 				_('Ability to connect to servers which are using SRV records.'),
@@ -200,9 +201,11 @@ class FeaturesWindow:
 			return False
 		return True
 
-	def gnome_keyring_available(self):
+	def some_keyring_available(self):
 		if os.name == 'nt':
 			return False
+		if kwalletbinding.kwallet_available():
+			return True
 		try:
 			import gnomekeyring
 		except Exception: