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