Cpp / Qt: Reduce boost usage (memory and tuple)
[gpgme.git] / lang / cpp / src / verificationresult.cpp
1 /*
2   verificationresult.cpp - wraps a gpgme verify result
3   Copyright (C) 2004 Klarälvdalens Datakonsult AB
4
5   This file is part of GPGME++.
6
7   GPGME++ is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Library General Public
9   License as published by the Free Software Foundation; either
10   version 2 of the License, or (at your option) any later version.
11
12   GPGME++ is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU Library General Public License for more details.
16
17   You should have received a copy of the GNU Library General Public License
18   along with GPGME++; see the file COPYING.LIB.  If not, write to the
19   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20   Boston, MA 02110-1301, USA.
21 */
22
23 #include <verificationresult.h>
24 #include <notation.h>
25 #include "result_p.h"
26 #include "util.h"
27
28 #include <gpgme.h>
29
30 #include <istream>
31 #include <algorithm>
32 #include <iterator>
33 #include <string>
34 #include <cstring>
35 #include <cstdlib>
36
37 #include <string.h>
38
39 class GpgME::VerificationResult::Private
40 {
41 public:
42     explicit Private(const gpgme_verify_result_t r)
43     {
44         if (!r) {
45             return;
46         }
47         if (r->file_name) {
48             file_name = r->file_name;
49         }
50         // copy recursively, using compiler-generated copy ctor.
51         // We just need to handle the pointers in the structs:
52         for (gpgme_signature_t is = r->signatures ; is ; is = is->next) {
53             gpgme_signature_t scopy = new _gpgme_signature(*is);
54             if (is->fpr) {
55                 scopy->fpr = strdup(is->fpr);
56             }
57 // PENDING(marc) why does this crash on Windows in strdup()?
58 # ifndef _WIN32
59             if (is->pka_address) {
60                 scopy->pka_address = strdup(is->pka_address);
61             }
62 # else
63             scopy->pka_address = 0;
64 # endif
65             scopy->next = 0;
66             sigs.push_back(scopy);
67             // copy notations:
68             nota.push_back(std::vector<Nota>());
69             purls.push_back(0);
70             for (gpgme_sig_notation_t in = is->notations ; in ; in = in->next) {
71                 if (!in->name) {
72                     if (in->value) {
73                         purls.back() = strdup(in->value);   // policy url
74                     }
75                     continue;
76                 }
77                 Nota n = { 0, 0, in->flags };
78                 n.name = strdup(in->name);
79                 if (in->value) {
80                     n.value = strdup(in->value);
81                 }
82                 nota.back().push_back(n);
83             }
84         }
85     }
86     ~Private()
87     {
88         for (std::vector<gpgme_signature_t>::iterator it = sigs.begin() ; it != sigs.end() ; ++it) {
89             std::free((*it)->fpr);
90             std::free((*it)->pka_address);
91             delete *it; *it = 0;
92         }
93         for (std::vector< std::vector<Nota> >::iterator it = nota.begin() ; it != nota.end() ; ++it) {
94             for (std::vector<Nota>::iterator jt = it->begin() ; jt != it->end() ; ++jt) {
95                 std::free(jt->name);  jt->name = 0;
96                 std::free(jt->value); jt->value = 0;
97             }
98         }
99         std::for_each(purls.begin(), purls.end(), &std::free);
100     }
101
102     struct Nota {
103         char *name;
104         char *value;
105         gpgme_sig_notation_flags_t flags;
106     };
107
108     std::vector<gpgme_signature_t> sigs;
109     std::vector< std::vector<Nota> > nota;
110     std::vector<char *> purls;
111     std::string file_name;
112 };
113
114 GpgME::VerificationResult::VerificationResult(gpgme_ctx_t ctx, int error)
115     : GpgME::Result(error), d()
116 {
117     init(ctx);
118 }
119
120 GpgME::VerificationResult::VerificationResult(gpgme_ctx_t ctx, const Error &error)
121     : GpgME::Result(error), d()
122 {
123     init(ctx);
124 }
125
126 void GpgME::VerificationResult::init(gpgme_ctx_t ctx)
127 {
128     if (!ctx) {
129         return;
130     }
131     gpgme_verify_result_t res = gpgme_op_verify_result(ctx);
132     if (!res) {
133         return;
134     }
135     d.reset(new Private(res));
136 }
137
138 make_standard_stuff(VerificationResult)
139
140 const char *GpgME::VerificationResult::fileName() const
141 {
142     return d ? d->file_name.c_str() : 0 ;
143 }
144
145 unsigned int GpgME::VerificationResult::numSignatures() const
146 {
147     return d ? d->sigs.size() : 0 ;
148 }
149
150 GpgME::Signature GpgME::VerificationResult::signature(unsigned int idx) const
151 {
152     return Signature(d, idx);
153 }
154
155 std::vector<GpgME::Signature> GpgME::VerificationResult::signatures() const
156 {
157     if (!d) {
158         return std::vector<Signature>();
159     }
160     std::vector<Signature> result;
161     result.reserve(d->sigs.size());
162     for (unsigned int i = 0 ; i < d->sigs.size() ; ++i) {
163         result.push_back(Signature(d, i));
164     }
165     return result;
166 }
167
168 GpgME::Signature::Signature(const std::shared_ptr<VerificationResult::Private> &parent, unsigned int i)
169     : d(parent), idx(i)
170 {
171 }
172
173 GpgME::Signature::Signature() : d(), idx(0) {}
174
175 bool GpgME::Signature::isNull() const
176 {
177     return !d || idx >= d->sigs.size() ;
178 }
179
180 GpgME::Signature::Summary GpgME::Signature::summary() const
181 {
182     if (isNull()) {
183         return None;
184     }
185     gpgme_sigsum_t sigsum = d->sigs[idx]->summary;
186     unsigned int result = 0;
187     if (sigsum & GPGME_SIGSUM_VALID) {
188         result |= Valid;
189     }
190     if (sigsum & GPGME_SIGSUM_GREEN) {
191         result |= Green;
192     }
193     if (sigsum & GPGME_SIGSUM_RED) {
194         result |= Red;
195     }
196     if (sigsum & GPGME_SIGSUM_KEY_REVOKED) {
197         result |= KeyRevoked;
198     }
199     if (sigsum & GPGME_SIGSUM_KEY_EXPIRED) {
200         result |= KeyExpired;
201     }
202     if (sigsum & GPGME_SIGSUM_SIG_EXPIRED) {
203         result |= SigExpired;
204     }
205     if (sigsum & GPGME_SIGSUM_KEY_MISSING) {
206         result |= KeyMissing;
207     }
208     if (sigsum & GPGME_SIGSUM_CRL_MISSING) {
209         result |= CrlMissing;
210     }
211     if (sigsum & GPGME_SIGSUM_CRL_TOO_OLD) {
212         result |= CrlTooOld;
213     }
214     if (sigsum & GPGME_SIGSUM_BAD_POLICY) {
215         result |= BadPolicy;
216     }
217     if (sigsum & GPGME_SIGSUM_SYS_ERROR) {
218         result |= SysError;
219     }
220     return static_cast<Summary>(result);
221 }
222
223 const char *GpgME::Signature::fingerprint() const
224 {
225     return isNull() ? 0 : d->sigs[idx]->fpr ;
226 }
227
228 GpgME::Error GpgME::Signature::status() const
229 {
230     return Error(isNull() ? 0 : d->sigs[idx]->status);
231 }
232
233 time_t GpgME::Signature::creationTime() const
234 {
235     return static_cast<time_t>(isNull() ? 0 : d->sigs[idx]->timestamp);
236 }
237
238 time_t GpgME::Signature::expirationTime() const
239 {
240     return static_cast<time_t>(isNull() ? 0 : d->sigs[idx]->exp_timestamp);
241 }
242
243 bool GpgME::Signature::neverExpires() const
244 {
245     return expirationTime() == (time_t)0;
246 }
247
248 bool GpgME::Signature::isWrongKeyUsage() const
249 {
250     return !isNull() && d->sigs[idx]->wrong_key_usage;
251 }
252
253 bool GpgME::Signature::isVerifiedUsingChainModel() const
254 {
255     return !isNull() && d->sigs[idx]->chain_model;
256 }
257
258 GpgME::Signature::PKAStatus GpgME::Signature::pkaStatus() const
259 {
260     if (!isNull()) {
261         return static_cast<PKAStatus>(d->sigs[idx]->pka_trust);
262     }
263     return UnknownPKAStatus;
264 }
265
266 const char *GpgME::Signature::pkaAddress() const
267 {
268     if (!isNull()) {
269         return d->sigs[idx]->pka_address;
270     }
271     return 0;
272 }
273
274 GpgME::Signature::Validity GpgME::Signature::validity() const
275 {
276     if (isNull()) {
277         return Unknown;
278     }
279     switch (d->sigs[idx]->validity) {
280     default:
281     case GPGME_VALIDITY_UNKNOWN:   return Unknown;
282     case GPGME_VALIDITY_UNDEFINED: return Undefined;
283     case GPGME_VALIDITY_NEVER:     return Never;
284     case GPGME_VALIDITY_MARGINAL:  return Marginal;
285     case GPGME_VALIDITY_FULL:      return Full;
286     case GPGME_VALIDITY_ULTIMATE:  return Ultimate;
287     }
288 }
289
290 char GpgME::Signature::validityAsString() const
291 {
292     if (isNull()) {
293         return '?';
294     }
295     switch (d->sigs[idx]->validity) {
296     default:
297     case GPGME_VALIDITY_UNKNOWN:   return '?';
298     case GPGME_VALIDITY_UNDEFINED: return 'q';
299     case GPGME_VALIDITY_NEVER:     return 'n';
300     case GPGME_VALIDITY_MARGINAL:  return 'm';
301     case GPGME_VALIDITY_FULL:      return 'f';
302     case GPGME_VALIDITY_ULTIMATE:  return 'u';
303     }
304 }
305
306 GpgME::Error GpgME::Signature::nonValidityReason() const
307 {
308     return Error(isNull() ? 0 : d->sigs[idx]->validity_reason);
309 }
310
311 unsigned int GpgME::Signature::publicKeyAlgorithm() const
312 {
313     if (!isNull()) {
314         return d->sigs[idx]->pubkey_algo;
315     }
316     return 0;
317 }
318
319 const char *GpgME::Signature::publicKeyAlgorithmAsString() const
320 {
321     if (!isNull()) {
322         return gpgme_pubkey_algo_name(d->sigs[idx]->pubkey_algo);
323     }
324     return 0;
325 }
326
327 unsigned int GpgME::Signature::hashAlgorithm() const
328 {
329     if (!isNull()) {
330         return d->sigs[idx]->hash_algo;
331     }
332     return 0;
333 }
334
335 const char *GpgME::Signature::hashAlgorithmAsString() const
336 {
337     if (!isNull()) {
338         return gpgme_hash_algo_name(d->sigs[idx]->hash_algo);
339     }
340     return 0;
341 }
342
343 const char *GpgME::Signature::policyURL() const
344 {
345     return isNull() ? 0 : d->purls[idx] ;
346 }
347
348 GpgME::Notation GpgME::Signature::notation(unsigned int nidx) const
349 {
350     return GpgME::Notation(d, idx, nidx);
351 }
352
353 std::vector<GpgME::Notation> GpgME::Signature::notations() const
354 {
355     if (isNull()) {
356         return std::vector<GpgME::Notation>();
357     }
358     std::vector<GpgME::Notation> result;
359     result.reserve(d->nota[idx].size());
360     for (unsigned int i = 0 ; i < d->nota[idx].size() ; ++i) {
361         result.push_back(GpgME::Notation(d, idx, i));
362     }
363     return result;
364 }
365
366 class GpgME::Notation::Private
367 {
368 public:
369     Private() : d(), sidx(0), nidx(0), nota(0) {}
370     Private(const std::shared_ptr<VerificationResult::Private> &priv, unsigned int sindex, unsigned int nindex)
371         : d(priv), sidx(sindex), nidx(nindex), nota(0)
372     {
373
374     }
375     Private(gpgme_sig_notation_t n)
376         : d(), sidx(0), nidx(0), nota(n ? new _gpgme_sig_notation(*n) : 0)
377     {
378         if (nota && nota->name) {
379             nota->name = strdup(nota->name);
380         }
381         if (nota && nota->value) {
382             nota->value = strdup(nota->value);
383         }
384     }
385     Private(const Private &other)
386         : d(other.d), sidx(other.sidx), nidx(other.nidx), nota(other.nota)
387     {
388         if (nota) {
389             nota->name = strdup(nota->name);
390             nota->value = strdup(nota->value);
391         }
392     }
393     ~Private()
394     {
395         if (nota) {
396             std::free(nota->name);  nota->name = 0;
397             std::free(nota->value); nota->value = 0;
398             delete nota;
399         }
400     }
401
402     std::shared_ptr<VerificationResult::Private> d;
403     unsigned int sidx, nidx;
404     gpgme_sig_notation_t nota;
405 };
406
407 GpgME::Notation::Notation(const std::shared_ptr<VerificationResult::Private> &parent, unsigned int sindex, unsigned int nindex)
408     : d(new Private(parent, sindex, nindex))
409 {
410
411 }
412
413 GpgME::Notation::Notation(gpgme_sig_notation_t nota)
414     : d(new Private(nota))
415 {
416
417 }
418
419 GpgME::Notation::Notation() : d() {}
420
421 bool GpgME::Notation::isNull() const
422 {
423     if (!d) {
424         return true;
425     }
426     if (d->d) {
427         return d->sidx >= d->d->nota.size() || d->nidx >= d->d->nota[d->sidx].size() ;
428     }
429     return !d->nota;
430 }
431
432 const char *GpgME::Notation::name() const
433 {
434     return
435         isNull() ? 0 :
436         d->d ? d->d->nota[d->sidx][d->nidx].name :
437         d->nota ? d->nota->name : 0 ;
438 }
439
440 const char *GpgME::Notation::value() const
441 {
442     return
443         isNull() ? 0 :
444         d->d ? d->d->nota[d->sidx][d->nidx].value :
445         d->nota ? d->nota->value : 0 ;
446 }
447
448 GpgME::Notation::Flags GpgME::Notation::flags() const
449 {
450     return
451         convert_from_gpgme_sig_notation_flags_t(
452             isNull() ? 0 :
453             d->d ? d->d->nota[d->sidx][d->nidx].flags :
454             d->nota ? d->nota->flags : 0);
455 }
456
457 bool GpgME::Notation::isHumanReadable() const
458 {
459     return flags() & HumanReadable;
460 }
461
462 bool GpgME::Notation::isCritical() const
463 {
464     return flags() & Critical;
465 }
466
467 std::ostream &GpgME::operator<<(std::ostream &os, const VerificationResult &result)
468 {
469     os << "GpgME::VerificationResult(";
470     if (!result.isNull()) {
471         os << "\n error:      " << result.error()
472            << "\n fileName:   " << protect(result.fileName())
473            << "\n signatures:\n";
474         const std::vector<Signature> sigs = result.signatures();
475         std::copy(sigs.begin(), sigs.end(),
476                   std::ostream_iterator<Signature>(os, "\n"));
477     }
478     return os << ')';
479 }
480
481 std::ostream &GpgME::operator<<(std::ostream &os, Signature::PKAStatus pkaStatus)
482 {
483 #define OUTPUT( x ) if ( !(pkaStatus & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0)
484     os << "GpgME::Signature::PKAStatus(";
485     OUTPUT(UnknownPKAStatus);
486     OUTPUT(PKAVerificationFailed);
487     OUTPUT(PKAVerificationSucceeded);
488 #undef OUTPUT
489     return os << ')';
490 }
491
492 std::ostream &GpgME::operator<<(std::ostream &os, Signature::Summary summary)
493 {
494 #define OUTPUT( x ) if ( !(summary & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0)
495     os << "GpgME::Signature::Summary(";
496     OUTPUT(Valid);
497     OUTPUT(Green);
498     OUTPUT(Red);
499     OUTPUT(KeyRevoked);
500     OUTPUT(KeyExpired);
501     OUTPUT(SigExpired);
502     OUTPUT(KeyMissing);
503     OUTPUT(CrlMissing);
504     OUTPUT(CrlTooOld);
505     OUTPUT(BadPolicy);
506     OUTPUT(SysError);
507 #undef OUTPUT
508     return os << ')';
509 }
510
511 std::ostream &GpgME::operator<<(std::ostream &os, const Signature &sig)
512 {
513     os << "GpgME::Signature(";
514     if (!sig.isNull()) {
515         os << "\n Summary:                   " << sig.summary()
516            << "\n Fingerprint:               " << protect(sig.fingerprint())
517            << "\n Status:                    " << sig.status()
518            << "\n creationTime:              " << sig.creationTime()
519            << "\n expirationTime:            " << sig.expirationTime()
520            << "\n isWrongKeyUsage:           " << sig.isWrongKeyUsage()
521            << "\n isVerifiedUsingChainModel: " << sig.isVerifiedUsingChainModel()
522            << "\n pkaStatus:                 " << sig.pkaStatus()
523            << "\n pkaAddress:                " << protect(sig.pkaAddress())
524            << "\n validity:                  " << sig.validityAsString()
525            << "\n nonValidityReason:         " << sig.nonValidityReason()
526            << "\n publicKeyAlgorithm:        " << protect(sig.publicKeyAlgorithmAsString())
527            << "\n hashAlgorithm:             " << protect(sig.hashAlgorithmAsString())
528            << "\n policyURL:                 " << protect(sig.policyURL())
529            << "\n notations:\n";
530         const std::vector<Notation> nota = sig.notations();
531         std::copy(nota.begin(), nota.end(),
532                   std::ostream_iterator<Notation>(os, "\n"));
533     }
534     return os << ')';
535 }
536
537 std::ostream &GpgME::operator<<(std::ostream &os, Notation::Flags flags)
538 {
539     os << "GpgME::Notation::Flags(";
540 #define OUTPUT( x ) if ( !(flags & (GpgME::Notation:: x)) ) {} else do { os << #x " "; } while(0)
541     OUTPUT(HumanReadable);
542     OUTPUT(Critical);
543 #undef OUTPUT
544     return os << ')';
545 }
546
547 std::ostream &GpgME::operator<<(std::ostream &os, const Notation &nota)
548 {
549     os << "GpgME::Signature::Notation(";
550     if (!nota.isNull()) {
551         os << "\n name:  " << protect(nota.name())
552            << "\n value: " << protect(nota.value())
553            << "\n flags: " << nota.flags()
554            << '\n';
555     }
556     return os << ")";
557 }