importCertificate( const char* fpr )
[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 bool encryptMessage( const char*  cleartext,
1483                      const char** ciphertext,
1484                      const size_t* cipherLen,
1485                      const char*  certificate,
1486                      struct StructuringInfo* structuring,
1487                      int* errId,
1488                      char** errTxt )
1489 {
1490   GpgmeCtx ctx;
1491   GpgmeError err;
1492   GpgmeData gCiphertext, gPlaintext;
1493   GpgmeRecipients rset;
1494   char*  rCiph = 0;
1495   bool   bOk   = false;
1496
1497   init_StructuringInfo( structuring );
1498
1499   gpgme_new (&ctx);
1500   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1501
1502   gpgme_set_armor (ctx, __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ? 0 : 1);
1503   /*  gpgme_set_textmode (ctx, 1); */
1504
1505   gpgme_data_new_from_mem (&gPlaintext, cleartext,
1506                             1+strlen( cleartext ), 1 );
1507   err = gpgme_data_new ( &gCiphertext );
1508
1509   gpgme_recipients_new (&rset);
1510
1511   /*
1512   if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
1513   {
1514     gpgme_recipients_add_name (rset,
1515       "/CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=DÃ?sseldorf,C=DE" );
1516
1517     fputs( "\nGPGSMPLUG encryptMessage() using test key of Aegypten Project\n", stderr );
1518   }
1519   else
1520   */
1521   {
1522     const char* p = certificate;
1523     char* tok;
1524     while( (tok = nextAddress( &p ) ) != 0 ) {
1525       gpgme_recipients_add_name (rset, tok );
1526       fprintf( stderr, "\nGPGMEPLUG encryptMessage() using addressee %s\n", tok );
1527       free(tok);
1528     }
1529   }
1530
1531   /* PENDING(g10) Implement this
1532      Possible values: RSA = 1, SHA1 = 2, TripleDES = 3
1533      gpgme_set_encryption_algorithm( ctx, config.encryptionAlgorithm );
1534
1535      -> Your are mixing public key and symmetric algorithms.  The
1536      latter may be configured but the sphix specifications do opnly
1537      allow 3-DES so this is not nothing we need to do.  The proper way
1538      to select the symmetric algorithm is anyway by looking at the
1539      capabilities of the certificate because this is the only way to
1540      know what the recipient can accept. [wk 2002-03-23]
1541
1542      PENDING(g10) Implement this
1543      gpgme_set_encryption_check_certificate_path(
1544      config.checkCertificatePath )
1545
1546      PENDING(g10) Implement this
1547      gpgme_set_encryption_check_certificate_path_to_root(
1548      config.checkEncryptionCertificatePathToRoot )
1549
1550      -> Not checking a certificate up to the ROOT CA is dangerous and
1551      stupid. There is no need for those options.  [wk 2002-03-23] */
1552
1553
1554
1555   err = gpgme_op_encrypt (ctx, rset, gPlaintext, gCiphertext );
1556   if( err ) {
1557     fprintf( stderr, "\ngpgme_op_encrypt() returned this error code:  %i\n\n", err );
1558     if( errId )
1559       *errId = err;
1560     if( errTxt ) {
1561       const char* _errTxt = gpgme_strerror( err );
1562       *errTxt = malloc( strlen( _errTxt ) + 1 );
1563       if( *errTxt )
1564         strcpy(*errTxt, _errTxt );
1565     }
1566   }
1567
1568   gpgme_recipients_release (rset);
1569   gpgme_data_release (gPlaintext);
1570
1571   if( err == GPGME_No_Error ) {
1572     if( __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ) {
1573       *ciphertext = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1574       bOk = true;
1575     }
1576     else {
1577       rCiph = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1578       *ciphertext = malloc( *cipherLen + 1 );
1579       if( *ciphertext ) {
1580         if( *cipherLen ) {
1581           bOk = true;
1582           strncpy((char*)*ciphertext, rCiph, *cipherLen );
1583         }
1584         ((char*)(*ciphertext))[*cipherLen] = 0;
1585       }
1586       free( rCiph );
1587     }
1588   }
1589   else {
1590     gpgme_data_release ( gCiphertext );
1591     *ciphertext = 0;
1592     /* error handling is missing: if only one untrusted key was found
1593       (or none at all), gpg won't sign the message.  (hier fehlt eine
1594       Fehlerbehandlung: fuer einen Recipient nur ein untrusted key
1595       (oder gar keiner) gefunden wurde, verweigert gpg das signieren.)
1596     */
1597   }
1598
1599   gpgme_release (ctx);
1600
1601   fflush( stderr );
1602
1603   if( bOk && structuring ) {
1604     structuring->includeCleartext = GPGMEPLUG_ENC_INCLUDE_CLEARTEXT;
1605     structuring->makeMimeObject   = GPGMEPLUG_ENC_MAKE_MIME_OBJECT;
1606     if( structuring->makeMimeObject ) {
1607       structuring->makeMultiMime  = GPGMEPLUG_ENC_MAKE_MULTI_MIME;
1608       storeNewCharPtr( &structuring->contentTypeMain,
1609                        GPGMEPLUG_ENC_CTYPE_MAIN );
1610       storeNewCharPtr( &structuring->contentDispMain,
1611                        GPGMEPLUG_ENC_CDISP_MAIN );
1612       storeNewCharPtr( &structuring->contentTEncMain,
1613                        GPGMEPLUG_ENC_CTENC_MAIN );
1614       if( structuring->makeMultiMime ) {
1615         storeNewCharPtr( &structuring->contentTypeVersion,
1616                          GPGMEPLUG_ENC_CTYPE_VERSION );
1617         storeNewCharPtr( &structuring->contentDispVersion,
1618                          GPGMEPLUG_ENC_CDISP_VERSION );
1619         storeNewCharPtr( &structuring->contentTEncVersion,
1620                          GPGMEPLUG_ENC_CTENC_VERSION );
1621         storeNewCharPtr( &structuring->bodyTextVersion,
1622                          GPGMEPLUG_ENC_BTEXT_VERSION );
1623         storeNewCharPtr( &structuring->contentTypeCode,
1624                          GPGMEPLUG_ENC_CTYPE_CODE );
1625         storeNewCharPtr( &structuring->contentDispCode,
1626                          GPGMEPLUG_ENC_CDISP_CODE );
1627         storeNewCharPtr( &structuring->contentTEncCode,
1628                          GPGMEPLUG_ENC_CTENC_CODE );
1629       }
1630     } else {
1631       storeNewCharPtr( &structuring->flatTextPrefix,
1632                        GPGMEPLUG_ENC_FLAT_PREFIX );
1633       storeNewCharPtr( &structuring->flatTextSeparator,
1634                        GPGMEPLUG_ENC_FLAT_SEPARATOR );
1635       storeNewCharPtr( &structuring->flatTextPostfix,
1636                        GPGMEPLUG_ENC_FLAT_POSTFIX );
1637     }
1638   }
1639   return bOk;
1640 }
1641
1642
1643 bool encryptAndSignMessage( const char* cleartext,
1644                             const char** ciphertext,
1645                             const char* certificate,
1646                             struct StructuringInfo* structuring )
1647 {
1648   bool bOk;
1649
1650   init_StructuringInfo( structuring );
1651
1652   bOk = false;
1653
1654   /* implementation of this function is still missing */
1655
1656   if( bOk && structuring ) {
1657     structuring->includeCleartext = GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT;
1658     structuring->makeMimeObject   = GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT;
1659     if( structuring->makeMimeObject ) {
1660       structuring->makeMultiMime  = GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME;
1661       storeNewCharPtr( &structuring->contentTypeMain,
1662                        GPGMEPLUG_ENCSIGN_CTYPE_MAIN );
1663       storeNewCharPtr( &structuring->contentDispMain,
1664                        GPGMEPLUG_ENCSIGN_CDISP_MAIN );
1665       storeNewCharPtr( &structuring->contentTEncMain,
1666                        GPGMEPLUG_ENCSIGN_CTENC_MAIN );
1667       if( structuring->makeMultiMime ) {
1668         storeNewCharPtr( &structuring->contentTypeVersion,
1669                          GPGMEPLUG_ENCSIGN_CTYPE_VERSION );
1670         storeNewCharPtr( &structuring->contentDispVersion,
1671                          GPGMEPLUG_ENCSIGN_CDISP_VERSION );
1672         storeNewCharPtr( &structuring->contentTEncVersion,
1673                          GPGMEPLUG_ENCSIGN_CTENC_VERSION );
1674         storeNewCharPtr( &structuring->bodyTextVersion,
1675                          GPGMEPLUG_ENCSIGN_BTEXT_VERSION );
1676         storeNewCharPtr( &structuring->contentTypeCode,
1677                          GPGMEPLUG_ENCSIGN_CTYPE_CODE );
1678         storeNewCharPtr( &structuring->contentDispCode,
1679                          GPGMEPLUG_ENCSIGN_CDISP_CODE );
1680         storeNewCharPtr( &structuring->contentTEncCode,
1681                          GPGMEPLUG_ENCSIGN_CTENC_CODE );
1682       }
1683     } else {
1684       storeNewCharPtr( &structuring->flatTextPrefix,
1685                        GPGMEPLUG_ENCSIGN_FLAT_PREFIX );
1686       storeNewCharPtr( &structuring->flatTextSeparator,
1687                        GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR );
1688       storeNewCharPtr( &structuring->flatTextPostfix,
1689                        GPGMEPLUG_ENCSIGN_FLAT_POSTFIX );
1690     }
1691   }
1692   return bOk;
1693 }
1694
1695
1696 bool decryptMessage( const char* ciphertext,
1697                      bool        cipherIsBinary,
1698                      int         cipherLen,
1699                      const char** cleartext,
1700                      const char* certificate )
1701 {
1702   GpgmeCtx ctx;
1703   GpgmeError err;
1704   GpgmeData gCiphertext, gPlaintext;
1705   size_t rCLen = 0;
1706   char*  rCiph = 0;
1707   bool bOk = false;
1708
1709   if( !ciphertext )
1710     return false;
1711
1712   err = gpgme_new (&ctx);
1713   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1714   
1715   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
1716   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
1717
1718   /*
1719   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
1720                            1+strlen( ciphertext ), 1 ); */
1721   gpgme_data_new_from_mem( &gCiphertext,
1722                            ciphertext,
1723                            cipherIsBinary
1724                            ? cipherLen
1725                            : strlen( ciphertext ),
1726                            1 );
1727
1728   gpgme_data_new( &gPlaintext );
1729
1730   gpgme_op_decrypt( ctx, gCiphertext, gPlaintext );
1731   gpgme_data_release( gCiphertext );
1732
1733   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
1734
1735   *cleartext = malloc( rCLen + 1 );
1736   if( *cleartext ) {
1737       if( rCLen ) {
1738           bOk = true;
1739           strncpy((char*)*cleartext, rCiph, rCLen );
1740       }
1741       ((char*)(*cleartext))[rCLen] = 0;
1742   }
1743
1744   free( rCiph );
1745   gpgme_release( ctx );
1746   return bOk;
1747 }
1748
1749 bool decryptAndCheckMessage( const char* ciphertext,
1750           const char** cleartext, const char* certificate,
1751           struct SignatureMetaData* sigmeta ){ return true; }
1752
1753
1754 const char* requestCertificateDialog(){ return 0; }
1755
1756 bool requestDecentralCertificate( const char* certparms, 
1757                                   char** generatedKey, int* length )
1758 {
1759     GpgmeError err;
1760     GpgmeCtx ctx;
1761     GpgmeData pub;
1762     int len;
1763
1764     err = gpgme_data_new (&pub);
1765     fprintf( stderr,  "1: gpgme returned %d\n", err );
1766     if( err != GPGME_No_Error )
1767         return false;
1768
1769     err = gpgme_new (&ctx);
1770     fprintf( stderr,  "2: gpgme returned %d\n", err );
1771     if( err != GPGME_No_Error ) {
1772         gpgme_data_release( pub );
1773         return false;
1774     }
1775
1776     gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
1777     /* Don't ASCII-armor, the MUA will use base64 encoding */
1778     /*    gpgme_set_armor (ctx, 1); */
1779     err = gpgme_op_genkey (ctx, certparms, pub, NULL );
1780     fprintf( stderr,  "3: gpgme returned %d\n", err );
1781     if( err != GPGME_No_Error ) {
1782         gpgme_data_release( pub );
1783         gpgme_release( ctx );
1784         return false;
1785     }
1786
1787     gpgme_release (ctx);
1788     *generatedKey = gpgme_data_release_and_get_mem (pub, &len);
1789     *length = len;
1790
1791     /* The buffer generatedKey contains the LEN bytes you want */
1792     // Caller is responsible for freeing
1793     return true;
1794 }
1795
1796 bool requestCentralCertificateAndPSE( const char* name,
1797           const char* email, const char* organization, const char* department,
1798           const char* ca_address ){ return true; }
1799
1800 bool createPSE(){ return true; }
1801
1802 bool registerCertificate( const char* certificate ){ return true; }
1803
1804 bool requestCertificateProlongation( const char* certificate,
1805                                      const char* ca_address ){ return true; }
1806
1807 const char* certificateChain(){ return 0; }
1808
1809 bool deleteCertificate( const char* certificate ){ return true; }
1810
1811 bool archiveCertificate( const char* certificate ){ return true; }
1812
1813
1814 const char* displayCRL(){ return 0; }
1815
1816 void updateCRL(){}
1817
1818 /*
1819  * Copyright (C) 2002 g10 Code GmbH
1820  * 
1821  *     This program is free software; you can redistribute it
1822  *     and/or modify it under the terms of the GNU General Public
1823  *     License as published by the Free Software Foundation; either
1824  *     version 2 of the License, or (at your option) any later
1825  *     version.
1826  * 
1827  *     This program is distributed in the hope that it will be
1828  *     useful, but WITHOUT ANY WARRANTY; without even the implied
1829  *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
1830  *     PURPOSE.  See the GNU General Public License for more
1831  *     details.
1832  * 
1833  *     You should have received a copy of the GNU General Public
1834  *     License along with this program; if not, write to the Free
1835  *     Software Foundation, Inc., 59 Temple Place - Suite 330,
1836  *     Boston, MA  02111, USA.
1837  */
1838
1839 /* Max number of parts in a DN */
1840 #define MAX_GPGME_IDX 20
1841
1842 /* some macros to replace ctype ones and avoid locale problems */
1843 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
1844 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
1845 #define hexdigitp(a) (digitp (a)                     \
1846                       || (*(a) >= 'A' && *(a) <= 'F')  \
1847                       || (*(a) >= 'a' && *(a) <= 'f'))
1848 /* the atoi macros assume that the buffer has only valid digits */
1849 #define atoi_1(p)   (*(p) - '0' )
1850 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
1851 #define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
1852 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
1853                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
1854 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
1855
1856 #define safe_malloc( x ) malloc( x )
1857 #define xstrdup( x ) (x)?strdup(x):0
1858
1859 static void 
1860 safe_free( void** x ) 
1861 {
1862   free( *x );
1863   *x = 0;
1864 }
1865 char *
1866 trim_trailing_spaces( char *string )
1867 {
1868     char *p, *mark;
1869
1870     for( mark = NULL, p = string; *p; p++ ) {
1871         if( isspace( *p ) ) {
1872             if( !mark )
1873                 mark = p;
1874         }
1875         else
1876             mark = NULL;
1877     }
1878     if( mark )
1879         *mark = '\0' ;
1880
1881     return string ;
1882 }
1883 /*#define safe_free( x ) free( x )*/
1884
1885 /* Parse a DN and return an array-ized one.  This is not a validating
1886    parser and it does not support any old-stylish syntax; gpgme is
1887    expected to return only rfc2253 compatible strings. */
1888 static const unsigned char *
1889 parse_dn_part (struct DnPair *array, const unsigned char *string)
1890 {
1891   const unsigned char *s, *s1;
1892   size_t n;
1893   unsigned char *p;
1894
1895   /* parse attributeType */
1896   for (s = string+1; *s && *s != '='; s++)
1897     ;
1898   if (!*s)
1899     return NULL; /* error */
1900   n = s - string;
1901   if (!n)
1902     return NULL; /* empty key */
1903   array->key = p = safe_malloc (n+1);
1904   
1905   
1906   memcpy (p, string, n);
1907   p[n] = 0;
1908   trim_trailing_spaces (p);
1909   if ( !strcmp (p, "1.2.840.113549.1.9.1") )
1910     strcpy (p, "EMail");
1911   string = s + 1;
1912
1913   if (*string == '#')
1914     { /* hexstring */
1915       string++;
1916       for (s=string; hexdigitp (s); s++)
1917         s++;
1918       n = s - string;
1919       if (!n || (n & 1))
1920         return NULL; /* empty or odd number of digits */
1921       n /= 2;
1922       array->value = p = safe_malloc (n+1);
1923       
1924       
1925       for (s1=string; n; s1 += 2, n--)
1926         *p++ = xtoi_2 (s1);
1927       *p = 0;
1928    }
1929   else
1930     { /* regular v3 quoted string */
1931       for (n=0, s=string; *s; s++)
1932         {
1933           if (*s == '\\')
1934             { /* pair */
1935               s++;
1936               if (*s == ',' || *s == '=' || *s == '+'
1937                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
1938                   || *s == '\\' || *s == '\"' || *s == ' ')
1939                 n++;
1940               else if (hexdigitp (s) && hexdigitp (s+1))
1941                 {
1942                   s++;
1943                   n++;
1944                 }
1945               else
1946                 return NULL; /* invalid escape sequence */
1947             }
1948           else if (*s == '\"')
1949             return NULL; /* invalid encoding */
1950           else if (*s == ',' || *s == '=' || *s == '+'
1951                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
1952             break; 
1953           else
1954             n++;
1955         }
1956
1957       array->value = p = safe_malloc (n+1);
1958       
1959       
1960       for (s=string; n; s++, n--)
1961         {
1962           if (*s == '\\')
1963             { 
1964               s++;
1965               if (hexdigitp (s))
1966                 {
1967                   *p++ = xtoi_2 (s);
1968                   s++;
1969                 }
1970               else
1971                 *p++ = *s;
1972             }
1973           else
1974             *p++ = *s;
1975         }
1976       *p = 0;
1977     }
1978   return s;
1979 }
1980
1981
1982 /* Parse a DN and return an array-ized one.  This is not a validating
1983    parser and it does not support any old-stylish syntax; gpgme is
1984    expected to return only rfc2253 compatible strings. */
1985 static struct DnPair *
1986 parse_dn (const unsigned char *string)
1987 {
1988   struct DnPair *array;
1989   size_t arrayidx, arraysize;
1990   int i;
1991
1992   arraysize = 7; /* C,ST,L,O,OU,CN,email */
1993   arrayidx = 0;
1994   array = safe_malloc ((arraysize+1) * sizeof *array);
1995   
1996   
1997   while (*string)
1998     {
1999       while (*string == ' ')
2000         string++;
2001       if (!*string)
2002         break; /* ready */
2003       if (arrayidx >= arraysize)
2004         { /* mutt lacks a real safe_realoc - so we need to copy */
2005           struct DnPair *a2;
2006
2007           arraysize += 5;
2008           a2 = safe_malloc ((arraysize+1) * sizeof *array);
2009           for (i=0; i < arrayidx; i++)
2010             {
2011               a2[i].key = array[i].key;
2012               a2[i].value = array[i].value;
2013             }
2014           safe_free ((void **)&array);
2015           array = a2;
2016         }
2017       array[arrayidx].key = NULL;
2018       array[arrayidx].value = NULL;
2019       string = parse_dn_part (array+arrayidx, string);
2020       arrayidx++;
2021       if (!string)
2022         goto failure;
2023       while (*string == ' ')
2024         string++;
2025       if (*string && *string != ',' && *string != ';' && *string != '+')
2026         goto failure; /* invalid delimiter */
2027       if (*string)
2028         string++;
2029     }
2030   array[arrayidx].key = NULL;
2031   array[arrayidx].value = NULL;
2032   return array;
2033
2034  failure:
2035   for (i=0; i < arrayidx; i++)
2036     {
2037       safe_free ((void**)&array[i].key);
2038       safe_free ((void**)&array[i].value);
2039     }
2040   safe_free ((void**)&array);
2041   return NULL;
2042 }
2043
2044 static int 
2045 add_dn_part( char* result, struct DnPair* dn, const char* part )
2046 {
2047   int any = 0;
2048
2049   for(; dn->key; ++dn ) {
2050     if( !strcmp( dn->key, part ) ) {
2051       if( any ) strcat( result, "+" );
2052       /* email hack */
2053       if( !strcmp( part, "1.2.840.113549.1.9.1" ) ) strcat( result, "EMail" );
2054       else strcat( result, part );
2055       strcat( result, "=" );
2056       strcat( result, dn->value );
2057       any = 1;
2058     }
2059   }
2060   return any;
2061 }
2062
2063 static char* 
2064 reorder_dn( struct DnPair *dn )
2065 {
2066   // note: The must parts are: CN, L, OU, O, C
2067   const char* stdpart[] = {
2068     "CN", "S", "SN", "GN", "T", "UID",
2069           "MAIL", "EMAIL", "MOBILE", "TEL", "FAX", "STREET",
2070     "L",  "PC", "SP", "ST",
2071     "OU",
2072     "O",
2073     "C",
2074     NULL
2075   };
2076   int any=0, any2=0, len=0, i;
2077   char* result;
2078   for( i = 0; dn[i].key; ++i ) {
2079     len += strlen( dn[i].key );
2080     len += strlen( dn[i].value );
2081     len += 4; /* ',' and '=', and possibly "(" and ")" */
2082   }
2083   result = (char*)safe_malloc( (len+1)*sizeof(char) );
2084   *result = 0;
2085
2086   /* add standard parts */
2087   for( i = 0; stdpart[i]; ++i ) {
2088     if( any ) {
2089       strcat( result, "," );
2090     }
2091     any = add_dn_part( result, dn, stdpart[i] );
2092   }
2093
2094   /* add remaining parts in no particular order */
2095   for(; dn->key; ++dn ) {
2096     for( i = 0; stdpart[i]; ++i ) {
2097       if( !strcmp( dn->key, stdpart[i] ) ) {
2098         break;
2099       }
2100     }
2101     if( !stdpart[i] ) {
2102       if( any ) strcat( result, "," );
2103       if( !any2 ) strcat( result, "(");
2104       any = add_dn_part( result, dn, dn->key );
2105       any2 = 1;
2106     }
2107   }
2108   if( any2 ) strcat( result, ")");
2109   return result;
2110 }
2111
2112 struct CertIterator {
2113   GpgmeCtx ctx;  
2114   struct CertificateInfo info;
2115 };
2116
2117 struct CertIterator* 
2118 startListCertificates( const char* pattern, int remote )
2119 {
2120     GpgmeError err;
2121     struct CertIterator* it;
2122     /*fprintf( stderr,  "startListCertificates()" );*/
2123
2124     it = (struct CertIterator*)safe_malloc( sizeof( struct CertIterator ) );
2125
2126     err = gpgme_new (&(it->ctx));
2127     /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2128     if( err != GPGME_No_Error ) {
2129       free( it );
2130       return NULL;
2131     }
2132
2133     gpgme_set_protocol (it->ctx, GPGME_PROTOCOL_CMS);
2134     if( remote ) gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_EXTERN ); 
2135     else gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_LOCAL );
2136     err =  gpgme_op_keylist_start ( it->ctx, pattern, 0);
2137     if( err != GPGME_No_Error ) {
2138       endListCertificates( it );
2139       return NULL;
2140     }
2141     memset( &(it->info), 0, sizeof( struct CertificateInfo ) );
2142     return it;
2143 }
2144
2145 /* free() each string in a char*[] and the array itself */
2146 static void 
2147 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 
2160 freeInfo( struct CertificateInfo* info )
2161 {
2162   struct DnPair* a = info->dnarray;
2163   assert( info );
2164   if( info->userid ) freeStringArray( info->userid );
2165   if( info->serial ) safe_free( (void**)&(info->serial) );
2166   if( info->fingerprint ) safe_free( (void**)&(info->fingerprint) );
2167   if( info->issuer ) safe_free( (void**)&(info->issuer) );
2168   if( info->chainid ) safe_free( (void**)&(info->chainid) );
2169   if( info->caps ) safe_free( (void**)&(info->caps) );
2170   while( a && a->key && a->value ) {
2171     safe_free ((void**)&(a->key));
2172     safe_free ((void**)&(a->value));
2173     ++a;
2174   }
2175   if( info->dnarray ) safe_free ((void**)&(info->dnarray));
2176   memset( info, 0, sizeof( *info ) );
2177 }
2178
2179 /* Format the fingerprint nicely. The caller should
2180    free the returned value with safe_free() */
2181 static char* make_fingerprint( const char* fpr )
2182 {
2183   int len = strlen(fpr);
2184   int i = 0;
2185   char* result = safe_malloc( (len + len/2 + 1)*sizeof(char) );
2186   if( !result ) return NULL;
2187   for(; *fpr; ++fpr, ++i ) {
2188     if( i%3 == 2) {
2189       result[i] = ':'; ++i;
2190     }
2191     result[i] = *fpr;
2192   }
2193   result[i] = 0;
2194   return result;
2195 }
2196
2197 int 
2198 nextCertificate( struct CertIterator* it, struct CertificateInfo** result )
2199 {
2200   GpgmeError err;
2201   GpgmeKey   key;
2202   int retval = GPGME_No_Error;
2203   assert( it );
2204   err = gpgme_op_keylist_next ( it->ctx, &key);
2205   if( err != GPGME_EOF ) {   
2206     int idx;
2207     const char* s;
2208     unsigned long u;
2209     char* names[MAX_GPGME_IDX+1];
2210     struct DnPair *issuer_dn, *tmp_dn;
2211     retval = err;
2212     memset( names, 0, sizeof( names ) );
2213     freeInfo( &(it->info) );
2214
2215     for( idx = 0; (s = gpgme_key_get_string_attr (key, GPGME_ATTR_USERID, 0, idx)) && idx < MAX_GPGME_IDX; 
2216          ++idx ) {
2217       names[idx] = xstrdup( s );
2218     }
2219     
2220     it->info.userid = safe_malloc( sizeof( char* ) * (idx+1) );
2221     memset( it->info.userid, 0, sizeof( char* ) * (idx+1) );
2222     it->info.dnarray = 0;
2223     for( idx = 0; names[idx] != 0; ++idx ) {
2224       struct DnPair* a = parse_dn( names[idx] ); 
2225       if( idx == 0 ) {
2226         it->info.userid[idx] = reorder_dn( a );
2227         it->info.dnarray = a;
2228         safe_free( (void **)&(names[idx]) );
2229       } else {
2230         it->info.userid[idx] = names[idx];
2231       }
2232     }
2233     it->info.userid[idx] = 0;
2234
2235     s = gpgme_key_get_string_attr (key, GPGME_ATTR_SERIAL, 0, 0); 
2236     it->info.serial = xstrdup(s);
2237
2238     s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, 0, 0); 
2239     it->info.fingerprint = make_fingerprint( s );
2240
2241     s = gpgme_key_get_string_attr (key, GPGME_ATTR_ISSUER, 0, 0); 
2242     if( s ) {
2243       issuer_dn = tmp_dn = parse_dn( s );     
2244       /*it->info.issuer = xstrdup(s);*/
2245       it->info.issuer = reorder_dn( issuer_dn );
2246       while( tmp_dn->key ) {
2247         safe_free( (void**)&issuer_dn->key );
2248         safe_free( (void**)&issuer_dn->value );
2249         ++tmp_dn;
2250       }
2251       safe_free( (void**)&issuer_dn );
2252     } else {
2253       it->info.issuer = NULL;
2254     }
2255     s = gpgme_key_get_string_attr (key, GPGME_ATTR_CHAINID, 0, 0); 
2256     it->info.chainid = xstrdup(s);
2257
2258     s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEY_CAPS, 0, 0); 
2259     it->info.caps = xstrdup(s);
2260
2261     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_CREATED, 0, 0); 
2262     it->info.created = u;
2263
2264     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_EXPIRE, 0, 0); 
2265     it->info.expire = u;
2266
2267     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_IS_SECRET, 0, 0); 
2268     it->info.secret = u;
2269
2270     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_UID_INVALID, 0, 0); 
2271     it->info.invalid = u;
2272
2273     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_EXPIRED, 0, 0); 
2274     it->info.expired = u;
2275
2276     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_DISABLED, 0, 0); 
2277     it->info.disabled = u;
2278
2279     gpgme_key_release (key);
2280     /*return &(it->info);*/
2281     *result =  &(it->info);
2282   } else *result = NULL;
2283   return retval;
2284 }
2285
2286 void 
2287 endListCertificates( struct CertIterator* it )
2288 {
2289   /*fprintf( stderr,  "endListCertificates()\n" );*/
2290   assert(it);
2291   freeInfo( &(it->info) );
2292   gpgme_op_keylist_end(it->ctx);
2293   gpgme_release (it->ctx);
2294   free( it );
2295 }
2296
2297 int
2298 importCertificate( const char* fingerprint )
2299 {
2300   GpgmeError err;
2301   GpgmeCtx  ctx;
2302   GpgmeData keydata;
2303   GpgmeRecipients recips;
2304   /*
2305   char* buf;
2306   char* tmp1;
2307   char* tmp2;
2308   */
2309   err = gpgme_new( &ctx );
2310   /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2311   if( err != GPGME_No_Error ) {
2312     return err;
2313   }
2314
2315   err = gpgme_data_new( &keydata );
2316   if( err ) {
2317     fprintf( stderr,  "gpgme_data_new returned %d\n", err );
2318     gpgme_release( ctx );
2319     return err;
2320   }
2321
2322   err = gpgme_recipients_new( &recips );
2323   if( err ) {
2324     fprintf( stderr,  "gpgme_recipients_new returned %d\n", err );
2325     gpgme_data_release( keydata );
2326     gpgme_release( ctx );
2327     return err;
2328   }
2329   
2330   /*
2331   buf = safe_malloc( sizeof(char)*( strlen( fingerprint ) + 1 ) );
2332   if( !buf ) {
2333     gpgme_recipients_release( recips );
2334     gpgme_data_release( keydata );    
2335     gpgme_release( ctx );
2336     return GPGME_Out_Of_Core;
2337   }
2338   tmp1 = fingerprint;
2339   tmp2 = buf;
2340   while( *tmp1 ) {
2341     if( *tmp1 != ':' ) *tmp2++ = *tmp1;
2342     tmp1++;
2343   }
2344   *tmp2 = 0;
2345   fprintf( stderr,  "calling gpgme_recipients_add_name( %s )\n", buf );  
2346   */
2347
2348   err = gpgme_recipients_add_name( recips, fingerprint ); 
2349   if( err ) {
2350     fprintf( stderr,  "gpgme_recipients_add_name returned %d\n", err );
2351     /*safe_free( (void**)&buf );*/
2352     gpgme_recipients_release( recips );
2353     gpgme_data_release( keydata );    
2354     gpgme_release( ctx );
2355     return err;
2356   }
2357
2358   err = gpgme_op_export( ctx, recips, keydata );
2359   if( err ) {
2360     fprintf( stderr,  "gpgme_op_export returned %d\n", err );
2361     /*safe_free( (void**)&buf );*/
2362     gpgme_recipients_release( recips );
2363     gpgme_data_release( keydata );    
2364     gpgme_release( ctx );
2365     return err;
2366   }
2367   /*safe_free( (void**)&buf );*/
2368
2369   err = gpgme_op_import( ctx, keydata );
2370   if( err ) {    
2371     fprintf( stderr,  "gpgme_op_import returned %d\n", err );
2372     gpgme_recipients_release( recips );
2373     gpgme_data_release( keydata );    
2374     gpgme_release( ctx );
2375     return err;
2376   }
2377
2378   gpgme_recipients_release( recips );
2379   gpgme_data_release( keydata );    
2380   gpgme_release( ctx );
2381   return 0;
2382 }
2383
2384     // // // // // // // // // // // // // // // // // // // // // // // // //
2385    //                                                                      //
2386   //         Continuation of CryptPlug code                               //
2387  //                                                                      //
2388 // // // // // // // // // // // // // // // // // // // // // // // // //
2389
2390
2391 /*
2392   Find all certificate for a given addressee and return them in a
2393   '\1' separated list.
2394   NOTE: The certificate parameter must point to an allready allocated
2395   block of memory which is large enough to hold the complete list.
2396   If secretOnly is true, only secret keys are returned.
2397 */
2398 bool findCertificates( const char* addressee, char** certificates, bool secretOnly )
2399 {
2400   GpgmeCtx ctx;
2401   GpgmeError err;
2402   GpgmeKey rKey;
2403   const char *s;
2404   const char *s2;
2405   char* dn;
2406   struct DnPair* a;
2407   int nFound = 0;
2408
2409   strcpy( *certificates, "" );
2410
2411   gpgme_new (&ctx);
2412   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
2413
2414   err = gpgme_op_keylist_start(ctx, addressee, secretOnly ? 1 : 0);
2415   while( GPGME_No_Error == err ) {
2416     err = gpgme_op_keylist_next(ctx, &rKey);
2417     if( GPGME_No_Error == err ) {
2418       s = gpgme_key_get_string_attr (rKey, GPGME_ATTR_USERID, NULL, 0);
2419       if( s ) {
2420         s2 = gpgme_key_get_string_attr (rKey, GPGME_ATTR_FPR, NULL, 0);
2421         if( s2 ) {
2422           if( nFound )
2423             strcat(*certificates,"\1" );
2424           dn = xstrdup( s );
2425 /*fprintf( stderr, "\n\n\nDN before reordering: \"%s\"\n", dn );*/
2426           a = parse_dn( dn ); 
2427           dn = reorder_dn( a );
2428 /*fprintf( stderr, "\nDN after reordering: \"%s\"\n", dn );*/
2429           strcat( *certificates, s );
2430           strcat( *certificates, "    (" );
2431           strcat( *certificates, s2 );
2432           strcat( *certificates, ")" );
2433           safe_free( (void **)&dn );
2434           ++nFound;
2435         }
2436       }
2437     }
2438   }
2439   gpgme_op_keylist_end( ctx );
2440   gpgme_release (ctx);
2441
2442   return ( 0 < nFound );
2443 }