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