summaryrefslogtreecommitdiff
path: root/src/syncevo/UserInterface.h
blob: 5248039735107006f59b4f51d105e4f5e537cc36 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/*
 * Copyright (C) 2008-2009 Patrick Ohly <patrick.ohly@gmx.de>
 * Copyright (C) 2009-12 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) version 3.
 *
 * 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */
#ifndef INCL_USERINTERFACE
# define INCL_USERINTERFACE

#include <string>

#include <boost/signals2.hpp>

#include <syncevo/util.h>

#include <syncevo/declarations.h>
SE_BEGIN_CXX

/**
 * This struct wraps keys for storing passwords
 * in configuration system. Some fields might be empty
 * for some passwords. Each field might have different 
 * meaning for each password. Fields using depends on
 * what user actually wants.
 */
struct ConfigPasswordKey {
 public:
    ConfigPasswordKey() : port(0) {}

    /** the user for the password */
    std::string user;
    /** the server for the password */
    std::string server;
    /** the domain name */
    std::string domain;
    /** the remote object */
    std::string object;
    /** the network protocol */
    std::string protocol;
    /** the authentication type */
    std::string authtype;
    /** the network port */
    unsigned int port;
};

/**
 * This interface has to be provided to let SyncEvolution interact
 * with the user. Possible implementations are:
 * - command line: use platform secret storage, ask for password via stdin
 * - D-Bus server: use platform secret storage, relay password requests via D-Bus to UIs
 */
class UserInterface {
 public:
    virtual ~UserInterface() {}

    /**
     * A helper function which interactively asks the user for
     * a certain password. May throw errors.
     *
     * @param passwordName the name of the password in the config file, such as 'proxyPassword'
     * @param descr        A simple string explaining what the password is needed for,
     *                     e.g. "SyncML server". This string alone has to be enough
     *                     for the user to know what the password is for, i.e. the
     *                     string has to be unique.
     * @param key          the key used to retrieve password. Using this instead of ConfigNode is
     *                     to make user interface independent on Configuration Tree
     * @return entered password
     */
    virtual std::string askPassword(const std::string &passwordName,
                                    const std::string &descr,
                                    const ConfigPasswordKey &key) = 0;

    /**
     * A helper function which interactively asks the user for
     * a certain password. May throw errors. Final result will
     * be returned via callbacks. Use this function in code which
     * is currently inside glib event processing, because askPassword()
     * might only work when it is allowed to invoke glib.
     *
     * @param passwordName the name of the password in the config file, such as 'proxyPassword'
     * @param descr        A simple string explaining what the password is needed for,
     *                     e.g. "SyncML server". This string alone has to be enough
     *                     for the user to know what the password is for, i.e. the
     *                     string has to be unique.
     * @param key          the key used to retrieve password. Using this instead of ConfigNode is
     *                     to make user interface independent on Configuration Tree
     */
    virtual void askPasswordAsync(const std::string &passwordName,
                                  const std::string &descr,
                                  const ConfigPasswordKey &key,
                                  const boost::function<void (const std::string &)> &success,
                                  const boost::function<void ()> &failureException);

    /**
     * A helper function which is used for user interface to save
     * a certain password. Currently possibly syncml server. May
     * throw errors.
     * @param passwordName the name of the password in the config file, such as 'proxyPassword'
     * @param password     password to be saved
     * @param key          the key used to store password
     * @return true if ui saves the password and false if not
     */
    virtual bool savePassword(const std::string &passwordName,
                              const std::string &password,
                              const ConfigPasswordKey &key) = 0;

    /**
     * Read from stdin until end of stream. Must be connected to
     * stdin as seen by user (different in command line client
     * and D-Bus server).
     */
    virtual void readStdin(std::string &content) = 0;
};

/**
 * Some ConfigUserInterface implementations check in the system's
 * password manager before asking the user. Backends provide optional
 * access to GNOME keyring (maps to freedesktop.org Secrets D-Bus API)
 * and KWallet (custom protocol in KDE < 4.8, same Secrets API >=
 * 4.8).
 *
 * The following signals are to be invoked by ConfigUserInterface
 * implementations which want to use these extensions. They return
 * true if some backend implemented the request, false otherwise.
 */

/**
 * call one slot after the other, return as soon as the first one
 * returns true
 */
struct TrySlots
{
    typedef bool result_type;

    template<typename InputIterator>
    bool operator()(InputIterator first, InputIterator last) const
    {
        while (first != last) {
            if (*first) {
                return true;
            }
            ++first;
        }
        return false;
    }
};

/**
 * Same as ConfigUserInterface::askPassword(), except that the
 * password is returned as retval. If it was set, then the
 * password was found in the keyring. The return value indicates
 * whether any slot matched the configured keyring.
 *
 * Backends need to be sure that the user wants them to handle
 * the request before doing the work and returning true. They
 * should check the first parameter, the value of the "keyring"
 * configuration option, to determine that.
 *
 * GNOME keyring and KWallet add themselves here and in
 * SavePasswordSignal. KWallet adds itself with priority 0
 * and GNOME keyring with 1, which means that KWallet is called
 * first. It checks whether KDE really is the preferred
 * storage, otherwise defers to GNOME keyring (or any other
 * slot) by returning false.
 */
typedef boost::signals2::signal<bool (const InitStateTri &keyring,
                                      const std::string &passwordName,
                                      const std::string &descr,
                                      const ConfigPasswordKey &key,
                                      InitStateString &password),
                                TrySlots> LoadPasswordSignal;
LoadPasswordSignal &GetLoadPasswordSignal();

static const int INTERNAL_LOAD_PASSWORD_SLOTS = 1;

/**
 * Same as AskPasswordSignal for saving.
 */
typedef boost::signals2::signal<bool (const InitStateTri &keyring,
                                      const std::string &passwordName,
                                      const std::string &password,
                                      const ConfigPasswordKey &key),
                                TrySlots> SavePasswordSignal;
SavePasswordSignal &GetSavePasswordSignal();

static const int INTERNAL_SAVE_PASSWORD_SLOTS = 2;

SE_END_CXX

#endif // INCL_USERINTERFACE