1b98ccdca759e775118d9e87a48e7700ff90c283
[platform/upstream/syncevolution.git] / src / backends / kde / KDEPlatform.cpp
1 /*
2  * Copyright (C) 2011 Dinesh <saidinesh5@gmail.com>
3  * Copyright (C) 2012 Intel Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) version 3.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18  * 02110-1301  USA
19  */
20
21 #include <config.h>
22
23 #ifdef USE_KDE_KWALLET
24
25 #include "KDEPlatform.h"
26
27 #include <syncevo/SyncContext.h>
28 #include <syncevo/SyncConfig.h>
29
30 // Qt headers may define "signals" as preprocessor symbol,
31 // which conflicts with glib C headers included indirectly
32 // above. This order of header files works.
33 #include <QtCore/QCoreApplication>
34 #include <QtCore/QString>
35 #include <QtCore/QLatin1String>
36 #include <QtCore/QDebug>
37 #include <QtDBus/QDBusConnection>
38
39 #include <KApplication>
40 #include <KAboutData>
41 #include <KCmdLineArgs>
42
43 #include <kwallet.h>
44
45 #include <syncevo/declarations.h>
46 SE_BEGIN_CXX
47
48 // TODO: this check should be global
49 static bool HaveDBus;
50
51 void KDEInitMainSlot(const char *appname)
52 {
53     // Very simple check. API doesn't say whether asking
54     // for the bus connection will connect immediately.
55     QDBusConnection dbus = QDBusConnection::sessionBus();
56     HaveDBus = dbus.isConnected();
57
58     if (!HaveDBus) {
59         // KApplication has been seen to crash without D-Bus (BMC #25596).
60         // Bail out here if we don't have D-Bus.
61         return;
62     }
63
64     //QCoreApplication *app;
65     int argc = 1;
66     static char *argv[] = { const_cast<char *>(appname), NULL };
67     KAboutData aboutData(// The program name used internally.
68                          "syncevolution",
69                          // The message catalog name
70                          // If null, program name is used instead.
71                          0,
72                          // A displayable program name string.
73                          ki18n("SyncEvolution"),
74                          // The program version string.
75                          VERSION,
76                          // Short description of what the app does.
77                          ki18n("Lets Akonadi synchronize with a SyncML Peer"),
78                          // The license this code is released under
79                          KAboutData::License_GPL,
80                          // Copyright Statement
81                          ki18n("(c) 2010-12"),
82                          // Optional text shown in the About box.
83                          // Can contain any information desired.
84                          ki18n(""),
85                          // The program homepage string.
86                          "http://www.syncevolution.org/",
87                          // The bug report email address
88                          "syncevolution@syncevolution.org");
89
90     KCmdLineArgs::init(argc, argv, &aboutData);
91     if (!kapp) {
92         // Don't allow KApplication to mess with SIGINT/SIGTERM.
93         // Restore current behavior after construction.
94         struct sigaction oldsigint, oldsigterm;
95         sigaction(SIGINT, NULL, &oldsigint);
96         sigaction(SIGTERM, NULL, &oldsigterm);
97
98         // Explicitly disable GUI mode in the KApplication.  Otherwise
99         // the whole binary will fail to run when there is no X11
100         // display.
101         new KApplication(false);
102         //To stop KApplication from spawning it's own DBus Service ... Will have to patch KApplication about this
103         QDBusConnection::sessionBus().unregisterService("org.syncevolution.syncevolution-"+QString::number(getpid()));
104
105         sigaction(SIGINT, &oldsigint, NULL);
106         sigaction(SIGTERM, &oldsigterm, NULL);
107     }
108 }
109
110 static bool UseKWallet(const InitStateTri &keyring,
111                        int slotCount)
112 {
113     // Disabled by user?
114     if (keyring.getValue() == InitStateTri::VALUE_FALSE) {
115         return false;
116     }
117
118     // When both (presumably) GNOME keyring and KWallet are available,
119     // check if the user really wanted KWallet before using KWallet
120     // instead of GNOME keyring. This default favors GNOME keyring
121     // over KWallet because SyncEvolution traditionally used that.
122     if (keyring.getValue() == InitStateTri::VALUE_TRUE &&
123         slotCount > 1) {
124         return false;
125     }
126
127     // If explicitly selected, it must be us.
128     if (keyring.getValue() == InitStateTri::VALUE_STRING &&
129         !boost::iequals(keyring.get(), "KDE")) {
130         return false;
131     }
132
133     // User wants KWallet, but is it usable?
134     if (!HaveDBus) {
135         SE_THROW("KDE KWallet requested, but it is not usable (running outside of a D-Bus session)");
136     }
137
138     // Use KWallet.
139     return true;
140 }
141
142 /**
143  * Here we use server sync url without protocol prefix and
144  * user account name as the key in the keyring.
145  *
146  * Also since the KWallet's API supports only storing (key,password)
147  * or Map<QString,QString> , the former is used.
148  */
149 bool KWalletLoadPasswordSlot(const InitStateTri &keyring,
150                              const std::string &passwordName,
151                              const std::string &descr,
152                              const ConfigPasswordKey &key,
153                              InitStateString &password)
154 {
155     if (!UseKWallet(keyring,
156                     GetLoadPasswordSignal().num_slots() - INTERNAL_LOAD_PASSWORD_SLOTS)) {
157         return false;
158     }
159
160     QString walletPassword;
161     QString walletKey = QString(key.user.c_str()) + ',' +
162         QString(key.domain.c_str())+ ','+
163         QString(key.server.c_str())+','+
164         QString(key.object.c_str())+','+
165         QString(key.protocol.c_str())+','+
166         QString(key.authtype.c_str())+','+
167         QString::number(key.port);
168
169     QString wallet_name = KWallet::Wallet::NetworkWallet();
170     //QString folder = QString::fromUtf8("Syncevolution");
171     const QLatin1String folder("Syncevolution");
172
173     if (!KWallet::Wallet::keyDoesNotExist(wallet_name, folder, walletKey)) {
174         KWallet::Wallet *wallet = KWallet::Wallet::openWallet(wallet_name, -1, KWallet::Wallet::Synchronous);
175         if (wallet &&
176             wallet->setFolder(folder) &&
177             wallet->readPassword(walletKey, walletPassword) == 0) {
178             password = walletPassword.toStdString();
179         }
180     }
181
182     return true;
183 }
184
185
186 bool KWalletSavePasswordSlot(const InitStateTri &keyring,
187                              const std::string &passwordName,
188                              const std::string &password,
189                              const ConfigPasswordKey &key)
190 {
191     if (!UseKWallet(keyring,
192                     GetSavePasswordSignal().num_slots() - INTERNAL_SAVE_PASSWORD_SLOTS)) {
193         return false;
194     }
195
196     /* It is possible to let CmdlineSyncClient decide which of fields in ConfigPasswordKey it would use
197      * but currently only use passed key instead */
198
199     // write password to keyring
200     const QString walletKey = QString::fromStdString(key.user + ',' +
201                                                      key.domain + ',' + key.server + ',' + key.object + ',' +
202                                                      key.protocol + ',' + key.authtype + ',')+ QString::number(key.port);
203     const QString walletPassword = QString::fromStdString(password);
204
205     bool write_success = false;
206     const QString wallet_name = KWallet::Wallet::NetworkWallet();
207     const QLatin1String folder("Syncevolution");
208     KWallet::Wallet *wallet = KWallet::Wallet::openWallet(wallet_name, -1,
209                                                           KWallet::Wallet::Synchronous);
210     if (wallet) {
211         if (!wallet->hasFolder(folder)) {
212             wallet->createFolder(folder);
213         }
214
215         if (wallet->setFolder(folder) &&
216             wallet->writePassword(walletKey, walletPassword) == 0) {
217             write_success = true;
218         }
219     }
220
221     if (!write_success) {
222         SyncContext::throwError("Saving " + passwordName + " in KWallet failed.");
223     }
224     return write_success;
225 }
226
227 SE_END_CXX
228
229 #endif // USE_KDE_WALLET