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