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