1 /*
2     qgpgmenewcryptoconfig.cpp
3 
4     This file is part of qgpgme, the Qt API binding for gpgme
5     Copyright (c) 2010 Klarälvdalens Datakonsult AB
6     Copyright (c) 2016 by Bundesamt für Sicherheit in der Informationstechnik
7     Software engineering by Intevation GmbH
8 
9     QGpgME is free software; you can redistribute it and/or
10     modify it under the terms of the GNU General Public License as
11     published by the Free Software Foundation; either version 2 of the
12     License, or (at your option) any later version.
13 
14     QGpgME is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17     General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with this program; if not, write to the Free Software
21     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 
23     In addition, as a special exception, the copyright holders give
24     permission to link the code of this program with any edition of
25     the Qt library by Trolltech AS, Norway (or with modified versions
26     of Qt that use the same license as Qt), and distribute linked
27     combinations including the two.  You must obey the GNU General
28     Public License in all respects for all of the code used other than
29     Qt.  If you modify this file, you may extend this exception to
30     your version of the file, but you are not obligated to do so.  If
31     you do not wish to do so, delete this exception statement from
32     your version.
33 */
34 
35 #ifdef HAVE_CONFIG_H
36  #include "config.h"
37 #endif
38 
39 #include "qgpgmenewcryptoconfig.h"
40 
41 #include <QDebug>
42 #include "qgpgme_debug.h"
43 
44 #include <QFile>
45 #include <QDir>
46 
47 #include "global.h"
48 #include "error.h"
49 
50 
51 #include <sstream>
52 #include <string>
53 #include <functional>
54 #include <cassert>
55 #include <functional>
56 
57 using namespace QGpgME;
58 using namespace GpgME;
59 using namespace GpgME::Configuration;
60 
61 namespace
62 {
63 struct Select1St {
64     template <typename U, typename V>
operator ()__anon41f0527f0111::Select1St65     const U &operator()(const std::pair<U, V> &p) const
66     {
67         return p.first;
68     }
69     template <typename U, typename V>
operator ()__anon41f0527f0111::Select1St70     const U &operator()(const QPair<U, V> &p) const
71     {
72         return p.first;
73     }
74 };
75 }
76 
77 // Just for the Q_ASSERT in the dtor. Not thread-safe, but who would
78 // have 2 threads talking to gpgconf anyway? :)
79 static bool s_duringClear = false;
80 
QGpgMENewCryptoConfig()81 QGpgMENewCryptoConfig::QGpgMENewCryptoConfig()
82     :  m_parsed(false)
83 {
84 }
85 
~QGpgMENewCryptoConfig()86 QGpgMENewCryptoConfig::~QGpgMENewCryptoConfig()
87 {
88     clear();
89 }
90 
reloadConfiguration(bool)91 void QGpgMENewCryptoConfig::reloadConfiguration(bool)
92 {
93     clear();
94 
95     Error error;
96     const std::vector<Component> components = Component::load(error);
97 #ifndef NDEBUG
98     {
99         std::stringstream ss;
100         ss << "error: " << error
101            << "components:\n";
102         std::copy(components.begin(), components.end(),
103                   std::ostream_iterator<Component>(ss, "\n"));
104         qCDebug(QGPGME_LOG) << ss.str().c_str();
105     }
106 #endif
107 #if 0
108     TODO port?
109     if (error && showErrors) {
110         const QString wmsg = i18n("<qt>Failed to execute gpgconf:<p>%1</p></qt>", QString::fromLocal8Bit(error.asString()));
111         qCWarning(QGPGME_LOG) << wmsg; // to see it from test_cryptoconfig.cpp
112         KMessageBox::error(0, wmsg);
113     }
114 #endif
115     Q_FOREACH(const Component & c, components) {
116         const std::shared_ptr<QGpgMENewCryptoConfigComponent> comp(new QGpgMENewCryptoConfigComponent);
117         comp->setComponent(c);
118         m_componentsByName[ comp->name() ] = comp;
119     }
120     m_parsed = true;
121 }
122 
componentList() const123 QStringList QGpgMENewCryptoConfig::componentList() const
124 {
125     if (!m_parsed) {
126         const_cast<QGpgMENewCryptoConfig *>(this)->reloadConfiguration(true);
127     }
128     QStringList result;
129     std::transform(m_componentsByName.begin(), m_componentsByName.end(),
130                    std::back_inserter(result),
131                    mem_fn(&QGpgMENewCryptoConfigComponent::name));
132     return result;
133 }
134 
component(const QString & name) const135 QGpgMENewCryptoConfigComponent *QGpgMENewCryptoConfig::component(const QString &name) const
136 {
137     if (!m_parsed) {
138         const_cast<QGpgMENewCryptoConfig *>(this)->reloadConfiguration(false);
139     }
140     return m_componentsByName.value(name).get();
141 }
142 
sync(bool runtime)143 void QGpgMENewCryptoConfig::sync(bool runtime)
144 {
145     Q_FOREACH(const std::shared_ptr<QGpgMENewCryptoConfigComponent> &c, m_componentsByName)
146     c->sync(runtime);
147 }
148 
clear()149 void QGpgMENewCryptoConfig::clear()
150 {
151     s_duringClear = true;
152     m_componentsByName.clear();
153     s_duringClear = false;
154     m_parsed = false; // next call to componentList/component will need to run gpgconf again
155 }
156 
157 ////
158 
QGpgMENewCryptoConfigComponent()159 QGpgMENewCryptoConfigComponent::QGpgMENewCryptoConfigComponent()
160     : CryptoConfigComponent(),
161       m_component()
162 {
163 
164 }
165 
setComponent(const Component & component)166 void QGpgMENewCryptoConfigComponent::setComponent(const Component &component)
167 {
168     m_component = component;
169     m_groupsByName.clear();
170 
171     std::shared_ptr<QGpgMENewCryptoConfigGroup> group;
172 
173     const std::vector<Option> options = m_component.options();
174     Q_FOREACH(const Option & o, options)
175     if (o.flags() & Group) {
176         if (group) {
177             m_groupsByName[group->name()] = group;
178         }
179         group.reset(new QGpgMENewCryptoConfigGroup(shared_from_this(), o));
180     } else if (group) {
181         const std::shared_ptr<QGpgMENewCryptoConfigEntry> entry(new QGpgMENewCryptoConfigEntry(group, o));
182         const QString name = entry->name();
183         group->m_entryNames.push_back(name);
184         group->m_entriesByName[name] = entry;
185     } else {
186         qCWarning(QGPGME_LOG) << "found no group for entry" << o.name() << "of component" << name();
187     }
188     if (group) {
189         m_groupsByName[group->name()] = group;
190     }
191 
192 }
193 
~QGpgMENewCryptoConfigComponent()194 QGpgMENewCryptoConfigComponent::~QGpgMENewCryptoConfigComponent() {}
195 
name() const196 QString QGpgMENewCryptoConfigComponent::name() const
197 {
198     return QString::fromUtf8(m_component.name());
199 }
200 
description() const201 QString QGpgMENewCryptoConfigComponent::description() const
202 {
203     return QString::fromUtf8(m_component.description());
204 }
205 
groupList() const206 QStringList QGpgMENewCryptoConfigComponent::groupList() const
207 {
208     QStringList result;
209     result.reserve(m_groupsByName.size());
210     std::transform(m_groupsByName.begin(), m_groupsByName.end(),
211                    std::back_inserter(result),
212                    std::mem_fn(&QGpgMENewCryptoConfigGroup::name));
213     return result;
214 }
215 
group(const QString & name) const216 QGpgMENewCryptoConfigGroup *QGpgMENewCryptoConfigComponent::group(const QString &name) const
217 {
218     return m_groupsByName.value(name).get();
219 }
220 
sync(bool runtime)221 void QGpgMENewCryptoConfigComponent::sync(bool runtime)
222 {
223     Q_UNUSED(runtime) // runtime is always set by engine_gpgconf
224     if (const Error err = m_component.save()) {
225         qCWarning(QGPGME_LOG) << ":"
226             << "Error from gpgconf while saving configuration: %1"
227             << QString::fromLocal8Bit(err.asString());
228     }
229 }
230 
231 ////
232 
QGpgMENewCryptoConfigGroup(const std::shared_ptr<QGpgMENewCryptoConfigComponent> & comp,const Option & option)233 QGpgMENewCryptoConfigGroup::QGpgMENewCryptoConfigGroup(const std::shared_ptr<QGpgMENewCryptoConfigComponent> &comp, const Option &option)
234     : CryptoConfigGroup(),
235       m_component(comp),
236       m_option(option)
237 {
238 }
239 
~QGpgMENewCryptoConfigGroup()240 QGpgMENewCryptoConfigGroup::~QGpgMENewCryptoConfigGroup() {}
241 
name() const242 QString QGpgMENewCryptoConfigGroup::name() const
243 {
244     return QString::fromUtf8(m_option.name());
245 }
246 
description() const247 QString QGpgMENewCryptoConfigGroup::description() const
248 {
249     return QString::fromUtf8(m_option.description());
250 }
251 
path() const252 QString QGpgMENewCryptoConfigGroup::path() const
253 {
254     if (const std::shared_ptr<QGpgMENewCryptoConfigComponent> c = m_component.lock()) {
255         return c->name() + QLatin1Char('/') + name();
256     } else {
257         return QString();
258     }
259 }
260 
level() const261 CryptoConfigEntry::Level QGpgMENewCryptoConfigGroup::level() const
262 {
263     // two casts to make SunCC happy:
264     return static_cast<CryptoConfigEntry::Level>(static_cast<unsigned int>(m_option.level()));
265 }
266 
entryList() const267 QStringList QGpgMENewCryptoConfigGroup::entryList() const
268 {
269     return m_entryNames;
270 }
271 
entry(const QString & name) const272 QGpgMENewCryptoConfigEntry *QGpgMENewCryptoConfigGroup::entry(const QString &name) const
273 {
274     return m_entriesByName.value(name).get();
275 }
276 
urlpart_encode(const QString & str)277 static QString urlpart_encode(const QString &str)
278 {
279     QString enc(str);
280     enc.replace(QLatin1Char('%'), QStringLiteral("%25"));   // first!
281     enc.replace(QLatin1Char(':'), QStringLiteral("%3a"));
282     //qCDebug(QGPGME_LOG) <<"  urlpart_encode:" << str <<" ->" << enc;
283     return enc;
284 }
285 
urlpart_decode(const QString & str)286 static QString urlpart_decode(const QString &str)
287 {
288     return QUrl::fromPercentEncoding(str.toLatin1());
289 }
290 
291 // gpgconf arg type number -> NewCryptoConfigEntry arg type enum mapping
knownArgType(int argType,bool & ok)292 static QGpgME::CryptoConfigEntry::ArgType knownArgType(int argType, bool &ok)
293 {
294     ok = true;
295     switch (argType) {
296     case 0: // none
297         return QGpgME::CryptoConfigEntry::ArgType_None;
298     case 1: // string
299         return QGpgME::CryptoConfigEntry::ArgType_String;
300     case 2: // int32
301         return QGpgME::CryptoConfigEntry::ArgType_Int;
302     case 3: // uint32
303         return QGpgME::CryptoConfigEntry::ArgType_UInt;
304     case 32: // pathname
305         return QGpgME::CryptoConfigEntry::ArgType_Path;
306     case 33: // ldap server
307         return QGpgME::CryptoConfigEntry::ArgType_LDAPURL;
308     default:
309         ok = false;
310         return QGpgME::CryptoConfigEntry::ArgType_None;
311     }
312 }
313 
QGpgMENewCryptoConfigEntry(const std::shared_ptr<QGpgMENewCryptoConfigGroup> & group,const Option & option)314 QGpgMENewCryptoConfigEntry::QGpgMENewCryptoConfigEntry(const std::shared_ptr<QGpgMENewCryptoConfigGroup> &group, const Option &option)
315     : m_group(group), m_option(option)
316 {
317 }
318 
319 #if 0
320 QVariant QGpgMENewCryptoConfigEntry::stringToValue(const QString &str, bool unescape) const
321 {
322     const bool isString = isStringType();
323 
324     if (isList()) {
325         if (argType() == ArgType_None) {
326             bool ok = true;
327             const QVariant v = str.isEmpty() ? 0U : str.toUInt(&ok);
328             if (!ok) {
329                 qCWarning(QGPGME_LOG) << "list-of-none should have an unsigned int as value:" << str;
330             }
331             return v;
332         }
333         QList<QVariant> lst;
334         QStringList items = str.split(',', QString::SkipEmptyParts);
335         for (QStringList::const_iterator valit = items.constBegin(); valit != items.constEnd(); ++valit) {
336             QString val = *valit;
337             if (isString) {
338                 if (val.isEmpty()) {
339                     lst << QVariant(QString());
340                     continue;
341                 } else if (unescape) {
342                     if (val[0] != '"') { // see README.gpgconf
343                         qCWarning(QGPGME_LOG) << "String value should start with '\"' :" << val;
344                     }
345                     val = val.mid(1);
346                 }
347             }
348             lst << QVariant(unescape ? gpgconf_unescape(val) : val);
349         }
350         return lst;
351     } else { // not a list
352         QString val(str);
353         if (isString) {
354             if (val.isEmpty()) {
355                 return QVariant(QString());    // not set  [ok with lists too?]
356             } else if (unescape) {
357                 if (val[0] != '"') { // see README.gpgconf
358                     qCWarning(QGPGME_LOG) << "String value should start with '\"' :" << val;
359                 }
360                 val = val.mid(1);
361             }
362         }
363         return QVariant(unescape ? gpgconf_unescape(val) : val);
364     }
365 }
366 #endif
367 
~QGpgMENewCryptoConfigEntry()368 QGpgMENewCryptoConfigEntry::~QGpgMENewCryptoConfigEntry()
369 {
370 #ifndef NDEBUG
371     if (!s_duringClear && m_option.dirty())
372         qCWarning(QGPGME_LOG) << "Deleting a QGpgMENewCryptoConfigEntry that was modified (" << m_option.description() << ")"
373                                       << "You forgot to call sync() (to commit) or clear() (to discard)";
374 #endif
375 }
376 
name() const377 QString QGpgMENewCryptoConfigEntry::name() const
378 {
379     return QString::fromUtf8(m_option.name());
380 }
381 
description() const382 QString QGpgMENewCryptoConfigEntry::description() const
383 {
384     return QString::fromUtf8(m_option.description());
385 }
386 
path() const387 QString QGpgMENewCryptoConfigEntry::path() const
388 {
389     if (const std::shared_ptr<QGpgMENewCryptoConfigGroup> g = m_group.lock()) {
390         return g->path() + QLatin1Char('/') + name();
391     } else {
392         return QString();
393     }
394 }
395 
isOptional() const396 bool QGpgMENewCryptoConfigEntry::isOptional() const
397 {
398     return m_option.flags() & Optional;
399 }
400 
isReadOnly() const401 bool QGpgMENewCryptoConfigEntry::isReadOnly() const
402 {
403     return m_option.flags() & NoChange;
404 }
405 
isList() const406 bool QGpgMENewCryptoConfigEntry::isList() const
407 {
408     return m_option.flags() & List;
409 }
410 
isRuntime() const411 bool QGpgMENewCryptoConfigEntry::isRuntime() const
412 {
413     return m_option.flags() & Runtime;
414 }
415 
level() const416 CryptoConfigEntry::Level QGpgMENewCryptoConfigEntry::level() const
417 {
418     // two casts to make SunCC happy:
419     return static_cast<Level>(static_cast<unsigned int>(m_option.level()));
420 }
421 
argType() const422 CryptoConfigEntry::ArgType QGpgMENewCryptoConfigEntry::argType() const
423 {
424     bool ok = false;
425     const ArgType type = knownArgType(m_option.type(), ok);
426     if (ok) {
427         return type;
428     } else {
429         return knownArgType(m_option.alternateType(), ok);
430     }
431 }
432 
isSet() const433 bool QGpgMENewCryptoConfigEntry::isSet() const
434 {
435     return m_option.set();
436 }
437 
boolValue() const438 bool QGpgMENewCryptoConfigEntry::boolValue() const
439 {
440     Q_ASSERT(m_option.alternateType() == NoType);
441     Q_ASSERT(!isList());
442     return m_option.currentValue().boolValue();
443 }
444 
stringValue() const445 QString QGpgMENewCryptoConfigEntry::stringValue() const
446 {
447     //return toString( false );
448     Q_ASSERT(m_option.alternateType() == StringType);
449     Q_ASSERT(!isList());
450     return QString::fromUtf8(m_option.currentValue().stringValue());
451 }
452 
intValue() const453 int QGpgMENewCryptoConfigEntry::intValue() const
454 {
455     Q_ASSERT(m_option.alternateType() == IntegerType);
456     Q_ASSERT(!isList());
457     return m_option.currentValue().intValue();
458 }
459 
uintValue() const460 unsigned int QGpgMENewCryptoConfigEntry::uintValue() const
461 {
462     Q_ASSERT(m_option.alternateType() == UnsignedIntegerType);
463     Q_ASSERT(!isList());
464     return m_option.currentValue().uintValue();
465 }
466 
parseURL(int mRealArgType,const QString & str)467 static QUrl parseURL(int mRealArgType, const QString &str)
468 {
469     if (mRealArgType == 33) {   // LDAP server
470         // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
471         QStringList items = str.split(QLatin1Char(':'));
472         if (items.count() == 5) {
473             QStringList::const_iterator it = items.constBegin();
474             QUrl url;
475             url.setScheme(QStringLiteral("ldap"));
476             url.setHost(urlpart_decode(*it++));
477 
478             bool ok;
479             const int port = (*it++).toInt(&ok);
480             if (ok) {
481                 url.setPort(port);
482             } else if (!it->isEmpty()) {
483                 qCWarning(QGPGME_LOG) << "parseURL: malformed LDAP server port, ignoring: \"" << *it << "\"";
484             }
485 
486             const QString userName = urlpart_decode(*it++);
487             if (!userName.isEmpty()) {
488                 url.setUserName(userName);
489             }
490             const QString passWord = urlpart_decode(*it++);
491             if (!passWord.isEmpty()) {
492                 url.setPassword(passWord);
493             }
494             url.setQuery(urlpart_decode(*it));
495             return url;
496         } else {
497             qCWarning(QGPGME_LOG) << "parseURL: malformed LDAP server:" << str;
498         }
499     }
500     // other URLs : assume wellformed URL syntax.
501     return QUrl(str);
502 }
503 
504 // The opposite of parseURL
splitURL(int mRealArgType,const QUrl & url)505 static QString splitURL(int mRealArgType, const QUrl &url)
506 {
507     if (mRealArgType == 33) {   // LDAP server
508         // The format is HOSTNAME:PORT:USERNAME:PASSWORD:BASE_DN
509         Q_ASSERT(url.scheme() == QLatin1String("ldap"));
510         return urlpart_encode(url.host()) + QLatin1Char(':') +
511                (url.port() != -1 ? QString::number(url.port()) : QString()) + QLatin1Char(':') +     // -1 is used for default ports, omit
512                urlpart_encode(url.userName()) + QLatin1Char(':') +
513                urlpart_encode(url.password()) + QLatin1Char(':') +
514                urlpart_encode(url.query());
515     }
516     return url.path();
517 }
518 
urlValue() const519 QUrl QGpgMENewCryptoConfigEntry::urlValue() const
520 {
521     const Type type = m_option.type();
522     Q_ASSERT(type == FilenameType || type == LdapServerType);
523     Q_ASSERT(!isList());
524     if (type == FilenameType) {
525         QUrl url = QUrl::fromLocalFile(m_option.currentValue().stringValue());
526         return url;
527     }
528     return parseURL(type, stringValue());
529 }
530 
numberOfTimesSet() const531 unsigned int QGpgMENewCryptoConfigEntry::numberOfTimesSet() const
532 {
533     Q_ASSERT(m_option.alternateType() == NoType);
534     Q_ASSERT(isList());
535     return m_option.currentValue().uintValue();
536 }
537 
intValueList() const538 std::vector<int> QGpgMENewCryptoConfigEntry::intValueList() const
539 {
540     Q_ASSERT(m_option.alternateType() == IntegerType);
541     Q_ASSERT(isList());
542     return m_option.currentValue().intValues();
543 }
544 
uintValueList() const545 std::vector<unsigned int> QGpgMENewCryptoConfigEntry::uintValueList() const
546 {
547     Q_ASSERT(m_option.alternateType() == UnsignedIntegerType);
548     Q_ASSERT(isList());
549     return m_option.currentValue().uintValues();
550 }
551 
stringValueList() const552 QStringList QGpgMENewCryptoConfigEntry::stringValueList() const
553 {
554     Q_ASSERT(isList());
555     const Argument arg = m_option.currentValue();
556     const std::vector<const char *> values = arg.stringValues();
557     QStringList ret;
558     for(const char *value: values) {
559         ret << QString::fromUtf8(value);
560     }
561     return ret;
562 }
563 
urlValueList() const564 QList<QUrl> QGpgMENewCryptoConfigEntry::urlValueList() const
565 {
566     const Type type = m_option.type();
567     Q_ASSERT(type == FilenameType || type == LdapServerType);
568     Q_ASSERT(isList());
569     const Argument arg = m_option.currentValue();
570     const std::vector<const char *> values = arg.stringValues();
571     QList<QUrl> ret;
572     Q_FOREACH(const char *value, values)
573     if (type == FilenameType) {
574         QUrl url;
575         url.setPath(QFile::decodeName(value));
576         ret << url;
577     } else {
578         ret << parseURL(type, QString::fromUtf8(value));
579     }
580     return ret;
581 }
582 
resetToDefault()583 void QGpgMENewCryptoConfigEntry::resetToDefault()
584 {
585     m_option.resetToDefaultValue();
586 }
587 
setBoolValue(bool b)588 void QGpgMENewCryptoConfigEntry::setBoolValue(bool b)
589 {
590     Q_ASSERT(m_option.alternateType() == NoType);
591     Q_ASSERT(!isList());
592     // A "no arg" option is either set or not set.
593     // Being set means createNoneArgument(), being unset means resetToDefault()
594     m_option.setNewValue(m_option.createNoneArgument(b));
595 }
596 
setStringValue(const QString & str)597 void QGpgMENewCryptoConfigEntry::setStringValue(const QString &str)
598 {
599     Q_ASSERT(m_option.alternateType() == StringType);
600     Q_ASSERT(!isList());
601     const Type type = m_option.type();
602     // When setting a string to empty (and there's no default), we need to act like resetToDefault
603     // Otherwise we try e.g. "ocsp-responder:0:" and gpgconf answers:
604     // "gpgconf: argument required for option ocsp-responder"
605     if (str.isEmpty() && !isOptional()) {
606         m_option.resetToDefaultValue();
607     } else if (type == FilenameType) {
608         m_option.setNewValue(m_option.createStringArgument(QFile::encodeName(str).constData()));
609     } else {
610         m_option.setNewValue(m_option.createStringArgument(str.toUtf8().constData()));
611     }
612 }
613 
setIntValue(int i)614 void QGpgMENewCryptoConfigEntry::setIntValue(int i)
615 {
616     Q_ASSERT(m_option.alternateType() == IntegerType);
617     Q_ASSERT(!isList());
618     m_option.setNewValue(m_option.createIntArgument(i));
619 }
620 
setUIntValue(unsigned int i)621 void QGpgMENewCryptoConfigEntry::setUIntValue(unsigned int i)
622 {
623     Q_ASSERT(m_option.alternateType() == UnsignedIntegerType);
624     Q_ASSERT(!isList());
625     m_option.setNewValue(m_option.createUIntArgument(i));
626 }
627 
setURLValue(const QUrl & url)628 void QGpgMENewCryptoConfigEntry::setURLValue(const QUrl &url)
629 {
630     const Type type = m_option.type();
631     Q_ASSERT(type == FilenameType || type == LdapServerType);
632     Q_ASSERT(!isList());
633     const QString str = splitURL(type, url);
634     // cf. setStringValue()
635     if (str.isEmpty() && !isOptional()) {
636         m_option.resetToDefaultValue();
637     } else if (type == FilenameType) {
638         m_option.setNewValue(m_option.createStringArgument(QDir::toNativeSeparators(url.toLocalFile()).toUtf8().constData()));
639     } else {
640         m_option.setNewValue(m_option.createStringArgument(str.toUtf8().constData()));
641     }
642 }
643 
setNumberOfTimesSet(unsigned int i)644 void QGpgMENewCryptoConfigEntry::setNumberOfTimesSet(unsigned int i)
645 {
646     Q_ASSERT(m_option.alternateType() == NoType);
647     Q_ASSERT(isList());
648     m_option.setNewValue(m_option.createNoneListArgument(i));
649 }
650 
setIntValueList(const std::vector<int> & lst)651 void QGpgMENewCryptoConfigEntry::setIntValueList(const std::vector<int> &lst)
652 {
653     Q_ASSERT(m_option.alternateType() == IntegerType);
654     Q_ASSERT(isList());
655     m_option.setNewValue(m_option.createIntListArgument(lst));
656 }
657 
setUIntValueList(const std::vector<unsigned int> & lst)658 void QGpgMENewCryptoConfigEntry::setUIntValueList(const std::vector<unsigned int> &lst)
659 {
660     Q_ASSERT(m_option.alternateType() == UnsignedIntegerType);
661     Q_ASSERT(isList());
662     m_option.setNewValue(m_option.createUIntListArgument(lst));
663 }
664 
setURLValueList(const QList<QUrl> & urls)665 void QGpgMENewCryptoConfigEntry::setURLValueList(const QList<QUrl> &urls)
666 {
667     const Type type = m_option.type();
668     Q_ASSERT(m_option.alternateType() == StringType);
669     Q_ASSERT(isList());
670     std::vector<std::string> values;
671     values.reserve(urls.size());
672     Q_FOREACH (const QUrl &url, urls)
673         if (type == FilenameType) {
674             values.push_back(QFile::encodeName(url.path()).constData());
675         } else {
676             values.push_back(splitURL(type, url).toUtf8().constData());
677         }
678     m_option.setNewValue(m_option.createStringListArgument(values));
679 }
680 
isDirty() const681 bool QGpgMENewCryptoConfigEntry::isDirty() const
682 {
683     return m_option.dirty();
684 }
685 
686 #if 0
687 QString QGpgMENewCryptoConfigEntry::toString(bool escape) const
688 {
689     // Basically the opposite of stringToValue
690     if (isStringType()) {
691         if (mValue.isNull()) {
692             return QString();
693         } else if (isList()) { // string list
694             QStringList lst = mValue.toStringList();
695             if (escape) {
696                 for (QStringList::iterator it = lst.begin(); it != lst.end(); ++it) {
697                     if (!(*it).isNull()) {
698                         *it = gpgconf_escape(*it).prepend("\"");
699                     }
700                 }
701             }
702             QString res = lst.join(",");
703             //qCDebug(QGPGME_LOG) <<"toString:" << res;
704             return res;
705         } else { // normal string
706             QString res = mValue.toString();
707             if (escape) {
708                 res = gpgconf_escape(res).prepend("\"");
709             }
710             return res;
711         }
712     }
713     if (!isList()) { // non-list non-string
714         if (mArgType == ArgType_None) {
715             return mValue.toBool() ? QString::fromLatin1("1") : QString();
716         } else { // some int
717             Q_ASSERT(mArgType == ArgType_Int || mArgType == ArgType_UInt);
718             return mValue.toString(); // int to string conversion
719         }
720     }
721 
722     // Lists (of other types than strings)
723     if (mArgType == ArgType_None) {
724         return QString::number(numberOfTimesSet());
725     }
726     QStringList ret;
727     QList<QVariant> lst = mValue.toList();
728     for (QList<QVariant>::const_iterator it = lst.constBegin(); it != lst.constEnd(); ++it) {
729         ret << (*it).toString(); // QVariant does the conversion
730     }
731     return ret.join(",");
732 }
733 
734 QString QGpgMENewCryptoConfigEntry::outputString() const
735 {
736     Q_ASSERT(mSet);
737     return toString(true);
738 }
739 
740 bool QGpgMENewCryptoConfigEntry::isStringType() const
741 {
742     return (mArgType == QGpgME::NewCryptoConfigEntry::ArgType_String
743             || mArgType == QGpgME::NewCryptoConfigEntry::ArgType_Path
744             || mArgType == QGpgME::NewCryptoConfigEntry::ArgType_URL
745             || mArgType == QGpgME::NewCryptoConfigEntry::ArgType_LDAPURL);
746 }
747 
748 void QGpgMENewCryptoConfigEntry::setDirty(bool b)
749 {
750     mDirty = b;
751 }
752 #endif
753