reorder issuer DN also
[gpgme.git] / gpgmeplug / gpgmeplug.c
1 /* -*- Mode: C -*-
2
3   $Id$
4
5   GPGMEPLUG - an GPGME based cryptography plug-in following
6               the common CRYPTPLUG specification.
7
8   Copyright (C) 2001 by Klarälvdalens Datakonsult AB
9
10   GPGMEPLUG is free software; you can redistribute it and/or modify
11   it under the terms of GNU General Public License as published by
12   the Free Software Foundation; version 2 of the License.
13
14   GPGMEPLUG is distributed in the hope that it will be useful,
15   it under the terms of GNU General Public License as published by
16   the Free Software Foundation; version 2 of the License
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with this program; if not, write to the Free Software
23   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
24 */
25
26
27
28 /*! \file gpgmeplug.c
29     \brief GPGME implementation of CRYPTPLUG following the
30     specification located in common API header cryptplug.h.
31
32     CRYPTPLUG is an independent cryptography plug-in API
33     developed for Sphinx-enabeling KMail and Mutt.
34
35     CRYPTPLUG was designed for the Aegypten project, but it may
36     be used by 3rd party developers as well to design pluggable
37     crypto backends for the above mentioned MUAs.
38
39     \note All string parameters appearing in this API are to be
40     interpreted as UTF-8 encoded.
41
42     \see cryptplug.h
43 */
44
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48 #include <stdio.h>
49 #include <string.h>
50 #include <assert.h>
51 #include <errno.h>
52 #include <time.h>
53 #include <ctype.h>
54
55 #ifndef BUG_URL
56 #define BUG_URL "http:://www.gnupg.org/aegypten/"
57 #endif
58
59 #include "gpgme.h"
60 #ifndef GPGMEPLUG_PROTOCOL
61 #define GPGMEPLUG_PROTOCOL GPGME_PROTOCOL_OpenPGP
62 #endif
63
64 /* definitions for signing */
65 #ifndef GPGMEPLUG_SIGN_MAKE_MIME_OBJECT
66 #define GPGMEPLUG_SIGN_INCLUDE_CLEARTEXT true
67 #define GPGMEPLUG_SIGN_MAKE_MIME_OBJECT  true
68 #define GPGMEPLUG_SIGN_MAKE_MULTI_MIME   true
69 #define GPGMEPLUG_SIGN_CTYPE_MAIN        "multipart/signed;protocol=application/pgp-signature;micalg=pgp-sha1"
70 #define GPGMEPLUG_SIGN_CDISP_MAIN        ""
71 #define GPGMEPLUG_SIGN_CTENC_MAIN        ""
72 #define GPGMEPLUG_SIGN_CTYPE_VERSION     ""
73 #define GPGMEPLUG_SIGN_CDISP_VERSION     ""
74 #define GPGMEPLUG_SIGN_CTENC_VERSION     ""
75 #define GPGMEPLUG_SIGN_BTEXT_VERSION     ""
76 #define GPGMEPLUG_SIGN_CTYPE_CODE        "application/pgp-signature"
77 #define GPGMEPLUG_SIGN_CDISP_CODE        ""
78 #define GPGMEPLUG_SIGN_CTENC_CODE        ""
79 #define GPGMEPLUG_SIGN_FLAT_PREFIX       ""
80 #define GPGMEPLUG_SIGN_FLAT_SEPARATOR    ""
81 #define GPGMEPLUG_SIGN_FLAT_POSTFIX      ""
82 #define __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY false
83 #endif
84 #define __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO "Error: Cannot run checkMessageSignature() with cleartext == 0"
85 /* definitions for encoding */
86 #ifndef GPGMEPLUG_ENC_MAKE_MIME_OBJECT
87 #define GPGMEPLUG_ENC_INCLUDE_CLEARTEXT  false
88 #define GPGMEPLUG_ENC_MAKE_MIME_OBJECT   true
89 #define GPGMEPLUG_ENC_MAKE_MULTI_MIME    true
90 #define GPGMEPLUG_ENC_CTYPE_MAIN         "multipart/encrypted; protocol=application/pgp-encrypted"
91 #define GPGMEPLUG_ENC_CDISP_MAIN         ""
92 #define GPGMEPLUG_ENC_CTENC_MAIN         ""
93 #define GPGMEPLUG_ENC_CTYPE_VERSION      "application/pgp-encrypted"
94 #define GPGMEPLUG_ENC_CDISP_VERSION      "attachment"
95 #define GPGMEPLUG_ENC_CTENC_VERSION      ""
96 #define GPGMEPLUG_ENC_BTEXT_VERSION      "Version: 1"
97 #define GPGMEPLUG_ENC_CTYPE_CODE         "application/octet-stream"
98 #define GPGMEPLUG_ENC_CDISP_CODE         "inline; filename=\"msg.asc\""
99 #define GPGMEPLUG_ENC_CTENC_CODE         ""
100 #define GPGMEPLUG_ENC_FLAT_PREFIX        ""
101 #define GPGMEPLUG_ENC_FLAT_SEPARATOR     ""
102 #define GPGMEPLUG_ENC_FLAT_POSTFIX       ""
103 #define __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY false
104 #endif
105 /* Note: The following specification will result in
106        function encryptAndSignMessage() producing
107        _empty_ mails.
108        This must be changed as soon as our plugin
109        is supporting the encryptAndSignMessage() function. */
110 #ifndef GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT
111 #define GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT false
112 #define GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT  false
113 #define GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME   false
114 #define GPGMEPLUG_ENCSIGN_CTYPE_MAIN        ""
115 #define GPGMEPLUG_ENCSIGN_CDISP_MAIN        ""
116 #define GPGMEPLUG_ENCSIGN_CTENC_MAIN        ""
117 #define GPGMEPLUG_ENCSIGN_CTYPE_VERSION     ""
118 #define GPGMEPLUG_ENCSIGN_CDISP_VERSION     ""
119 #define GPGMEPLUG_ENCSIGN_CTENC_VERSION     ""
120 #define GPGMEPLUG_ENCSIGN_BTEXT_VERSION     ""
121 #define GPGMEPLUG_ENCSIGN_CTYPE_CODE        ""
122 #define GPGMEPLUG_ENCSIGN_CDISP_CODE        ""
123 #define GPGMEPLUG_ENCSIGN_CTENC_CODE        ""
124 #define GPGMEPLUG_ENCSIGN_FLAT_PREFIX       ""
125 #define GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR    ""
126 #define GPGMEPLUG_ENCSIGN_FLAT_POSTFIX      ""
127 #endif
128
129 #include "cryptplug.h"
130
131
132 typedef struct {
133   const char*             bugURL;
134   const char*             signatureKeyCertificate;
135   SignatureAlgorithm      signatureAlgorithm;
136   SendCertificates        sendCertificates;
137   SignEmail               signEmail;
138   bool                    saveSentSignatures;
139   bool                    warnNoCertificate;
140   PinRequests             numPINRequests;
141   bool                    checkSignatureCertificatePathToRoot;
142   bool                    signatureUseCRLs;
143   EncryptionAlgorithm     encryptionAlgorithm;
144   EncryptEmail            encryptEmail;
145   bool                    saveMessagesEncrypted;
146   bool                    checkEncryptionCertificatePathToRoot;
147   bool                    encryptionUseCRLs;
148   bool                    encryptionCRLExpiryNearWarning;
149   int                     encryptionCRLNearExpiryInterval;
150   struct DirectoryServer *directoryServers;
151   unsigned int            numDirectoryServers;
152   CertificateSource       certificateSource;
153   CertificateSource       cRLSource;
154   bool                    warnSendUnsigned;
155   int                     numPINRequestsInterval;
156   bool                    signatureCertificateExpiryNearWarning;
157   int                     signatureCertificateExpiryNearInterval;
158   bool                    cACertificateExpiryNearWarning;
159   int                     cACertificateExpiryNearInterval;
160   bool                    rootCertificateExpiryNearWarning;
161   int                     rootCertificateExpiryNearInterval;
162   bool                    warnSendUnencrypted;
163   bool                    checkCertificatePath;
164   bool                    receiverCertificateExpiryNearWarning;
165   int                     receiverCertificateExpiryNearWarningInterval;
166   bool                    certificateInChainExpiryNearWarning;
167   int                     certificateInChainExpiryNearWarningInterval;
168   bool                    receiverEmailAddressNotInCertificateWarning;
169 } Config;
170
171
172 Config config;
173
174 #define NEAR_EXPIRY 14
175
176 bool initialize()
177 {
178   config.bugURL                               = malloc( strlen( BUG_URL ) + 1 );
179   strcpy( (char* )config.bugURL,                BUG_URL );
180   config.signatureKeyCertificate              = malloc( 1 );
181   strcpy( (char* )config.signatureKeyCertificate, "" );
182   config.signatureAlgorithm                   = SignAlg_SHA1;
183   config.sendCertificates                     = SendCert_SendChainWithRoot;
184   config.signEmail                            = SignEmail_SignAll;
185   config.saveSentSignatures                   = true;
186   config.warnNoCertificate                    = true;
187   config.numPINRequests                       = PinRequest_Always;
188   config.checkSignatureCertificatePathToRoot  = true;
189   config.signatureUseCRLs                     = true;
190   config.encryptionAlgorithm                  = EncryptAlg_RSA;
191   config.encryptEmail                         = EncryptEmail_Ask;
192   config.saveMessagesEncrypted                = true;
193   config.checkEncryptionCertificatePathToRoot = true;
194   config.encryptionUseCRLs                    = true;
195   config.encryptionCRLExpiryNearWarning       = true;
196   config.encryptionCRLNearExpiryInterval      = NEAR_EXPIRY;
197   config.directoryServers                     = NULL;
198   config.numDirectoryServers                  = 0;
199   config.certificateSource                    = CertSrc_Server;
200   config.cRLSource                            = CertSrc_Server;
201   config.warnSendUnsigned                             = true;
202   config.numPINRequestsInterval                       = NEAR_EXPIRY;
203   config.signatureCertificateExpiryNearWarning        = true;
204   config.signatureCertificateExpiryNearInterval       = NEAR_EXPIRY;
205   config.cACertificateExpiryNearWarning               = true;
206   config.cACertificateExpiryNearInterval              = NEAR_EXPIRY;
207   config.rootCertificateExpiryNearWarning             = true;
208   config.rootCertificateExpiryNearInterval            = NEAR_EXPIRY;
209   config.warnSendUnencrypted                          = false;
210   config.checkCertificatePath                         = true;
211   config.receiverCertificateExpiryNearWarning         = true;
212   config.receiverCertificateExpiryNearWarningInterval = NEAR_EXPIRY;
213   config.certificateInChainExpiryNearWarning          = true;
214   config.certificateInChainExpiryNearWarningInterval  = NEAR_EXPIRY;
215   config.receiverEmailAddressNotInCertificateWarning  = true;
216
217   return true;
218 };
219
220
221 void deinitialize()
222 {
223   unsigned int i;
224   for( i = 0; i < config.numDirectoryServers; ++i ) {
225     free( (char *)config.directoryServers[i].servername );
226     free( (char *)config.directoryServers[i].description );
227   }
228   free( config.directoryServers );
229 }
230
231
232 bool hasFeature( Feature flag )
233 {
234   /* our own plugins are supposed to support everything */
235   switch ( flag ) {
236   case Feature_SignMessages:              return true;
237   case Feature_VerifySignatures:          return true;
238   case Feature_EncryptMessages:           return true;
239   case Feature_DecryptMessages:           return true;
240   case Feature_SendCertificates:          return true;
241   case Feature_WarnSignCertificateExpiry: return true;
242   case Feature_WarnSignEmailNotInCertificate: return true;
243   case Feature_PinEntrySettings:          return true;
244   case Feature_StoreMessagesWithSigs:     return true;
245   case Feature_EncryptionCRLs:            return true;
246   case Feature_WarnEncryptCertificateExpiry: return true;
247   case Feature_WarnEncryptEmailNotInCertificate: return true;
248   case Feature_StoreMessagesEncrypted:    return true;
249   case Feature_CheckCertificatePath:      return true;
250   case Feature_CertificateDirectoryService: return true;
251   case Feature_CRLDirectoryService:       return true;
252   /* undefined or not yet implemented: */
253   case Feature_undef:                     return false;
254   default:                                      return false;
255   }
256 }
257
258
259 const char* bugURL(){ return config.bugURL; }
260
261
262 void unsafeStationery( void** pixmap, const char** menutext, char* accel,
263           const char** tooltip, const char** statusbartext ){}
264
265 void signedStationery( void** pixmap, const char** menutext, char* accel,
266           const char** tooltip, const char** statusbartext ){}
267
268 void encryptedStationery( void** pixmap, const char**
269           menutext, char* accel,
270           const char** tooltip, const char** statusbartext ){}
271
272 void signedEncryptedStationery( void** pixmap, const char**
273           menutext, char* accel,
274           const char** tooltip, const char** statusbartext ){}
275
276 const char* signatureConfigurationDialog(){ return 0; }
277
278 const char* signatureKeySelectionDialog(){ return 0; }
279
280 const char* signatureAlgorithmDialog(){ return 0; }
281
282 const char* signatureHandlingDialog(){ return 0; }
283
284 void setSignatureKeyCertificate( const char* certificate )
285 {
286   config.signatureKeyCertificate = certificate;
287 }
288
289 const char* signatureKeyCertificate()
290 {
291   return config.signatureKeyCertificate;
292 }
293
294 void setSignatureAlgorithm( SignatureAlgorithm sigAlg )
295 {
296   config.signatureAlgorithm = sigAlg;
297 }
298
299 SignatureAlgorithm signatureAlgorithm()
300 {
301   return config.signatureAlgorithm;
302 }
303
304 void setSendCertificates( SendCertificates sendCert )
305 {
306   config.sendCertificates = sendCert;
307 }
308
309 SendCertificates sendCertificates()
310 {
311   return config.sendCertificates;
312 }
313
314 void setSignEmail( SignEmail signMail )
315 {
316   config.signEmail = signMail;
317 }
318
319 SignEmail signEmail()
320 {
321   return config.signEmail;
322 }
323
324
325
326
327
328 void setWarnSendUnsigned( bool flag )
329 {
330   config.warnSendUnsigned = flag;
331 }
332
333 bool warnSendUnsigned()
334 {
335   return config.warnSendUnsigned;
336 }
337
338
339
340
341
342
343 void setSaveSentSignatures( bool flag )
344 {
345   config.saveSentSignatures = flag;
346 }
347
348 bool saveSentSignatures()
349 {
350   return config.saveSentSignatures;
351 }
352
353 void setWarnNoCertificate( bool flag )
354 {
355   config.warnNoCertificate = flag;
356 }
357
358 bool warnNoCertificate()
359 {
360   return config.warnNoCertificate;
361 }
362
363
364 bool isEmailInCertificate( const char* email, const char* certificate )
365 {
366     /* PENDING(g10) this function should return true if the email
367        address passed as the first parameter is contained in the
368        certificate passed as the second parameter, and false
369        otherwise. This is used to alert the user if his own email
370        address is not contained in the certificate he uses for
371        signing.
372        Note that the parameter email can be anything that is allowed
373        in a From: line.
374        Another note: OK, OK, we'll handle that in the MUA. You can
375        assume that you only get the email address.
376     */
377   return false; /* dummy*/
378 }
379
380
381 void setNumPINRequests( PinRequests reqMode )
382 {
383   config.numPINRequests = reqMode;
384
385   /* PENDING(g10) Put this value into gpg and make it ask for the pin
386      according to this. Note that there is also
387      setNumPINRequestsInterval() which is only used if reqMode ==
388      PinRequest_AfterMinutes.
389   */
390 }
391
392 PinRequests numPINRequests()
393 {
394   return config.numPINRequests;
395 }
396
397
398
399 void setNumPINRequestsInterval( int interval )
400 {
401   config.numPINRequestsInterval = interval;
402
403   /* PENDING(g10) Put this value into gpg and make it ask for the pin
404      according to this. Note that this should only be used if
405      config.numPINRequests (set with setNumPINRequests()) has the
406      value PinRequest_AfterMinutes.
407   */
408 }
409
410 int numPINRequestsInterval()
411 {
412   return config.numPINRequestsInterval;
413 }
414
415
416
417 void setCheckSignatureCertificatePathToRoot( bool flag )
418 {
419   config.checkSignatureCertificatePathToRoot = flag;
420 }
421
422 bool checkSignatureCertificatePathToRoot()
423 {
424   return config.checkSignatureCertificatePathToRoot;
425 }
426
427 void setSignatureUseCRLs( bool flag )
428 {
429   config.signatureUseCRLs = flag;
430 }
431
432 bool signatureUseCRLs()
433 {
434   return config.signatureUseCRLs;
435 }
436
437
438
439
440
441
442 void setSignatureCertificateExpiryNearWarning( bool flag )
443 {
444   config.signatureCertificateExpiryNearWarning = flag;
445 }
446
447 bool signatureCertificateExpiryNearWarning( void )
448 {
449   return config.signatureCertificateExpiryNearWarning;
450 }
451
452
453 int signatureCertificateDaysLeftToExpiry( const char* certificate )
454 {
455   // pending (khz): make this work!
456   /*
457   GpgmeCtx ctx;
458   GpgmeError err;
459   GpgmeKey rKey;
460   time_t daysLeft = 0;
461
462   gpgme_new( &ctx );
463   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
464
465   err = gpgme_op_keylist_start( ctx, certificate, 0 );
466   if ( GPGME_No_Error == err ) {
467     err = gpgme_op_keylist_next( ctx, &rKey );
468     gpgme_op_keylist_end( ctx );
469     if ( GPGME_No_Error == err ) {
470       time_t expire_time = gpgme_key_get_ulong_attr(
471                              rKey,GPGME_ATTR_EXPIRE, NULL, 0 );
472       time_t cur_time = time (NULL);
473       daysLeft = expire_time - cur_time;
474       // convert seconds into days
475       daysLeft /= 43200;
476       gpgme_key_release( rKey );
477     }
478   }
479   gpgme_release( ctx );
480
481   return daysLeft;
482   */
483   return 10;
484 }
485
486
487 void setSignatureCertificateExpiryNearInterval( int interval )
488 {
489   config.signatureCertificateExpiryNearInterval = interval;
490 }
491
492 int signatureCertificateExpiryNearInterval( void )
493 {
494   return config.signatureCertificateExpiryNearInterval;
495 }
496
497 void setCACertificateExpiryNearWarning( bool flag )
498 {
499   config.cACertificateExpiryNearWarning = flag;
500 }
501
502 bool caCertificateExpiryNearWarning( void )
503 {
504   return config.cACertificateExpiryNearWarning;
505 }
506
507 int caCertificateDaysLeftToExpiry( const char* certificate )
508 {
509     /* PENDING(g10)
510        Please return the number of days that are left until the
511        CA certificate for the certificate specified in the parameter
512        certificate expires.
513     */
514   return 10; /* dummy that triggers a warning in the MUA */
515 }
516
517 void setCACertificateExpiryNearInterval( int interval )
518 {
519   config.cACertificateExpiryNearInterval = interval;
520 }
521
522 int caCertificateExpiryNearInterval( void )
523 {
524   return config.cACertificateExpiryNearInterval;
525 }
526
527 void setRootCertificateExpiryNearWarning( bool flag )
528 {
529   config.rootCertificateExpiryNearWarning = flag;
530 }
531
532 bool rootCertificateExpiryNearWarning( void )
533 {
534   return config.rootCertificateExpiryNearWarning;
535 }
536
537 int rootCertificateDaysLeftToExpiry( const char* certificate )
538 {
539     /* PENDING(g10)
540        Please return the number of days that are left until the
541        root certificate for the certificate specified in the parameter
542        certificate expires.
543     */
544   return 10; /* dummy that triggers a warning in the MUA */
545 }
546
547
548 void setRootCertificateExpiryNearInterval( int interval )
549 {
550   config.rootCertificateExpiryNearInterval = interval;
551 }
552
553 int rootCertificateExpiryNearInterval( void )
554 {
555   return config.rootCertificateExpiryNearInterval;
556 }
557
558
559
560
561
562
563
564
565 const char* encryptionConfigurationDialog(){ return 0; }
566
567 const char* encryptionAlgorithmDialog(){ return 0; }
568
569 const char* encryptionHandlingDialog(){ return 0; }
570
571 const char* encryptionReceiverDialog(){ return 0; }
572
573 void setEncryptionAlgorithm( EncryptionAlgorithm cryptAlg )
574 {
575   config.encryptionAlgorithm = cryptAlg;
576 }
577
578 EncryptionAlgorithm encryptionAlgorithm()
579 {
580   return config.encryptionAlgorithm;
581 }
582
583 void setEncryptEmail( EncryptEmail cryptMode )
584 {
585   config.encryptEmail = cryptMode;
586 }
587
588 EncryptEmail encryptEmail()
589 {
590   return config.encryptEmail;
591 }
592
593
594
595
596
597
598 void setWarnSendUnencrypted( bool flag )
599 {
600   config.warnSendUnencrypted = flag;
601 }
602
603 bool warnSendUnencrypted()
604 {
605   return config.warnSendUnencrypted;
606 }
607
608
609
610
611
612
613
614
615
616 void setSaveMessagesEncrypted( bool flag )
617 {
618   config.saveMessagesEncrypted = flag;
619 }
620
621 bool saveMessagesEncrypted()
622 {
623   return config.saveMessagesEncrypted;
624 }
625
626
627
628
629
630
631
632 void setCheckCertificatePath( bool flag )
633 {
634   config.checkCertificatePath = flag;
635 }
636
637 bool checkCertificatePath()
638 {
639   return config.checkCertificatePath;
640 }
641
642
643
644
645
646
647
648
649 void setCheckEncryptionCertificatePathToRoot( bool flag )
650 {
651   config.checkEncryptionCertificatePathToRoot = flag;
652 }
653
654 bool checkEncryptionCertificatePathToRoot()
655 {
656   return config.checkEncryptionCertificatePathToRoot;
657 }
658
659
660
661
662
663
664
665 void setReceiverCertificateExpiryNearWarning( bool flag )
666 {
667   config.receiverCertificateExpiryNearWarning = flag;
668 }
669
670 bool receiverCertificateExpiryNearWarning()
671 {
672   return config.receiverCertificateExpiryNearWarning;
673 }
674
675
676 int receiverCertificateDaysLeftToExpiry( const char* certificate )
677 {
678     /* PENDING(g10)
679        Please return the number of days that are left until the
680        certificate specified in the parameter certificate expires.
681     */
682   return 10; /* dummy that triggers a warning in the MUA */
683 }
684
685
686 void setReceiverCertificateExpiryNearWarningInterval( int interval )
687 {
688   config.receiverCertificateExpiryNearWarningInterval = interval;
689 }
690
691 int receiverCertificateExpiryNearWarningInterval()
692 {
693   return config.receiverCertificateExpiryNearWarningInterval;
694 }
695
696 void setCertificateInChainExpiryNearWarning( bool flag )
697 {
698   config.certificateInChainExpiryNearWarning = flag;
699 }
700
701 bool certificateInChainExpiryNearWarning()
702 {
703   return config.certificateInChainExpiryNearWarning;
704 }
705
706
707 int certificateInChainDaysLeftToExpiry( const char* certificate )
708 {
709     /* PENDING(g10)
710        Please return the number of days that are left until the
711        the first certificate in the chain of the specified certificate
712        expires.
713     */
714   return 10; /* dummy that triggers a warning in the MUA */
715 }
716
717
718 void setCertificateInChainExpiryNearWarningInterval( int interval )
719 {
720   config.certificateInChainExpiryNearWarningInterval = interval;
721 }
722
723 int certificateInChainExpiryNearWarningInterval()
724 {
725   return config.certificateInChainExpiryNearWarningInterval;
726 }
727
728 void setReceiverEmailAddressNotInCertificateWarning( bool flag )
729 {
730   config.receiverEmailAddressNotInCertificateWarning = flag;
731 }
732
733 bool receiverEmailAddressNotInCertificateWarning()
734 {
735   return config.receiverEmailAddressNotInCertificateWarning;
736 }
737
738
739
740
741
742
743
744
745 void setEncryptionUseCRLs( bool flag )
746 {
747   config.encryptionUseCRLs = flag;
748
749   /* PENDING(g10) Store this setting in gpgme and use it. If true,
750      every certificate used for encryption should be checked against
751      applicable CRLs.
752   */
753 }
754
755 bool encryptionUseCRLs()
756 {
757   return config.encryptionUseCRLs;
758 }
759
760
761 int encryptionCRLsDaysLeftToExpiry()
762 {
763     /* PENDING(g10)
764        Please return the number of days that are left until the
765        CRL used for encryption expires.
766     */
767   return 10; /* dummy that triggers a warning in the MUA */
768 }
769
770 void setEncryptionCRLExpiryNearWarning( bool flag )
771 {
772   config.encryptionCRLExpiryNearWarning = flag;
773 }
774
775 bool encryptionCRLExpiryNearWarning()
776 {
777   return config.encryptionCRLExpiryNearWarning;
778 }
779
780 void setEncryptionCRLNearExpiryInterval( int interval )
781 {
782   config.encryptionCRLNearExpiryInterval = interval;
783 }
784
785 int encryptionCRLNearExpiryInterval()
786 {
787   return config.encryptionCRLNearExpiryInterval;
788 }
789
790
791 const char* directoryServiceConfigurationDialog(){ return 0; }
792
793 void appendDirectoryServer( const char* servername,
794                             int         port,
795                             const char* description )
796 {
797   struct DirectoryServer *newServers = NULL;
798   newServers = realloc( config.directoryServers,
799                         (1+config.numDirectoryServers) * sizeof *newServers );
800   if( newServers ) {
801     config.directoryServers = newServers;
802     newServers[ config.numDirectoryServers ].servername =
803       malloc( 1+strlen( servername ) );
804     if( newServers[ config.numDirectoryServers ].servername ) {
805       strcpy( (char *)newServers[ config.numDirectoryServers ].servername,
806         servername );
807       newServers[ config.numDirectoryServers ].description =
808         malloc( 1+strlen(  description ) );
809       if( newServers[ config.numDirectoryServers ].description ) {
810         strcpy( (char *)newServers[ config.numDirectoryServers ].description,
811           description );
812         newServers[ config.numDirectoryServers ].port = port;
813         config.numDirectoryServers += 1;
814       }
815     }
816   }
817 }
818
819 void setDirectoryServers( struct DirectoryServer server[], unsigned int size )
820 {
821   unsigned int i;
822   int oldSize = config.numDirectoryServers;
823   struct DirectoryServer *newServers = NULL;
824   newServers = calloc ( size, sizeof *newServers );
825   if( newServers ) {
826     for( i=0; i < oldSize; ++i ) {
827       free( (char *)config.directoryServers[i].servername );
828       free( (char *)config.directoryServers[i].description );
829     }
830     free( config.directoryServers );
831     for( i=0; i < size; ++i ) {
832       newServers[ i ].servername = malloc( 1+strlen( server[i].servername ) );
833       if( newServers[ i ].servername ) {
834         strcpy( (char *)newServers[ i ].servername, server[i].servername );
835         newServers[ i ].description = malloc( 1+strlen( server[i].description ) );
836         if( newServers[ i ].description ) {
837           strcpy( (char *)newServers[ i ].description, server[i].description );
838           newServers[ i ].port = server[i].port;
839         }
840       }
841     }
842     config.directoryServers = newServers;
843     config.numDirectoryServers = size;
844   }
845 }
846
847 struct DirectoryServer * directoryServers( int* numServers )
848 {
849   if( numServers )
850     *numServers = config.numDirectoryServers;
851   return config.directoryServers;
852 };
853
854 void setCertificateSource( CertificateSource source )
855 {
856   config.certificateSource = source;
857 }
858
859 CertificateSource certificateSource()
860 {
861   return config.certificateSource;
862 }
863
864 void setCRLSource( CertificateSource source )
865 {
866   config.cRLSource = source;
867 }
868
869 CertificateSource crlSource()
870 {
871   return config.cRLSource;
872 }
873
874
875 bool certificateValidity( const char* certificate,
876                           int* level ){ return true; }
877
878
879 void storeNewCharPtr( char** dest, const char* src )
880 {
881   int sLen = strlen( src );
882   *dest = malloc( sLen + 1 );
883   strcpy( *dest, src );
884   (*dest)[sLen] = '\0';
885 }
886
887
888 bool signMessage( const char*  cleartext,
889                   char** ciphertext,
890                   const size_t* cipherLen,
891                   const char*  certificate,
892                   struct StructuringInfo* structuring,
893                   int* errId,
894                   char** errTxt )
895 {
896   GpgmeCtx ctx;
897   GpgmeError err;
898   GpgmeKey rKey;
899   GpgmeData data,  sig;
900   char* rSig  = 0;
901   bool  bOk   = false;
902   int sendCerts = 1;
903
904   init_StructuringInfo( structuring );
905
906   if( !ciphertext )
907     return false;
908
909   err = gpgme_new (&ctx);
910   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
911
912   gpgme_set_armor (ctx, __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ? 0 : 1);
913   /*  gpgme_set_textmode (ctx, 1); */
914
915   switch ( config.sendCertificates ) {
916     case SendCert_undef:
917       break;
918     case SendCert_DontSend:
919       sendCerts = 0;
920       break;
921     case SendCert_SendOwn:
922       sendCerts = 1;
923       break;
924     case SendCert_SendChainWithoutRoot:
925       sendCerts = -2;
926       break;
927     case SendCert_SendChainWithRoot:
928       sendCerts = -1;
929       break;
930     default:
931       sendCerts = 0;
932       break;
933   }
934   gpgme_set_include_certs (ctx, sendCerts);
935
936   /* select the signer's key if provided */
937   if (certificate != 0) {
938       err = gpgme_op_keylist_start(ctx, certificate, 0);
939       if (err == GPGME_No_Error) {
940           /* we only support one signer for now */
941           err = gpgme_op_keylist_next(ctx, &rKey);
942           if (err == GPGME_No_Error) {
943               /* clear existing signers */
944               gpgme_signers_clear(ctx);
945               /* set the signing key */
946               gpgme_signers_add(ctx, rKey);
947           }
948           gpgme_op_keylist_end(ctx);
949       }
950   }
951
952   /* PENDING(g10) Implement this
953
954      gpgme_set_signature_algorithm( ctx, config.signatureAlgorithm )
955      --> This does not make sense.  The algorithm is a property of
956      the certificate used [wk 2002-03-23] */
957
958   gpgme_data_new_from_mem (&data, cleartext,
959                             strlen( cleartext ), 1 );
960   gpgme_data_new ( &sig );
961   err = gpgme_op_sign (ctx, data, sig, GPGME_SIG_MODE_DETACH );
962
963   if ( err == GPGME_No_Error ) {
964     if( __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ) {
965       *ciphertext = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen );
966       bOk = true;
967     }
968     else {
969       rSig = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen );
970       *ciphertext = malloc( *cipherLen + 1 );
971       if( *ciphertext ) {
972         if( *cipherLen ) {
973           bOk = true;
974           strncpy((char*)*ciphertext, rSig, *cipherLen );
975         }
976         (*ciphertext)[*cipherLen] = '\0';
977       }
978       free( rSig );
979     }
980   }
981   else {
982     gpgme_data_release( sig );
983 /*
984 *ciphertext = malloc( 70 );
985 strcpy((char*)*ciphertext, "xyz\nsig-dummy\nzyx" );
986 (*ciphertext)[17] = '\0';
987 err = 0;
988 {
989 */
990     *ciphertext = 0;
991     fprintf( stderr, "\n\n    gpgme_op_sign() returned this error code:  %i\n\n", err );
992     if( errId )
993       *errId = err;
994     if( errTxt ) {
995       const char* _errTxt = gpgme_strerror( err );
996       *errTxt = malloc( strlen( _errTxt ) + 1 );
997       if( *errTxt )
998         strcpy(*errTxt, _errTxt );
999     }
1000 /*
1001 }
1002 */
1003   }
1004   gpgme_data_release( data );
1005   gpgme_release (ctx);
1006
1007   if( bOk && structuring ) {
1008     structuring->includeCleartext = GPGMEPLUG_SIGN_INCLUDE_CLEARTEXT;
1009     structuring->makeMimeObject   = GPGMEPLUG_SIGN_MAKE_MIME_OBJECT;
1010     if( structuring->makeMimeObject ) {
1011       structuring->makeMultiMime  = GPGMEPLUG_SIGN_MAKE_MULTI_MIME;
1012       storeNewCharPtr( &structuring->contentTypeMain,
1013                        GPGMEPLUG_SIGN_CTYPE_MAIN );
1014       storeNewCharPtr( &structuring->contentDispMain,
1015                        GPGMEPLUG_SIGN_CDISP_MAIN );
1016       storeNewCharPtr( &structuring->contentTEncMain,
1017                        GPGMEPLUG_SIGN_CTENC_MAIN );
1018       if( structuring->makeMultiMime ) {
1019         storeNewCharPtr( &structuring->contentTypeVersion,
1020                          GPGMEPLUG_SIGN_CTYPE_VERSION );
1021         storeNewCharPtr( &structuring->contentDispVersion,
1022                          GPGMEPLUG_SIGN_CDISP_VERSION );
1023         storeNewCharPtr( &structuring->contentTEncVersion,
1024                          GPGMEPLUG_SIGN_CTENC_VERSION );
1025         storeNewCharPtr( &structuring->bodyTextVersion,
1026                          GPGMEPLUG_SIGN_BTEXT_VERSION );
1027         storeNewCharPtr( &structuring->contentTypeCode,
1028                          GPGMEPLUG_SIGN_CTYPE_CODE );
1029         storeNewCharPtr( &structuring->contentDispCode,
1030                          GPGMEPLUG_SIGN_CDISP_CODE );
1031         storeNewCharPtr( &structuring->contentTEncCode,
1032                          GPGMEPLUG_SIGN_CTENC_CODE );
1033       }
1034     } else {
1035       storeNewCharPtr( &structuring->flatTextPrefix,
1036                        GPGMEPLUG_SIGN_FLAT_PREFIX );
1037       storeNewCharPtr( &structuring->flatTextSeparator,
1038                        GPGMEPLUG_SIGN_FLAT_SEPARATOR );
1039       storeNewCharPtr( &structuring->flatTextPostfix,
1040                        GPGMEPLUG_SIGN_FLAT_POSTFIX );
1041     }
1042   }
1043   return bOk;
1044 }
1045
1046
1047 static const char*
1048 sig_status_to_string( GpgmeSigStat status )
1049 {
1050   const char *result;
1051
1052   switch (status) {
1053     case GPGME_SIG_STAT_NONE:
1054       result = "Oops: Signature not verified";
1055       break;
1056     case GPGME_SIG_STAT_NOSIG:
1057       result = "No signature found";
1058       break;
1059     case GPGME_SIG_STAT_GOOD:
1060       result = "Good signature";
1061       break;
1062     case GPGME_SIG_STAT_BAD:
1063       result = "BAD signature";
1064       break;
1065     case GPGME_SIG_STAT_NOKEY:
1066       result = "No public key to verify the signature";
1067       break;
1068     case GPGME_SIG_STAT_ERROR:
1069       result = "Error verifying the signature";
1070       break;
1071     case GPGME_SIG_STAT_DIFF:
1072       result = "Different results for signatures";
1073       break;
1074     default:
1075       result = "Error: Unknown status";
1076       break;
1077   }
1078
1079   return result;
1080 }
1081
1082
1083 bool checkMessageSignature( char** cleartext,
1084                             const char* signaturetext,
1085                             bool signatureIsBinary,
1086                             int signatureLen,
1087                             struct SignatureMetaData* sigmeta )
1088 {
1089   GpgmeCtx ctx;
1090   GpgmeSigStat status;
1091   GpgmeData datapart, sigpart;
1092   char* rClear = 0;
1093   size_t clearLen;
1094   GpgmeError err;
1095   GpgmeKey key;
1096   time_t created;
1097   int sig_idx = 0;
1098   const char* statusStr;
1099   const char* fpr;
1100   bool isOpaqueSigned;
1101
1102   if( !cleartext ) {
1103     if( sigmeta )
1104       storeNewCharPtr( &sigmeta->status,
1105                         __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO );
1106
1107     return false;
1108   }
1109
1110   isOpaqueSigned = !*cleartext;
1111
1112   gpgme_new( &ctx );
1113   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1114   gpgme_set_armor (ctx,    signatureIsBinary ? 0 : 1);
1115   /*  gpgme_set_textmode (ctx, signatureIsBinary ? 0 : 1); */
1116
1117   if( isOpaqueSigned )
1118     gpgme_data_new( &datapart );
1119   else
1120     gpgme_data_new_from_mem( &datapart, *cleartext,
1121                              strlen( *cleartext ), 1 );
1122
1123   gpgme_data_new_from_mem( &sigpart,
1124                            signaturetext,
1125                            signatureIsBinary
1126                            ? signatureLen
1127                            : strlen( signaturetext ),
1128                            1 );
1129
1130   gpgme_op_verify( ctx, sigpart, datapart, &status );
1131
1132   if( isOpaqueSigned ) {
1133     rClear = gpgme_data_release_and_get_mem( datapart, &clearLen );
1134     *cleartext = malloc( clearLen + 1 );
1135     if( *cleartext ) {
1136       if( clearLen )
1137         strncpy(*cleartext, rClear, clearLen );
1138       (*cleartext)[clearLen] = '\0';
1139     }
1140     free( rClear );
1141   }
1142   else
1143     gpgme_data_release( datapart );
1144
1145   gpgme_data_release( sigpart );
1146
1147   /* Provide information in the sigmeta struct */
1148   /* the status string */
1149   statusStr = sig_status_to_string( status );
1150   sigmeta->status = malloc( strlen( statusStr ) + 1 );
1151   if( sigmeta->status ) {
1152     strcpy( sigmeta->status, statusStr );
1153     sigmeta->status[strlen( statusStr )] = '\0';
1154   } else
1155     ; /* nothing to do, is already 0 */
1156
1157   /* Extended information for any number of signatures. */
1158   fpr = gpgme_get_sig_status( ctx, sig_idx, &status, &created );
1159   sigmeta->extended_info = 0;
1160   while( fpr != NULL ) {
1161     struct tm* ctime_val;
1162     const char* sig_status;
1163
1164     void* realloc_return = realloc( sigmeta->extended_info,
1165                                     sizeof( struct SignatureMetaDataExtendedInfo ) * ( sig_idx + 1 ) );
1166     if( realloc_return ) {
1167       sigmeta->extended_info = realloc_return;
1168
1169       /* clear the data area */
1170       memset( &sigmeta->extended_info[sig_idx], 0, sizeof (struct SignatureMetaDataExtendedInfo) );
1171
1172       /* the creation time */
1173       sigmeta->extended_info[sig_idx].creation_time = malloc( sizeof( struct tm ) );
1174       if( sigmeta->extended_info[sig_idx].creation_time ) {
1175         ctime_val = localtime( &created );
1176         memcpy( sigmeta->extended_info[sig_idx].creation_time,
1177                 ctime_val, sizeof( struct tm ) );
1178       }
1179
1180       sigmeta->extended_info[sig_idx].validity = GPGME_VALIDITY_UNKNOWN;
1181
1182       err = gpgme_get_sig_key (ctx, sig_idx, &key);
1183
1184       if ( err == GPGME_No_Error) {
1185         const char* attr_string;
1186         unsigned long attr_ulong;
1187
1188         /* extract key identidy */
1189         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_KEYID, 0, 0);
1190         if (attr_string != 0)
1191             storeNewCharPtr( &sigmeta->extended_info[sig_idx].keyid, attr_string );
1192
1193         /* extract finger print */
1194         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_FPR, 0, 0);
1195         if (attr_string != 0)
1196             storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint,
1197                             attr_string );
1198
1199         /* algorithms useable with this key */
1200         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_ALGO, 0, 0);
1201         if (attr_string != 0)
1202             storeNewCharPtr( &sigmeta->extended_info[sig_idx].algo,
1203                             attr_string );
1204         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_ALGO, 0, 0);
1205         sigmeta->extended_info[sig_idx].algo_num = attr_ulong;
1206
1207         /* extract key validity */
1208         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_VALIDITY, 0, 0);
1209         sigmeta->extended_info[sig_idx].validity = attr_ulong;
1210
1211         /* extract user id, according to the documentation it's representable
1212         * as a number, but it seems that it also has a string representation
1213         */
1214         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_USERID, 0, 0);
1215         if (attr_string != 0)
1216             storeNewCharPtr( &sigmeta->extended_info[sig_idx].userid,
1217                             attr_string );
1218         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_USERID, 0, 0);
1219         sigmeta->extended_info[sig_idx].userid_num = attr_ulong;
1220
1221         /* extract the length */
1222         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_LEN, 0, 0);
1223         sigmeta->extended_info[sig_idx].keylen = attr_ulong;
1224
1225         /* extract the creation time of the key */
1226         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_CREATED, 0, 0);
1227         sigmeta->extended_info[sig_idx].key_created = attr_ulong;
1228
1229         /* extract the expiration time of the key */
1230         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_EXPIRE, 0, 0);
1231         sigmeta->extended_info[sig_idx].key_expires = attr_ulong;
1232
1233         /* extract user name */
1234         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_NAME, 0, 0);
1235         if (attr_string != 0)
1236             storeNewCharPtr( &sigmeta->extended_info[sig_idx].name,
1237                             attr_string );
1238
1239         /* extract email */
1240         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_EMAIL, 0, 0);
1241         if (attr_string != 0)
1242             storeNewCharPtr( &sigmeta->extended_info[sig_idx].email,
1243                             attr_string );
1244
1245         /* extract the comment */
1246         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_COMMENT, 0, 0);
1247         if (attr_string != 0)
1248             storeNewCharPtr( &sigmeta->extended_info[sig_idx].comment,
1249                             attr_string );
1250       }
1251       else
1252         storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint, fpr );
1253
1254       sig_status = sig_status_to_string( status );
1255       storeNewCharPtr( &sigmeta->extended_info[sig_idx].status_text,
1256                        sig_status );
1257
1258     } else
1259       break; /* if allocation fails once, it isn't likely to
1260                 succeed the next time either */
1261
1262     fpr = gpgme_get_sig_status (ctx, ++sig_idx, &status, &created);
1263   }
1264   sigmeta->extended_info_count = sig_idx;
1265   sigmeta->nota_xml = gpgme_get_notation( ctx );
1266   sigmeta->status_code = status;
1267
1268   gpgme_release( ctx );
1269   return ( status == GPGME_SIG_STAT_GOOD );
1270 }
1271
1272 bool storeCertificatesFromMessage(
1273         const char* ciphertext ){ return true; }
1274
1275
1276 /* returns address if address doesn't contain a <xxx> part
1277  * else it returns a new string xxx and frees address
1278  */
1279 static char* parseAddress( char* address )
1280 {
1281   char* result = address;
1282   char* i;
1283   char* j;
1284   if( !result ) return result;
1285   i = index( address, '<' );
1286   if( i ) {
1287     j = index( i+1, '>' );
1288     if( j == NULL ) j = address+strlen(address);
1289     result = malloc( j-i );
1290     strncpy( result, i+1, j-i-1 );
1291     result[j-i-1] = '\0';
1292     free( address );
1293   } else {
1294     i = address;
1295     j = i+strlen(address);
1296   }
1297   {
1298     /* remove surrounding whitespace */
1299     char* k = result+(j-i-1);
1300     char* l = result;
1301     while( isspace( *l ) ) ++l;
1302     while( isspace( *k ) ) --k;
1303     if( l != result || k != result+(j-i-1) ) {
1304       char* result2 = malloc( k-l+2 );
1305       strncpy( result2, l, k-l+1 );
1306       result2[k-l+1] = '\0';
1307       free(result);
1308       result = result2;
1309     }
1310   }
1311   return result;
1312 }
1313
1314 static char* nextAddress( const char** address )
1315 {
1316   const char *start = *address;
1317   char* result = NULL;
1318   int quote = 0;
1319   int comment = 0;
1320   int found = 0;
1321   if( *address == NULL ) return NULL;
1322   while( **address ) {
1323
1324     switch( **address ) {
1325     case '\\': /* escaped character */
1326       ++(*address);
1327       break;
1328     case '"':
1329       if( comment == 0 ) {
1330         if( quote > 0 ) --quote;
1331         else ++quote;
1332       }
1333       break;
1334     case '(': /* comment start */
1335       if( quote == 0 ) ++comment;
1336       break;
1337     case ')': /* comment end */
1338       if( quote == 0 ) --comment;
1339       break;
1340     case '\0':
1341     case '\1': /* delimiter */
1342       if( quote == 0 && comment == 0 ) {
1343         found = 1;
1344       }
1345       break;
1346     }
1347     ++(*address);
1348     if( found ) break;
1349   }
1350   if( found || **address == 0 ) {
1351     size_t len;
1352     len = *address - start;
1353     if( len > 0 ) {
1354       if( **address != 0 ) --len;
1355       result = malloc( len*sizeof(char)+1 );
1356       strncpy( result, start, len );
1357       result[len] = '\0';
1358     }
1359   }
1360   return parseAddress(result);
1361 }
1362
1363 /*
1364   Find all certificate for a given addressee and return them in a
1365   '\1' separated list.
1366   NOTE: The certificate parameter must point to an allready allocated
1367   block of memory which is large enough to hold the complete list.
1368 */
1369 bool findCertificates( const char* addressee, char** certificates )
1370 {
1371   GpgmeCtx ctx;
1372   GpgmeError err;
1373   GpgmeKey rKey;
1374   const char *s;
1375   const char *s2;
1376   int nFound = 0;
1377
1378   strcpy( *certificates, "" );
1379
1380   gpgme_new (&ctx);
1381   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1382
1383   err = gpgme_op_keylist_start(ctx, addressee, 0);
1384   while( GPGME_No_Error == err ) {
1385     err = gpgme_op_keylist_next(ctx, &rKey);
1386     if( GPGME_No_Error == err ) {
1387       s = gpgme_key_get_string_attr (rKey, GPGME_ATTR_USERID, NULL, 0);
1388       if( s ) {
1389         s2 = gpgme_key_get_string_attr (rKey, GPGME_ATTR_FPR, NULL, 0);
1390         if( s2 ) {
1391           if( nFound )
1392             strcat(*certificates,"\1" );
1393           strcat( *certificates, s );
1394           strcat( *certificates, "    (" );
1395           strcat( *certificates, s2 );
1396           strcat( *certificates, ")" );
1397           ++nFound;
1398         }
1399       }
1400     }
1401   }
1402   gpgme_op_keylist_end( ctx );
1403   gpgme_release (ctx);
1404
1405   return ( 0 < nFound );
1406 }
1407
1408 bool encryptMessage( const char*  cleartext,
1409                      const char** ciphertext,
1410                      const size_t* cipherLen,
1411                      const char*  certificate,
1412                      struct StructuringInfo* structuring,
1413                      int* errId,
1414                      char** errTxt )
1415 {
1416   GpgmeCtx ctx;
1417   GpgmeError err;
1418   GpgmeData gCiphertext, gPlaintext;
1419   GpgmeRecipients rset;
1420   char*  rCiph = 0;
1421   bool   bOk   = false;
1422
1423   init_StructuringInfo( structuring );
1424
1425   gpgme_new (&ctx);
1426   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1427
1428   gpgme_set_armor (ctx, __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ? 0 : 1);
1429   /*  gpgme_set_textmode (ctx, 1); */
1430
1431   gpgme_data_new_from_mem (&gPlaintext, cleartext,
1432                             1+strlen( cleartext ), 1 );
1433   err = gpgme_data_new ( &gCiphertext );
1434
1435   gpgme_recipients_new (&rset);
1436
1437   /*
1438   if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
1439   {
1440     gpgme_recipients_add_name (rset,
1441       "/CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=DĂĽsseldorf,C=DE" );
1442
1443     fputs( "\nGPGSMPLUG encryptMessage() using test key of Aegypten Project\n", stderr );
1444   }
1445   else
1446   */
1447   {
1448     const char* p = certificate;
1449     char* tok;
1450     while( (tok = nextAddress( &p ) ) != 0 ) {
1451       gpgme_recipients_add_name (rset, tok );
1452       fprintf( stderr, "\nGPGMEPLUG encryptMessage() using addressee %s\n", tok );
1453       free(tok);
1454     }
1455   }
1456
1457   /* PENDING(g10) Implement this
1458      Possible values: RSA = 1, SHA1 = 2, TripleDES = 3
1459      gpgme_set_encryption_algorithm( ctx, config.encryptionAlgorithm );
1460
1461      -> Your are mixing public key and symmetric algorithms.  The
1462      latter may be configured but the sphix specifications do opnly
1463      allow 3-DES so this is not nothing we need to do.  The proper way
1464      to select the symmetric algorithm is anyway by looking at the
1465      capabilities of the certificate because this is the only way to
1466      know what the recipient can accept. [wk 2002-03-23]
1467
1468      PENDING(g10) Implement this
1469      gpgme_set_encryption_check_certificate_path(
1470      config.checkCertificatePath )
1471
1472      PENDING(g10) Implement this
1473      gpgme_set_encryption_check_certificate_path_to_root(
1474      config.checkEncryptionCertificatePathToRoot )
1475
1476      -> Not checking a certificate up to the ROOT CA is dangerous and
1477      stupid. There is no need for those options.  [wk 2002-03-23] */
1478
1479
1480
1481   err = gpgme_op_encrypt (ctx, rset, gPlaintext, gCiphertext );
1482   if( err ) {
1483     fprintf( stderr, "\ngpgme_op_encrypt() returned this error code:  %i\n\n", err );
1484     if( errId )
1485       *errId = err;
1486     if( errTxt ) {
1487       const char* _errTxt = gpgme_strerror( err );
1488       *errTxt = malloc( strlen( _errTxt ) + 1 );
1489       if( *errTxt )
1490         strcpy(*errTxt, _errTxt );
1491     }
1492   }
1493
1494   gpgme_recipients_release (rset);
1495   gpgme_data_release (gPlaintext);
1496
1497   if( err == GPGME_No_Error ) {
1498     if( __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ) {
1499       *ciphertext = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1500       bOk = true;
1501     }
1502     else {
1503       rCiph = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1504       *ciphertext = malloc( *cipherLen + 1 );
1505       if( *ciphertext ) {
1506         if( *cipherLen ) {
1507           bOk = true;
1508           strncpy((char*)*ciphertext, rCiph, *cipherLen );
1509         }
1510         ((char*)(*ciphertext))[*cipherLen] = 0;
1511       }
1512       free( rCiph );
1513     }
1514   }
1515   else {
1516     gpgme_data_release ( gCiphertext );
1517     *ciphertext = 0;
1518     /* error handling is missing: if only one untrusted key was found
1519       (or none at all), gpg won't sign the message.  (hier fehlt eine
1520       Fehlerbehandlung: fuer einen Recipient nur ein untrusted key
1521       (oder gar keiner) gefunden wurde, verweigert gpg das signieren.)
1522     */
1523   }
1524
1525   gpgme_release (ctx);
1526
1527   fflush( stderr );
1528
1529   if( bOk && structuring ) {
1530     structuring->includeCleartext = GPGMEPLUG_ENC_INCLUDE_CLEARTEXT;
1531     structuring->makeMimeObject   = GPGMEPLUG_ENC_MAKE_MIME_OBJECT;
1532     if( structuring->makeMimeObject ) {
1533       structuring->makeMultiMime  = GPGMEPLUG_ENC_MAKE_MULTI_MIME;
1534       storeNewCharPtr( &structuring->contentTypeMain,
1535                        GPGMEPLUG_ENC_CTYPE_MAIN );
1536       storeNewCharPtr( &structuring->contentDispMain,
1537                        GPGMEPLUG_ENC_CDISP_MAIN );
1538       storeNewCharPtr( &structuring->contentTEncMain,
1539                        GPGMEPLUG_ENC_CTENC_MAIN );
1540       if( structuring->makeMultiMime ) {
1541         storeNewCharPtr( &structuring->contentTypeVersion,
1542                          GPGMEPLUG_ENC_CTYPE_VERSION );
1543         storeNewCharPtr( &structuring->contentDispVersion,
1544                          GPGMEPLUG_ENC_CDISP_VERSION );
1545         storeNewCharPtr( &structuring->contentTEncVersion,
1546                          GPGMEPLUG_ENC_CTENC_VERSION );
1547         storeNewCharPtr( &structuring->bodyTextVersion,
1548                          GPGMEPLUG_ENC_BTEXT_VERSION );
1549         storeNewCharPtr( &structuring->contentTypeCode,
1550                          GPGMEPLUG_ENC_CTYPE_CODE );
1551         storeNewCharPtr( &structuring->contentDispCode,
1552                          GPGMEPLUG_ENC_CDISP_CODE );
1553         storeNewCharPtr( &structuring->contentTEncCode,
1554                          GPGMEPLUG_ENC_CTENC_CODE );
1555       }
1556     } else {
1557       storeNewCharPtr( &structuring->flatTextPrefix,
1558                        GPGMEPLUG_ENC_FLAT_PREFIX );
1559       storeNewCharPtr( &structuring->flatTextSeparator,
1560                        GPGMEPLUG_ENC_FLAT_SEPARATOR );
1561       storeNewCharPtr( &structuring->flatTextPostfix,
1562                        GPGMEPLUG_ENC_FLAT_POSTFIX );
1563     }
1564   }
1565   return bOk;
1566 }
1567
1568
1569 bool encryptAndSignMessage( const char* cleartext,
1570                             const char** ciphertext,
1571                             const char* certificate,
1572                             struct StructuringInfo* structuring )
1573 {
1574   bool bOk;
1575
1576   init_StructuringInfo( structuring );
1577
1578   bOk = false;
1579
1580   /* implementation of this function is still missing */
1581
1582   if( bOk && structuring ) {
1583     structuring->includeCleartext = GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT;
1584     structuring->makeMimeObject   = GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT;
1585     if( structuring->makeMimeObject ) {
1586       structuring->makeMultiMime  = GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME;
1587       storeNewCharPtr( &structuring->contentTypeMain,
1588                        GPGMEPLUG_ENCSIGN_CTYPE_MAIN );
1589       storeNewCharPtr( &structuring->contentDispMain,
1590                        GPGMEPLUG_ENCSIGN_CDISP_MAIN );
1591       storeNewCharPtr( &structuring->contentTEncMain,
1592                        GPGMEPLUG_ENCSIGN_CTENC_MAIN );
1593       if( structuring->makeMultiMime ) {
1594         storeNewCharPtr( &structuring->contentTypeVersion,
1595                          GPGMEPLUG_ENCSIGN_CTYPE_VERSION );
1596         storeNewCharPtr( &structuring->contentDispVersion,
1597                          GPGMEPLUG_ENCSIGN_CDISP_VERSION );
1598         storeNewCharPtr( &structuring->contentTEncVersion,
1599                          GPGMEPLUG_ENCSIGN_CTENC_VERSION );
1600         storeNewCharPtr( &structuring->bodyTextVersion,
1601                          GPGMEPLUG_ENCSIGN_BTEXT_VERSION );
1602         storeNewCharPtr( &structuring->contentTypeCode,
1603                          GPGMEPLUG_ENCSIGN_CTYPE_CODE );
1604         storeNewCharPtr( &structuring->contentDispCode,
1605                          GPGMEPLUG_ENCSIGN_CDISP_CODE );
1606         storeNewCharPtr( &structuring->contentTEncCode,
1607                          GPGMEPLUG_ENCSIGN_CTENC_CODE );
1608       }
1609     } else {
1610       storeNewCharPtr( &structuring->flatTextPrefix,
1611                        GPGMEPLUG_ENCSIGN_FLAT_PREFIX );
1612       storeNewCharPtr( &structuring->flatTextSeparator,
1613                        GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR );
1614       storeNewCharPtr( &structuring->flatTextPostfix,
1615                        GPGMEPLUG_ENCSIGN_FLAT_POSTFIX );
1616     }
1617   }
1618   return bOk;
1619 }
1620
1621
1622 bool decryptMessage( const char* ciphertext,
1623                      bool        cipherIsBinary,
1624                      int         cipherLen,
1625                      const char** cleartext,
1626                      const char* certificate )
1627 {
1628   GpgmeCtx ctx;
1629   GpgmeError err;
1630   GpgmeData gCiphertext, gPlaintext;
1631   size_t rCLen = 0;
1632   char*  rCiph = 0;
1633   bool bOk = false;
1634
1635   if( !ciphertext )
1636     return false;
1637
1638   err = gpgme_new (&ctx);
1639   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1640   
1641   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
1642   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
1643
1644   /*
1645   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
1646                            1+strlen( ciphertext ), 1 ); */
1647   gpgme_data_new_from_mem( &gCiphertext,
1648                            ciphertext,
1649                            cipherIsBinary
1650                            ? cipherLen
1651                            : strlen( ciphertext ),
1652                            1 );
1653
1654   gpgme_data_new( &gPlaintext );
1655
1656   gpgme_op_decrypt( ctx, gCiphertext, gPlaintext );
1657   gpgme_data_release( gCiphertext );
1658
1659   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
1660
1661   *cleartext = malloc( rCLen + 1 );
1662   if( *cleartext ) {
1663       if( rCLen ) {
1664           bOk = true;
1665           strncpy((char*)*cleartext, rCiph, rCLen );
1666       }
1667       ((char*)(*cleartext))[rCLen] = 0;
1668   }
1669
1670   free( rCiph );
1671   gpgme_release( ctx );
1672   return bOk;
1673 }
1674
1675 bool decryptAndCheckMessage( const char* ciphertext,
1676           const char** cleartext, const char* certificate,
1677           struct SignatureMetaData* sigmeta ){ return true; }
1678
1679
1680 const char* requestCertificateDialog(){ return 0; }
1681
1682 bool requestDecentralCertificate( const char* certparms, 
1683                                   char** generatedKey, int* length )
1684 {
1685     GpgmeError err;
1686     GpgmeCtx ctx;
1687     GpgmeData pub;
1688     int len;
1689
1690     err = gpgme_data_new (&pub);
1691     fprintf( stderr,  "1: gpgme returned %d\n", err );
1692     if( err != GPGME_No_Error )
1693         return false;
1694
1695     err = gpgme_new (&ctx);
1696     fprintf( stderr,  "2: gpgme returned %d\n", err );
1697     if( err != GPGME_No_Error ) {
1698         gpgme_data_release( pub );
1699         return false;
1700     }
1701
1702     gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
1703     /* Don't ASCII-armor, the MUA will use base64 encoding */
1704     /*    gpgme_set_armor (ctx, 1); */
1705     err = gpgme_op_genkey (ctx, certparms, pub, NULL );
1706     fprintf( stderr,  "3: gpgme returned %d\n", err );
1707     if( err != GPGME_No_Error ) {
1708         gpgme_data_release( pub );
1709         gpgme_release( ctx );
1710         return false;
1711     }
1712
1713     gpgme_release (ctx);
1714     *generatedKey = gpgme_data_release_and_get_mem (pub, &len);
1715     *length = len;
1716
1717     /* The buffer generatedKey contains the LEN bytes you want */
1718     // Caller is responsible for freeing
1719     return true;
1720 }
1721
1722 bool requestCentralCertificateAndPSE( const char* name,
1723           const char* email, const char* organization, const char* department,
1724           const char* ca_address ){ return true; }
1725
1726 bool createPSE(){ return true; }
1727
1728 bool registerCertificate( const char* certificate ){ return true; }
1729
1730 bool requestCertificateProlongation( const char* certificate,
1731                                      const char* ca_address ){ return true; }
1732
1733 const char* certificateChain(){ return 0; }
1734
1735 bool deleteCertificate( const char* certificate ){ return true; }
1736
1737 bool archiveCertificate( const char* certificate ){ return true; }
1738
1739
1740 const char* displayCRL(){ return 0; }
1741
1742 void updateCRL(){}
1743
1744 /*
1745  * Copyright (C) 2002 g10 Code GmbH
1746  * 
1747  *     This program is free software; you can redistribute it
1748  *     and/or modify it under the terms of the GNU General Public
1749  *     License as published by the Free Software Foundation; either
1750  *     version 2 of the License, or (at your option) any later
1751  *     version.
1752  * 
1753  *     This program is distributed in the hope that it will be
1754  *     useful, but WITHOUT ANY WARRANTY; without even the implied
1755  *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
1756  *     PURPOSE.  See the GNU General Public License for more
1757  *     details.
1758  * 
1759  *     You should have received a copy of the GNU General Public
1760  *     License along with this program; if not, write to the Free
1761  *     Software Foundation, Inc., 59 Temple Place - Suite 330,
1762  *     Boston, MA  02111, USA.
1763  */
1764
1765 /* Max number of parts in a DN */
1766 #define MAX_GPGME_IDX 20
1767
1768 /* some macros to replace ctype ones and avoid locale problems */
1769 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
1770 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
1771 #define hexdigitp(a) (digitp (a)                     \
1772                       || (*(a) >= 'A' && *(a) <= 'F')  \
1773                       || (*(a) >= 'a' && *(a) <= 'f'))
1774 /* the atoi macros assume that the buffer has only valid digits */
1775 #define atoi_1(p)   (*(p) - '0' )
1776 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
1777 #define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
1778 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
1779                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
1780 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
1781
1782 #define safe_malloc( x ) malloc( x )
1783 #define xstrdup( x ) (x)?strdup(x):0
1784
1785 static void safe_free( void** x ) 
1786 {
1787   free( *x );
1788   *x = 0;
1789 }
1790 /*#define safe_free( x ) free( x )*/
1791
1792 /* Parse a DN and return an array-ized one.  This is not a validating
1793    parser and it does not support any old-stylish syntax; gpgme is
1794    expected to return only rfc2253 compatible strings. */
1795 static const unsigned char *
1796 parse_dn_part (struct DnPair *array, const unsigned char *string)
1797 {
1798   const unsigned char *s, *s1;
1799   size_t n;
1800   unsigned char *p;
1801
1802   /* parse attributeType */
1803   for (s = string+1; *s && *s != '='; s++)
1804     ;
1805   if (!*s)
1806     return NULL; /* error */
1807   n = s - string;
1808   if (!n)
1809     return NULL; /* empty key */
1810   array->key = p = safe_malloc (n+1);
1811   memcpy (p, string, n); /* fixme: trim trailing spaces */
1812   p[n] = 0;
1813   string = s + 1;
1814
1815   if (*string == '#')
1816     { /* hexstring */
1817       string++;
1818       for (s=string; hexdigitp (s); s++)
1819         s++;
1820       n = s - string;
1821       if (!n || (n & 1))
1822         return NULL; /* empty or odd number of digits */
1823       n /= 2;
1824       array->value = p = safe_malloc (n+1);
1825       for (s1=string; n; s1 += 2, n--)
1826         *p++ = xtoi_2 (s1);
1827       *p = 0;
1828    }
1829   else
1830     { /* regular v3 quoted string */
1831       for (n=0, s=string; *s; s++)
1832         {
1833           if (*s == '\\')
1834             { /* pair */
1835               s++;
1836               if (*s == ',' || *s == '=' || *s == '+'
1837                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
1838                   || *s == '\\' || *s == '\"' || *s == ' ')
1839                 n++;
1840               else if (hexdigitp (s) && hexdigitp (s+1))
1841                 {
1842                   s++;
1843                   n++;
1844                 }
1845               else
1846                 return NULL; /* invalid escape sequence */
1847             }
1848           else if (*s == '\"')
1849             return NULL; /* invalid encoding */
1850           else if (*s == ',' || *s == '=' || *s == '+'
1851                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
1852             break; 
1853           else
1854             n++;
1855         }
1856
1857       array->value = p = safe_malloc (n+1);
1858       for (s=string; n; s++, n--)
1859         {
1860           if (*s == '\\')
1861             { 
1862               s++;
1863               if (hexdigitp (s))
1864                 {
1865                   *p++ = xtoi_2 (s);
1866                   s++;
1867                 }
1868               else
1869                 *p++ = *s;
1870             }
1871           else
1872             *p++ = *s;
1873         }
1874       *p = 0;
1875     }
1876   return s;
1877 }
1878
1879
1880 /* Parse a DN and return an array-ized one.  This is not a validating
1881    parser and it does not support any old-stylish syntax; gpgme is
1882    expected to return only rfc2253 compatible strings. */
1883 static struct DnPair *
1884 parse_dn (const unsigned char *string)
1885 {
1886   struct DnPair *array;
1887   size_t arrayidx, arraysize;
1888   int i;
1889
1890   arraysize = 7; /* C,ST,L,O,OU,CN,email */
1891   array = safe_malloc ((arraysize+1) * sizeof *array);
1892   arrayidx = 0;
1893   while (*string)
1894     {
1895       while (*string == ' ')
1896         string++;
1897       if (!*string)
1898         break; /* ready */
1899       if (arrayidx >= arraysize)
1900         { /* mutt lacks a real safe_realoc - so we need to copy */
1901           struct DnPair *a2;
1902
1903           arraysize += 5;
1904           a2 = safe_malloc ((arraysize+1) * sizeof *array);
1905           for (i=0; i < arrayidx; i++)
1906             {
1907               a2[i].key = array[i].key;
1908               a2[i].value = array[i].value;
1909             }
1910           safe_free ((void **)&array);
1911           array = a2;
1912         }
1913       array[arrayidx].key = NULL;
1914       array[arrayidx].value = NULL;
1915       string = parse_dn_part (array+arrayidx, string);
1916       arrayidx++;
1917       if (!string)
1918         goto failure;
1919       while (*string == ' ')
1920         string++;
1921       if (*string && *string != ',' && *string != ';' && *string != '+')
1922         goto failure; /* invalid delimiter */
1923       if (*string)
1924         string++;
1925     }
1926   array[arrayidx].key = NULL;
1927   array[arrayidx].value = NULL;
1928   return array;
1929
1930  failure:
1931   for (i=0; i < arrayidx; i++)
1932     {
1933       safe_free ((void**)&array[i].key);
1934       safe_free ((void**)&array[i].value);
1935     }
1936   safe_free ((void**)&array);
1937   return NULL;
1938 }
1939
1940 static int add_dn_part( char* result, struct DnPair* dn, const char* part )
1941 {
1942   int any = 0;
1943
1944   for(; dn->key; ++dn ) {
1945     if( !strcmp( dn->key, part ) ) {
1946       if( any ) strcat( result, "+" );
1947       strcat( result, dn->value );
1948       any = 1;
1949     }
1950   }
1951   return any;
1952 }
1953
1954 static char* reorder_dn( struct DnPair *dn )
1955 {
1956   const char* stdpart[] = {
1957     "CN", "OU", "O", "STREET", "L", "ST", "C", NULL 
1958   };
1959   int any=0, any2=0, len=0, i;
1960   char* result;
1961   for( i = 0; dn[i].key; ++i ) {
1962     len += strlen( dn[i].key );
1963     len += strlen( dn[i].value );
1964     len += 4; /* ',' and '=', and possibly "(" and ")" */
1965   }
1966   result = (char*)safe_malloc( (len+1)*sizeof(char) );
1967   *result = 0;
1968
1969   /* add standard parts */
1970   for( i = 0; stdpart[i]; ++i ) {
1971     if( any ) {
1972       strcat( result, "," );
1973     }
1974     any = add_dn_part( result, dn, stdpart[i] );
1975   }
1976
1977   /* add remaining parts in no particular order */
1978   for(; dn->key; ++dn ) {
1979     for( i = 0; stdpart[i]; ++i ) {
1980       if( !strcmp( dn->key, stdpart[i] ) ) {
1981         break;
1982       }
1983     }
1984     if( !stdpart[i] ) {
1985       if( any ) strcat( result, "," );
1986       if( !any2 ) strcat( result, "(");
1987       any = add_dn_part( result, dn, dn->key );
1988       any2 = 1;
1989     }
1990   }
1991   if( any2 ) strcat( result, ")");
1992   return result;
1993 }
1994
1995 struct CertIterator {
1996   GpgmeCtx ctx;  
1997   struct CertificateInfo info;
1998 };
1999
2000 struct CertIterator* startListCertificates( const char* pattern )
2001 {
2002     GpgmeError err;
2003     struct CertIterator* it;
2004     /*fprintf( stderr,  "startListCertificates()" );*/
2005
2006     it = (struct CertIterator*)safe_malloc( sizeof( struct CertIterator ) );
2007
2008     err = gpgme_new (&(it->ctx));
2009     /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2010     if( err != GPGME_No_Error ) {
2011       free( it );
2012       return NULL;
2013     }
2014
2015     gpgme_set_protocol (it->ctx, GPGME_PROTOCOL_CMS);
2016     err =  gpgme_op_keylist_start ( it->ctx, pattern, 0);
2017     if( err != GPGME_No_Error ) {
2018       endListCertificates( it );
2019       return NULL;
2020     }
2021     memset( &(it->info), 0, sizeof( struct CertificateInfo ) );
2022     return it;
2023 }
2024
2025 static void freeStringArray( char** c )
2026 {
2027     char** _c = c;
2028     while( c && *c ) {
2029       /*fprintf( stderr, "freeing \"%s\"\n", *c );*/
2030       safe_free( (void**)&(*c) );
2031       ++c;
2032     }
2033     safe_free( (void**)&_c );
2034 }
2035
2036 static void freeInfo( struct CertificateInfo* info )
2037 {
2038   struct DnPair* a = info->dnarray;
2039   assert( info );
2040   if( info->userid ) freeStringArray( info->userid );
2041   if( info->serial ) safe_free( (void**)&(info->serial) );
2042   if( info->fingerprint ) safe_free( (void**)&(info->fingerprint) );
2043   if( info->issuer ) safe_free( (void**)&(info->issuer) );
2044   if( info->chainid ) safe_free( (void**)&(info->chainid) );
2045   if( info->caps ) safe_free( (void**)&(info->caps) );
2046   while( a && a->key && a->value ) {
2047     safe_free ((void**)&(a->key));
2048     safe_free ((void**)&(a->value));
2049     ++a;
2050   }
2051   if( info->dnarray ) safe_free ((void**)&(info->dnarray));
2052   memset( info, 0, sizeof( *info ) );
2053 }
2054
2055 static char* make_fingerprint( const char* fpr )
2056 {
2057   int len = strlen(fpr);
2058   int i = 0;
2059   char* result = safe_malloc( (len + len/2 + 1)*sizeof(char) );
2060   if( !result ) return NULL;
2061   for(; *fpr; ++fpr, ++i ) {
2062     if( i%3 == 2) {
2063       result[i] = ':'; ++i;
2064     }
2065     result[i] = *fpr;
2066   }
2067   result[i] = 0;
2068   return result;
2069 }
2070
2071 struct CertificateInfo* nextCertificate( struct CertIterator* it )
2072 {
2073   GpgmeError err;
2074   GpgmeKey   key;
2075   assert( it );
2076   err = gpgme_op_keylist_next ( it->ctx, &key);
2077   if( err != GPGME_EOF ) {   
2078     int idx;
2079     const char* s;
2080     unsigned long u;
2081     char* names[MAX_GPGME_IDX+1];
2082     struct DnPair *issuer_dn, *tmp_dn;
2083     memset( names, 0, sizeof( names ) );
2084     freeInfo( &(it->info) );
2085
2086     for( idx = 0; (s = gpgme_key_get_string_attr (key, GPGME_ATTR_USERID, 0, idx)) && idx < MAX_GPGME_IDX; 
2087          ++idx ) {
2088       names[idx] = xstrdup( s );
2089     }
2090     
2091     it->info.userid = safe_malloc( sizeof( char* ) * (idx+1) );
2092     memset( it->info.userid, 0, sizeof( char* ) * (idx+1) );
2093     it->info.dnarray = 0;
2094     for( idx = 0; names[idx] != 0; ++idx ) {
2095       struct DnPair* a = parse_dn( names[idx] ); 
2096       if( idx == 0 ) {
2097         it->info.userid[idx] = reorder_dn( a );
2098         safe_free( (void **)&(names[idx]) );
2099       } else {
2100         it->info.userid[idx] = names[idx];
2101         it->info.dnarray = a;
2102       }
2103     }
2104     it->info.userid[idx] = 0;
2105
2106     s = gpgme_key_get_string_attr (key, GPGME_ATTR_SERIAL, 0, 0); 
2107     it->info.serial = xstrdup(s);
2108
2109     s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, 0, 0); 
2110     it->info.fingerprint = make_fingerprint( s );
2111
2112     s = gpgme_key_get_string_attr (key, GPGME_ATTR_ISSUER, 0, 0); 
2113     if( s ) {
2114       issuer_dn = tmp_dn = parse_dn( s );     
2115       /*it->info.issuer = xstrdup(s);*/
2116       it->info.issuer = reorder_dn( issuer_dn );
2117       while( tmp_dn->key ) {
2118         safe_free( (void**)&issuer_dn->key );
2119         safe_free( (void**)&issuer_dn->value );
2120         ++tmp_dn;
2121       }
2122       safe_free( (void**)&issuer_dn );
2123     } else {
2124       it->info.issuer = NULL;
2125     }
2126     s = gpgme_key_get_string_attr (key, GPGME_ATTR_CHAINID, 0, 0); 
2127     it->info.chainid = xstrdup(s);
2128
2129     s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEY_CAPS, 0, 0); 
2130     it->info.caps = xstrdup(s);
2131
2132     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_CREATED, 0, 0); 
2133     it->info.created = u;
2134
2135     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_EXPIRE, 0, 0); 
2136     it->info.expire = u;
2137
2138     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_IS_SECRET, 0, 0); 
2139     it->info.secret = u;
2140
2141     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_UID_INVALID, 0, 0); 
2142     it->info.invalid = u;
2143
2144     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_EXPIRED, 0, 0); 
2145     it->info.expired = u;
2146
2147     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_DISABLED, 0, 0); 
2148     it->info.disabled = u;
2149
2150     gpgme_key_release (key);
2151     return &(it->info);
2152   } else return NULL;
2153 }
2154
2155 void endListCertificates( struct CertIterator* it )
2156 {
2157   /*fprintf( stderr,  "endListCertificates()\n" );*/
2158   assert(it);
2159   freeInfo( &(it->info) );
2160   gpgme_op_keylist_end(it->ctx);
2161   gpgme_release (it->ctx);
2162   free( it );
2163 }