Make the signatureCertificateDaysLeftToExpiry() work as expected.
[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   GpgmeCtx ctx;
500   GpgmeError err;
501   GpgmeKey rKey;
502   time_t daysLeft = 0;
503
504   gpgme_new( &ctx );
505   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
506
507   err = gpgme_op_keylist_start( ctx, certificate, 0 );
508   if ( GPGME_No_Error == err ) {
509     err = gpgme_op_keylist_next( ctx, &rKey );
510     gpgme_op_keylist_end( ctx );
511     if ( GPGME_No_Error == err ) {
512       time_t expire_time = gpgme_key_get_ulong_attr(
513                              rKey,GPGME_ATTR_EXPIRE, NULL, 0 );
514       time_t cur_time = time (NULL);
515       daysLeft = expire_time - cur_time;
516       // convert seconds into days
517       daysLeft /= 43200;
518       gpgme_key_release( rKey );
519     }
520   }
521   gpgme_release( ctx );
522     
523   /* 
524   fprintf( stderr, "gpgmeplug signatureCertificateDaysLeftToExpiry returned %d\n", daysLeft );
525   */
526
527   return daysLeft;
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   /*
559   GpgmeCtx ctx;
560   GpgmeError err;
561   GpgmeKey rKey;
562   time_t daysLeft = 0;
563
564   gpgme_new( &ctx );
565   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
566
567   err = gpgme_op_keylist_start( ctx, certificate, 0 );
568   if ( GPGME_No_Error == err ) {
569     err = gpgme_op_keylist_next( ctx, &rKey );
570     gpgme_op_keylist_end( ctx );
571     if ( GPGME_No_Error == err ) {
572       time_t expire_time = gpgme_key_get_ulong_attr(
573                              rKey,
574                              
575 ??????????????????????? GPGME_ATTR_EXPIRE,  ???????????????????????
576                              
577                              NULL, 0 );
578       time_t cur_time = time (NULL);
579       daysLeft = expire_time - cur_time;
580       // convert seconds into days
581       daysLeft /= 43200;
582       gpgme_key_release( rKey );
583     }
584   }
585   gpgme_release( ctx );
586     
587    
588   // fprintf( stderr, "gpgmeplug caCertificateDaysLeftToExpiry returned %d\n", daysLeft );
589   return daysLeft;
590   */
591   
592   return 10; /* dummy that triggers a warning in the MUA */
593 }
594
595 void setCACertificateExpiryNearInterval( int interval )
596 {
597   config.cACertificateExpiryNearInterval = interval;
598 }
599
600 int caCertificateExpiryNearInterval( void )
601 {
602   return config.cACertificateExpiryNearInterval;
603 }
604
605 void setRootCertificateExpiryNearWarning( bool flag )
606 {
607   config.rootCertificateExpiryNearWarning = flag;
608 }
609
610 bool rootCertificateExpiryNearWarning( void )
611 {
612   return config.rootCertificateExpiryNearWarning;
613 }
614
615 int rootCertificateDaysLeftToExpiry( const char* certificate )
616 {
617     /* PENDING(g10)
618        Please return the number of days that are left until the
619        root certificate for the certificate specified in the parameter
620        certificate expires.
621     */
622   /*
623   GpgmeCtx ctx;
624   GpgmeError err;
625   GpgmeKey rKey;
626   time_t daysLeft = 0;
627
628   gpgme_new( &ctx );
629   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
630
631   err = gpgme_op_keylist_start( ctx, certificate, 0 );
632   if ( GPGME_No_Error == err ) {
633     err = gpgme_op_keylist_next( ctx, &rKey );
634     gpgme_op_keylist_end( ctx );
635     if ( GPGME_No_Error == err ) {
636       time_t expire_time = gpgme_key_get_ulong_attr(
637                              rKey,
638                              
639 ??????????????????????? GPGME_ATTR_EXPIRE,  ???????????????????????
640                              
641                              NULL, 0 );
642       time_t cur_time = time (NULL);
643       daysLeft = expire_time - cur_time;
644       // convert seconds into days
645       daysLeft /= 43200;
646       gpgme_key_release( rKey );
647     }
648   }
649   gpgme_release( ctx );
650     
651    
652   // fprintf( stderr, "gpgmeplug rootCertificateDaysLeftToExpiry returned %d\n", daysLeft );
653   return daysLeft;
654   */
655   
656   return 10; /* dummy that triggers a warning in the MUA */
657 }
658
659
660 void setRootCertificateExpiryNearInterval( int interval )
661 {
662   config.rootCertificateExpiryNearInterval = interval;
663 }
664
665 int rootCertificateExpiryNearInterval( void )
666 {
667   return config.rootCertificateExpiryNearInterval;
668 }
669
670
671
672
673
674
675
676
677 const char* encryptionConfigurationDialog(){ return 0; }
678
679 const char* encryptionAlgorithmDialog(){ return 0; }
680
681 const char* encryptionHandlingDialog(){ return 0; }
682
683 const char* encryptionReceiverDialog(){ return 0; }
684
685 void setEncryptionAlgorithm( EncryptionAlgorithm cryptAlg )
686 {
687   config.encryptionAlgorithm = cryptAlg;
688 }
689
690 EncryptionAlgorithm encryptionAlgorithm()
691 {
692   return config.encryptionAlgorithm;
693 }
694
695 void setEncryptEmail( EncryptEmail cryptMode )
696 {
697   config.encryptEmail = cryptMode;
698 }
699
700 EncryptEmail encryptEmail()
701 {
702   return config.encryptEmail;
703 }
704
705
706
707
708
709
710 void setWarnSendUnencrypted( bool flag )
711 {
712   config.warnSendUnencrypted = flag;
713 }
714
715 bool warnSendUnencrypted()
716 {
717   return config.warnSendUnencrypted;
718 }
719
720
721
722
723
724
725
726
727
728 void setSaveMessagesEncrypted( bool flag )
729 {
730   config.saveMessagesEncrypted = flag;
731 }
732
733 bool saveMessagesEncrypted()
734 {
735   return config.saveMessagesEncrypted;
736 }
737
738
739
740
741
742
743
744 void setCheckCertificatePath( bool flag )
745 {
746   config.checkCertificatePath = flag;
747 }
748
749 bool checkCertificatePath()
750 {
751   return config.checkCertificatePath;
752 }
753
754
755
756
757
758
759
760
761 void setCheckEncryptionCertificatePathToRoot( bool flag )
762 {
763   config.checkEncryptionCertificatePathToRoot = flag;
764 }
765
766 bool checkEncryptionCertificatePathToRoot()
767 {
768   return config.checkEncryptionCertificatePathToRoot;
769 }
770
771
772
773
774
775
776
777 void setReceiverCertificateExpiryNearWarning( bool flag )
778 {
779   config.receiverCertificateExpiryNearWarning = flag;
780 }
781
782 bool receiverCertificateExpiryNearWarning()
783 {
784   return config.receiverCertificateExpiryNearWarning;
785 }
786
787
788 int receiverCertificateDaysLeftToExpiry( const char* certificate )
789 {
790     /* PENDING(g10)
791        Please return the number of days that are left until the
792        certificate specified in the parameter certificate expires.
793     */
794   return 10; /* dummy that triggers a warning in the MUA */
795 }
796
797
798 void setReceiverCertificateExpiryNearWarningInterval( int interval )
799 {
800   config.receiverCertificateExpiryNearWarningInterval = interval;
801 }
802
803 int receiverCertificateExpiryNearWarningInterval()
804 {
805   return config.receiverCertificateExpiryNearWarningInterval;
806 }
807
808 void setCertificateInChainExpiryNearWarning( bool flag )
809 {
810   config.certificateInChainExpiryNearWarning = flag;
811 }
812
813 bool certificateInChainExpiryNearWarning()
814 {
815   return config.certificateInChainExpiryNearWarning;
816 }
817
818
819 int certificateInChainDaysLeftToExpiry( const char* certificate )
820 {
821     /* PENDING(g10)
822        Please return the number of days that are left until the
823        the first certificate in the chain of the specified certificate
824        expires.
825     */
826   return 10; /* dummy that triggers a warning in the MUA */
827 }
828
829
830 void setCertificateInChainExpiryNearWarningInterval( int interval )
831 {
832   config.certificateInChainExpiryNearWarningInterval = interval;
833 }
834
835 int certificateInChainExpiryNearWarningInterval()
836 {
837   return config.certificateInChainExpiryNearWarningInterval;
838 }
839
840 void setReceiverEmailAddressNotInCertificateWarning( bool flag )
841 {
842   config.receiverEmailAddressNotInCertificateWarning = flag;
843 }
844
845 bool receiverEmailAddressNotInCertificateWarning()
846 {
847   return config.receiverEmailAddressNotInCertificateWarning;
848 }
849
850
851
852
853
854
855
856
857 void setEncryptionUseCRLs( bool flag )
858 {
859   config.encryptionUseCRLs = flag;
860
861   /* PENDING(g10) Store this setting in gpgme and use it. If true,
862      every certificate used for encryption should be checked against
863      applicable CRLs.
864   */
865 }
866
867 bool encryptionUseCRLs()
868 {
869   return config.encryptionUseCRLs;
870 }
871
872
873 int encryptionCRLsDaysLeftToExpiry()
874 {
875     /* PENDING(g10)
876        Please return the number of days that are left until the
877        CRL used for encryption expires.
878     */
879   return 10; /* dummy that triggers a warning in the MUA */
880 }
881
882 void setEncryptionCRLExpiryNearWarning( bool flag )
883 {
884   config.encryptionCRLExpiryNearWarning = flag;
885 }
886
887 bool encryptionCRLExpiryNearWarning()
888 {
889   return config.encryptionCRLExpiryNearWarning;
890 }
891
892 void setEncryptionCRLNearExpiryInterval( int interval )
893 {
894   config.encryptionCRLNearExpiryInterval = interval;
895 }
896
897 int encryptionCRLNearExpiryInterval()
898 {
899   return config.encryptionCRLNearExpiryInterval;
900 }
901
902
903 const char* directoryServiceConfigurationDialog(){ return 0; }
904
905 void appendDirectoryServer( const char* servername,
906                             int         port,
907                             const char* description )
908 {
909   struct DirectoryServer *newServers = NULL;
910   newServers = realloc( config.directoryServers,
911                         (1+config.numDirectoryServers) * sizeof *newServers );
912   if( newServers ) {
913     config.directoryServers = newServers;
914     newServers[ config.numDirectoryServers ].servername =
915       malloc( 1+strlen( servername ) );
916     if( newServers[ config.numDirectoryServers ].servername ) {
917       strcpy( (char *)newServers[ config.numDirectoryServers ].servername,
918         servername );
919       newServers[ config.numDirectoryServers ].description =
920         malloc( 1+strlen(  description ) );
921       if( newServers[ config.numDirectoryServers ].description ) {
922         strcpy( (char *)newServers[ config.numDirectoryServers ].description,
923           description );
924         newServers[ config.numDirectoryServers ].port = port;
925         config.numDirectoryServers += 1;
926       }
927     }
928   }
929 }
930
931 void setDirectoryServers( struct DirectoryServer server[], unsigned int size )
932 {
933   unsigned int i;
934   int oldSize = config.numDirectoryServers;
935   struct DirectoryServer *newServers = NULL;
936   newServers = calloc ( size, sizeof *newServers );
937   if( newServers ) {
938     for( i=0; i < oldSize; ++i ) {
939       free( (char *)config.directoryServers[i].servername );
940       free( (char *)config.directoryServers[i].description );
941     }
942     free( config.directoryServers );
943     for( i=0; i < size; ++i ) {
944       newServers[ i ].servername = malloc( 1+strlen( server[i].servername ) );
945       if( newServers[ i ].servername ) {
946         strcpy( (char *)newServers[ i ].servername, server[i].servername );
947         newServers[ i ].description = malloc( 1+strlen( server[i].description ) );
948         if( newServers[ i ].description ) {
949           strcpy( (char *)newServers[ i ].description, server[i].description );
950           newServers[ i ].port = server[i].port;
951         }
952       }
953     }
954     config.directoryServers = newServers;
955     config.numDirectoryServers = size;
956   }
957 }
958
959 struct DirectoryServer * directoryServers( int* numServers )
960 {
961   if( numServers )
962     *numServers = config.numDirectoryServers;
963   return config.directoryServers;
964 };
965
966 void setCertificateSource( CertificateSource source )
967 {
968   config.certificateSource = source;
969 }
970
971 CertificateSource certificateSource()
972 {
973   return config.certificateSource;
974 }
975
976 void setCRLSource( CertificateSource source )
977 {
978   config.cRLSource = source;
979 }
980
981 CertificateSource crlSource()
982 {
983   return config.cRLSource;
984 }
985
986
987 bool certificateValidity( const char* certificate,
988                           int* level ){ return true; }
989
990
991 void storeNewCharPtr( char** dest, const char* src )
992 {
993   int sLen = strlen( src );
994   *dest = malloc( sLen + 1 );
995   strcpy( *dest, src );
996   (*dest)[sLen] = '\0';
997 }
998
999
1000 bool signMessage( const char*  cleartext,
1001                   char** ciphertext,
1002                   const size_t* cipherLen,
1003                   const char*  certificate,
1004                   struct StructuringInfo* structuring,
1005                   int* errId,
1006                   char** errTxt )
1007 {
1008   bool bIsOpaque;
1009   GpgmeCtx ctx;
1010   GpgmeError err;
1011   GpgmeKey rKey;
1012   GpgmeData data,  sig;
1013   char* rSig  = 0;
1014   bool  bOk   = false;
1015   int sendCerts = 1;
1016
1017   init_StructuringInfo( structuring );
1018
1019   if( !ciphertext )
1020     return false;
1021
1022   err = gpgme_new (&ctx);
1023   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1024
1025   gpgme_set_armor (ctx, __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ? 0 : 1);
1026   /*  gpgme_set_textmode (ctx, 1); */
1027
1028   switch ( config.sendCertificates ) {
1029     case SendCert_undef:
1030       break;
1031     case SendCert_DontSend:
1032       sendCerts = 0;
1033       break;
1034     case SendCert_SendOwn:
1035       sendCerts = 1;
1036       break;
1037     case SendCert_SendChainWithoutRoot:
1038       sendCerts = -2;
1039       break;
1040     case SendCert_SendChainWithRoot:
1041       sendCerts = -1;
1042       break;
1043     default:
1044       sendCerts = 0;
1045       break;
1046   }
1047   gpgme_set_include_certs (ctx, sendCerts);
1048
1049   /* select the signer's key if provided */
1050   if (certificate != 0) {
1051       err = gpgme_op_keylist_start(ctx, certificate, 0);
1052       if (err == GPGME_No_Error) {
1053           /* we only support one signer for now */
1054           err = gpgme_op_keylist_next(ctx, &rKey);
1055           if (err == GPGME_No_Error) {
1056               /* clear existing signers */
1057               gpgme_signers_clear(ctx);
1058               /* set the signing key */
1059               gpgme_signers_add(ctx, rKey);
1060           }
1061           gpgme_op_keylist_end(ctx);
1062       }
1063   }
1064
1065   /* PENDING(g10) Implement this
1066
1067      gpgme_set_signature_algorithm( ctx, config.signatureAlgorithm )
1068      --> This does not make sense.  The algorithm is a property of
1069      the certificate used [wk 2002-03-23] */
1070
1071   gpgme_data_new_from_mem (&data, cleartext,
1072                             strlen( cleartext ), 1 );
1073   gpgme_data_new ( &sig );
1074
1075   // NOTE: Currently we support Opaque signed messages only for S/MIME,
1076   //       but not for OpenPGP mode!
1077   if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
1078     bIsOpaque = (SignatureCompoundMode_Opaque == signatureCompoundMode());
1079   else
1080     bIsOpaque = false;
1081
1082   err = gpgme_op_sign ( ctx,
1083                         data,
1084                         sig,
1085                         bIsOpaque
1086                         ? GPGME_SIG_MODE_NORMAL
1087                         : GPGME_SIG_MODE_DETACH );
1088
1089   if ( err == GPGME_No_Error ) {
1090     if( __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ) {
1091       *ciphertext = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen );
1092       bOk = true;
1093     }
1094     else {
1095       rSig = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen );
1096       *ciphertext = malloc( *cipherLen + 1 );
1097       if( *ciphertext ) {
1098         if( *cipherLen ) {
1099           bOk = true;
1100           strncpy((char*)*ciphertext, rSig, *cipherLen );
1101         }
1102         (*ciphertext)[*cipherLen] = '\0';
1103       }
1104       free( rSig );
1105     }
1106   }
1107   else {
1108     gpgme_data_release( sig );
1109 /*
1110 *ciphertext = malloc( 70 );
1111 strcpy((char*)*ciphertext, "xyz\nsig-dummy\nzyx" );
1112 (*ciphertext)[17] = '\0';
1113 err = 0;
1114 {
1115 */
1116     *ciphertext = 0;
1117     fprintf( stderr, "\n\n    gpgme_op_sign() returned this error code:  %i\n\n", err );
1118     if( errId )
1119       *errId = err;
1120     if( errTxt ) {
1121       const char* _errTxt = gpgme_strerror( err );
1122       *errTxt = malloc( strlen( _errTxt ) + 1 );
1123       if( *errTxt )
1124         strcpy(*errTxt, _errTxt );
1125     }
1126 /*
1127 }
1128 */
1129   }
1130   gpgme_data_release( data );
1131   gpgme_release (ctx);
1132
1133   if( bOk && structuring ) {
1134     if( bIsOpaque ) {
1135       structuring->includeCleartext = GPGMEPLUG_OPA_SIGN_INCLUDE_CLEARTEXT;
1136       structuring->makeMimeObject   = GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT;
1137       if( structuring->makeMimeObject ) {
1138         structuring->makeMultiMime  = GPGMEPLUG_OPA_SIGN_MAKE_MULTI_MIME;
1139         storeNewCharPtr( &structuring->contentTypeMain,
1140                         GPGMEPLUG_OPA_SIGN_CTYPE_MAIN );
1141         storeNewCharPtr( &structuring->contentDispMain,
1142                         GPGMEPLUG_OPA_SIGN_CDISP_MAIN );
1143         storeNewCharPtr( &structuring->contentTEncMain,
1144                         GPGMEPLUG_OPA_SIGN_CTENC_MAIN );
1145         if( structuring->makeMultiMime ) {
1146             storeNewCharPtr( &structuring->contentTypeVersion,
1147                             GPGMEPLUG_OPA_SIGN_CTYPE_VERSION );
1148             storeNewCharPtr( &structuring->contentDispVersion,
1149                             GPGMEPLUG_OPA_SIGN_CDISP_VERSION );
1150             storeNewCharPtr( &structuring->contentTEncVersion,
1151                             GPGMEPLUG_OPA_SIGN_CTENC_VERSION );
1152             storeNewCharPtr( &structuring->bodyTextVersion,
1153                             GPGMEPLUG_OPA_SIGN_BTEXT_VERSION );
1154             storeNewCharPtr( &structuring->contentTypeCode,
1155                             GPGMEPLUG_OPA_SIGN_CTYPE_CODE );
1156             storeNewCharPtr( &structuring->contentDispCode,
1157                             GPGMEPLUG_OPA_SIGN_CDISP_CODE );
1158             storeNewCharPtr( &structuring->contentTEncCode,
1159                             GPGMEPLUG_OPA_SIGN_CTENC_CODE );
1160         }
1161       } else {
1162         storeNewCharPtr( &structuring->flatTextPrefix,
1163                         GPGMEPLUG_OPA_SIGN_FLAT_PREFIX );
1164         storeNewCharPtr( &structuring->flatTextSeparator,
1165                         GPGMEPLUG_OPA_SIGN_FLAT_SEPARATOR );
1166         storeNewCharPtr( &structuring->flatTextPostfix,
1167                         GPGMEPLUG_OPA_SIGN_FLAT_POSTFIX );
1168       }
1169     } else {
1170       structuring->includeCleartext = GPGMEPLUG_DET_SIGN_INCLUDE_CLEARTEXT;
1171       structuring->makeMimeObject   = GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT;
1172       if( structuring->makeMimeObject ) {
1173         structuring->makeMultiMime  = GPGMEPLUG_DET_SIGN_MAKE_MULTI_MIME;
1174         storeNewCharPtr( &structuring->contentTypeMain,
1175                         GPGMEPLUG_DET_SIGN_CTYPE_MAIN );
1176         storeNewCharPtr( &structuring->contentDispMain,
1177                         GPGMEPLUG_DET_SIGN_CDISP_MAIN );
1178         storeNewCharPtr( &structuring->contentTEncMain,
1179                         GPGMEPLUG_DET_SIGN_CTENC_MAIN );
1180         if( structuring->makeMultiMime ) {
1181             storeNewCharPtr( &structuring->contentTypeVersion,
1182                             GPGMEPLUG_DET_SIGN_CTYPE_VERSION );
1183             storeNewCharPtr( &structuring->contentDispVersion,
1184                             GPGMEPLUG_DET_SIGN_CDISP_VERSION );
1185             storeNewCharPtr( &structuring->contentTEncVersion,
1186                             GPGMEPLUG_DET_SIGN_CTENC_VERSION );
1187             storeNewCharPtr( &structuring->bodyTextVersion,
1188                             GPGMEPLUG_DET_SIGN_BTEXT_VERSION );
1189             storeNewCharPtr( &structuring->contentTypeCode,
1190                             GPGMEPLUG_DET_SIGN_CTYPE_CODE );
1191             storeNewCharPtr( &structuring->contentDispCode,
1192                             GPGMEPLUG_DET_SIGN_CDISP_CODE );
1193             storeNewCharPtr( &structuring->contentTEncCode,
1194                             GPGMEPLUG_DET_SIGN_CTENC_CODE );
1195         }
1196       } else {
1197         storeNewCharPtr( &structuring->flatTextPrefix,
1198                         GPGMEPLUG_DET_SIGN_FLAT_PREFIX );
1199         storeNewCharPtr( &structuring->flatTextSeparator,
1200                         GPGMEPLUG_DET_SIGN_FLAT_SEPARATOR );
1201         storeNewCharPtr( &structuring->flatTextPostfix,
1202                         GPGMEPLUG_DET_SIGN_FLAT_POSTFIX );
1203       }
1204     }
1205   }
1206   return bOk;
1207 }
1208
1209
1210 static const char*
1211 sig_status_to_string( GpgmeSigStat status )
1212 {
1213   const char *result;
1214
1215   switch (status) {
1216     case GPGME_SIG_STAT_NONE:
1217       result = "Oops: Signature not verified";
1218       break;
1219     case GPGME_SIG_STAT_NOSIG:
1220       result = "No signature found";
1221       break;
1222     case GPGME_SIG_STAT_GOOD:
1223       result = "Good signature";
1224       break;
1225     case GPGME_SIG_STAT_BAD:
1226       result = "BAD signature";
1227       break;
1228     case GPGME_SIG_STAT_NOKEY:
1229       result = "No public key to verify the signature";
1230       break;
1231     case GPGME_SIG_STAT_ERROR:
1232       result = "Error verifying the signature";
1233       break;
1234     case GPGME_SIG_STAT_DIFF:
1235       result = "Different results for signatures";
1236       break;
1237     default:
1238       result = "Error: Unknown status";
1239       break;
1240   }
1241
1242   return result;
1243 }
1244
1245
1246 bool checkMessageSignature( char** cleartext,
1247                             const char* signaturetext,
1248                             bool signatureIsBinary,
1249                             int signatureLen,
1250                             struct SignatureMetaData* sigmeta )
1251 {
1252   GpgmeCtx ctx;
1253   GpgmeSigStat status;
1254   unsigned long sumGPGME;
1255   SigStatusFlags sumPlug;
1256   GpgmeData datapart, sigpart;
1257   char* rClear = 0;
1258   size_t clearLen;
1259   GpgmeError err;
1260   GpgmeKey key;
1261   time_t created;
1262   int sig_idx = 0;
1263   const char* statusStr;
1264   const char* fpr;
1265   bool isOpaqueSigned;
1266
1267   if( !cleartext ) {
1268     if( sigmeta )
1269       storeNewCharPtr( &sigmeta->status,
1270                         __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO );
1271
1272     return false;
1273   }
1274
1275   isOpaqueSigned = !*cleartext;
1276
1277   gpgme_new( &ctx );
1278   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1279   gpgme_set_armor (ctx,    signatureIsBinary ? 0 : 1);
1280   /*  gpgme_set_textmode (ctx, signatureIsBinary ? 0 : 1); */
1281
1282   if( isOpaqueSigned )
1283     gpgme_data_new( &datapart );
1284   else
1285     gpgme_data_new_from_mem( &datapart, *cleartext,
1286                              strlen( *cleartext ), 1 );
1287
1288   gpgme_data_new_from_mem( &sigpart,
1289                            signaturetext,
1290                            signatureIsBinary
1291                            ? signatureLen
1292                            : strlen( signaturetext ),
1293                            1 );
1294
1295   gpgme_op_verify( ctx, sigpart, datapart, &status );
1296
1297   if( isOpaqueSigned ) {
1298     rClear = gpgme_data_release_and_get_mem( datapart, &clearLen );
1299     *cleartext = malloc( clearLen + 1 );
1300     if( *cleartext ) {
1301       if( clearLen )
1302         strncpy(*cleartext, rClear, clearLen );
1303       (*cleartext)[clearLen] = '\0';
1304     }
1305     free( rClear );
1306   }
1307   else
1308     gpgme_data_release( datapart );
1309
1310   gpgme_data_release( sigpart );
1311
1312   /* Provide information in the sigmeta struct */
1313   /* the status string */
1314   statusStr = sig_status_to_string( status );
1315   sigmeta->status = malloc( strlen( statusStr ) + 1 );
1316   if( sigmeta->status ) {
1317     strcpy( sigmeta->status, statusStr );
1318     sigmeta->status[strlen( statusStr )] = '\0';
1319   } else
1320     ; /* nothing to do, is already 0 */
1321
1322   /* Extended information for any number of signatures. */
1323   fpr = gpgme_get_sig_status( ctx, sig_idx, &status, &created );
1324   sigmeta->extended_info = 0;
1325   while( fpr != NULL ) {
1326     struct tm* ctime_val;
1327     const char* sig_status;
1328
1329     void* realloc_return = realloc( sigmeta->extended_info,
1330                                     sizeof( struct SignatureMetaDataExtendedInfo ) * ( sig_idx + 1 ) );
1331     if( realloc_return ) {
1332       sigmeta->extended_info = realloc_return;
1333
1334       /* clear the data area */
1335       memset( &sigmeta->extended_info[sig_idx], 0, sizeof (struct SignatureMetaDataExtendedInfo) );
1336
1337       /* the creation time */
1338       sigmeta->extended_info[sig_idx].creation_time = malloc( sizeof( struct tm ) );
1339       if( sigmeta->extended_info[sig_idx].creation_time ) {
1340         ctime_val = localtime( &created );
1341         memcpy( sigmeta->extended_info[sig_idx].creation_time,
1342                 ctime_val, sizeof( struct tm ) );
1343       }
1344
1345       /* the extended signature verification status */
1346       sumGPGME = gpgme_get_sig_ulong_attr( ctx,
1347                                            sig_idx,
1348                                            GPGME_ATTR_SIG_SUMMARY,
1349                                            0 );
1350       // translate GPGME status flags to common CryptPlug status flags
1351       sumPlug = 0;
1352       if( sumGPGME & GPGME_SIGSUM_VALID       ) sumPlug |= SigStat_VALID      ;
1353       if( sumGPGME & GPGME_SIGSUM_GREEN       ) sumPlug |= SigStat_GREEN      ;
1354       if( sumGPGME & GPGME_SIGSUM_RED         ) sumPlug |= SigStat_RED        ;
1355       if( sumGPGME & GPGME_SIGSUM_KEY_REVOKED ) sumPlug |= SigStat_KEY_REVOKED;
1356       if( sumGPGME & GPGME_SIGSUM_KEY_EXPIRED ) sumPlug |= SigStat_KEY_EXPIRED;
1357       if( sumGPGME & GPGME_SIGSUM_SIG_EXPIRED ) sumPlug |= SigStat_SIG_EXPIRED;
1358       if( sumGPGME & GPGME_SIGSUM_KEY_MISSING ) sumPlug |= SigStat_KEY_MISSING;
1359       if( sumGPGME & GPGME_SIGSUM_CRL_MISSING ) sumPlug |= SigStat_CRL_MISSING;
1360       if( sumGPGME & GPGME_SIGSUM_CRL_TOO_OLD ) sumPlug |= SigStat_CRL_TOO_OLD;
1361       if( sumGPGME & GPGME_SIGSUM_BAD_POLICY  ) sumPlug |= SigStat_BAD_POLICY ;
1362       if( sumGPGME & GPGME_SIGSUM_SYS_ERROR   ) sumPlug |= SigStat_SYS_ERROR  ;
1363       if( !sumPlug )
1364         sumPlug = SigStat_NUMERICAL_CODE | sumGPGME;
1365       sigmeta->extended_info[sig_idx].sigStatusFlags = sumPlug;
1366
1367       sigmeta->extended_info[sig_idx].validity = GPGME_VALIDITY_UNKNOWN;
1368
1369       err = gpgme_get_sig_key (ctx, sig_idx, &key);
1370
1371       if ( err == GPGME_No_Error) {
1372         const char* attr_string;
1373         unsigned long attr_ulong;
1374
1375         /* extract key identidy */
1376         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_KEYID, 0, 0);
1377         if (attr_string != 0)
1378             storeNewCharPtr( &sigmeta->extended_info[sig_idx].keyid, attr_string );
1379
1380         /* extract finger print */
1381         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_FPR, 0, 0);
1382         if (attr_string != 0)
1383             storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint,
1384                             attr_string );
1385
1386         /* algorithms useable with this key */
1387         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_ALGO, 0, 0);
1388         if (attr_string != 0)
1389             storeNewCharPtr( &sigmeta->extended_info[sig_idx].algo,
1390                             attr_string );
1391         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_ALGO, 0, 0);
1392         sigmeta->extended_info[sig_idx].algo_num = attr_ulong;
1393
1394         /* extract key validity */
1395         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_VALIDITY, 0, 0);
1396         sigmeta->extended_info[sig_idx].validity = attr_ulong;
1397
1398         /* extract user id, according to the documentation it's representable
1399         * as a number, but it seems that it also has a string representation
1400         */
1401         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_USERID, 0, 0);
1402         if (attr_string != 0)
1403             storeNewCharPtr( &sigmeta->extended_info[sig_idx].userid,
1404                             attr_string );
1405         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_USERID, 0, 0);
1406         sigmeta->extended_info[sig_idx].userid_num = attr_ulong;
1407
1408         /* extract the length */
1409         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_LEN, 0, 0);
1410         sigmeta->extended_info[sig_idx].keylen = attr_ulong;
1411
1412         /* extract the creation time of the key */
1413         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_CREATED, 0, 0);
1414         sigmeta->extended_info[sig_idx].key_created = attr_ulong;
1415
1416         /* extract the expiration time of the key */
1417         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_EXPIRE, 0, 0);
1418         sigmeta->extended_info[sig_idx].key_expires = attr_ulong;
1419
1420         /* extract user name */
1421         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_NAME, 0, 0);
1422         if (attr_string != 0)
1423             storeNewCharPtr( &sigmeta->extended_info[sig_idx].name,
1424                             attr_string );
1425
1426         /* extract email */
1427         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_EMAIL, 0, 0);
1428         if (attr_string != 0)
1429             storeNewCharPtr( &sigmeta->extended_info[sig_idx].email,
1430                             attr_string );
1431
1432         /* extract the comment */
1433         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_COMMENT, 0, 0);
1434         if (attr_string != 0)
1435             storeNewCharPtr( &sigmeta->extended_info[sig_idx].comment,
1436                             attr_string );
1437       }
1438       else
1439         storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint, fpr );
1440
1441       sig_status = sig_status_to_string( status );
1442       storeNewCharPtr( &sigmeta->extended_info[sig_idx].status_text,
1443                        sig_status );
1444
1445     } else
1446       break; /* if allocation fails once, it isn't likely to
1447                 succeed the next time either */
1448
1449     fpr = gpgme_get_sig_status (ctx, ++sig_idx, &status, &created);
1450   }
1451   sigmeta->extended_info_count = sig_idx;
1452   sigmeta->nota_xml = gpgme_get_notation( ctx );
1453   sigmeta->status_code = status;
1454
1455   gpgme_release( ctx );
1456   return ( status == GPGME_SIG_STAT_GOOD );
1457 }
1458
1459 bool storeCertificatesFromMessage(
1460         const char* ciphertext ){ return true; }
1461
1462
1463 /* returns address if address doesn't contain a <xxx> part
1464  * else it returns a new string xxx and frees address
1465  */
1466 static char* parseAddress( char* address )
1467 {
1468   char* result = address;
1469   char* i;
1470   char* j;
1471   if( !result ) return result;
1472   i = index( address, '<' );
1473   if( i ) {
1474     j = index( i+1, '>' );
1475     if( j == NULL ) j = address+strlen(address);
1476     result = malloc( j-i );
1477     strncpy( result, i+1, j-i-1 );
1478     result[j-i-1] = '\0';
1479     free( address );
1480   } else {
1481     i = address;
1482     j = i+strlen(address);
1483   }
1484   {
1485     /* remove surrounding whitespace */
1486     char* k = result+(j-i-1);
1487     char* l = result;
1488     while( isspace( *l ) ) ++l;
1489     while( isspace( *k ) ) --k;
1490     if( l != result || k != result+(j-i-1) ) {
1491       char* result2 = malloc( k-l+2 );
1492       strncpy( result2, l, k-l+1 );
1493       result2[k-l+1] = '\0';
1494       free(result);
1495       result = result2;
1496     }
1497   }
1498   return result;
1499 }
1500
1501 static char* nextAddress( const char** address )
1502 {
1503   const char *start = *address;
1504   char* result = NULL;
1505   int quote = 0;
1506   int comment = 0;
1507   int found = 0;
1508   if( *address == NULL ) return NULL;
1509   while( **address ) {
1510
1511     switch( **address ) {
1512     case '\\': /* escaped character */
1513       ++(*address);
1514       break;
1515     case '"':
1516       if( comment == 0 ) {
1517         if( quote > 0 ) --quote;
1518         else ++quote;
1519       }
1520       break;
1521     case '(': /* comment start */
1522       if( quote == 0 ) ++comment;
1523       break;
1524     case ')': /* comment end */
1525       if( quote == 0 ) --comment;
1526       break;
1527     case '\0':
1528     case '\1': /* delimiter */
1529       if( quote == 0 && comment == 0 ) {
1530         found = 1;
1531       }
1532       break;
1533     }
1534     ++(*address);
1535     if( found ) break;
1536   }
1537   if( found || **address == 0 ) {
1538     size_t len;
1539     len = *address - start;
1540     if( len > 0 ) {
1541       if( **address != 0 ) --len;
1542       result = malloc( len*sizeof(char)+1 );
1543       strncpy( result, start, len );
1544       result[len] = '\0';
1545     }
1546   }
1547   return parseAddress(result);
1548 }
1549
1550 bool encryptMessage( const char*  cleartext,
1551                      const char** ciphertext,
1552                      const size_t* cipherLen,
1553                      const char*  certificate,
1554                      struct StructuringInfo* structuring,
1555                      int* errId,
1556                      char** errTxt )
1557 {
1558   GpgmeCtx ctx;
1559   GpgmeError err;
1560   GpgmeData gCiphertext, gPlaintext;
1561   GpgmeRecipients rset;
1562   char*  rCiph = 0;
1563   bool   bOk   = false;
1564
1565   init_StructuringInfo( structuring );
1566
1567   gpgme_new (&ctx);
1568   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1569
1570   gpgme_set_armor (ctx, __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ? 0 : 1);
1571   /*  gpgme_set_textmode (ctx, 1); */
1572
1573   gpgme_data_new_from_mem (&gPlaintext, cleartext,
1574                             1+strlen( cleartext ), 1 );
1575   err = gpgme_data_new ( &gCiphertext );
1576
1577   gpgme_recipients_new (&rset);
1578
1579   /*
1580   if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
1581   {
1582     gpgme_recipients_add_name (rset,
1583       "/CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=DÃ?sseldorf,C=DE" );
1584
1585     fputs( "\nGPGSMPLUG encryptMessage() using test key of Aegypten Project\n", stderr );
1586   }
1587   else
1588   */
1589   {
1590     const char* p = certificate;
1591     char* tok;
1592     while( (tok = nextAddress( &p ) ) != 0 ) {
1593       gpgme_recipients_add_name (rset, tok );
1594       fprintf( stderr, "\nGPGMEPLUG encryptMessage() using addressee %s\n", tok );
1595       free(tok);
1596     }
1597   }
1598
1599   /* PENDING(g10) Implement this
1600      Possible values: RSA = 1, SHA1 = 2, TripleDES = 3
1601      gpgme_set_encryption_algorithm( ctx, config.encryptionAlgorithm );
1602
1603      -> Your are mixing public key and symmetric algorithms.  The
1604      latter may be configured but the sphix specifications do opnly
1605      allow 3-DES so this is not nothing we need to do.  The proper way
1606      to select the symmetric algorithm is anyway by looking at the
1607      capabilities of the certificate because this is the only way to
1608      know what the recipient can accept. [wk 2002-03-23]
1609
1610      PENDING(g10) Implement this
1611      gpgme_set_encryption_check_certificate_path(
1612      config.checkCertificatePath )
1613
1614      PENDING(g10) Implement this
1615      gpgme_set_encryption_check_certificate_path_to_root(
1616      config.checkEncryptionCertificatePathToRoot )
1617
1618      -> Not checking a certificate up to the ROOT CA is dangerous and
1619      stupid. There is no need for those options.  [wk 2002-03-23] */
1620
1621
1622
1623   err = gpgme_op_encrypt (ctx, rset, gPlaintext, gCiphertext );
1624   if( err ) {
1625     fprintf( stderr, "\ngpgme_op_encrypt() returned this error code:  %i\n\n", err );
1626     if( errId )
1627       *errId = err;
1628     if( errTxt ) {
1629       const char* _errTxt = gpgme_strerror( err );
1630       *errTxt = malloc( strlen( _errTxt ) + 1 );
1631       if( *errTxt )
1632         strcpy(*errTxt, _errTxt );
1633     }
1634   }
1635
1636   gpgme_recipients_release (rset);
1637   gpgme_data_release (gPlaintext);
1638
1639   if( err == GPGME_No_Error ) {
1640     if( __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ) {
1641       *ciphertext = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1642       bOk = true;
1643     }
1644     else {
1645       rCiph = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1646       *ciphertext = malloc( *cipherLen + 1 );
1647       if( *ciphertext ) {
1648         if( *cipherLen ) {
1649           bOk = true;
1650           strncpy((char*)*ciphertext, rCiph, *cipherLen );
1651         }
1652         ((char*)(*ciphertext))[*cipherLen] = 0;
1653       }
1654       free( rCiph );
1655     }
1656   }
1657   else {
1658     gpgme_data_release ( gCiphertext );
1659     *ciphertext = 0;
1660     /* error handling is missing: if only one untrusted key was found
1661       (or none at all), gpg won't sign the message.  (hier fehlt eine
1662       Fehlerbehandlung: fuer einen Recipient nur ein untrusted key
1663       (oder gar keiner) gefunden wurde, verweigert gpg das signieren.)
1664     */
1665   }
1666
1667   gpgme_release (ctx);
1668
1669   fflush( stderr );
1670
1671   if( bOk && structuring ) {
1672     structuring->includeCleartext = GPGMEPLUG_ENC_INCLUDE_CLEARTEXT;
1673     structuring->makeMimeObject   = GPGMEPLUG_ENC_MAKE_MIME_OBJECT;
1674     if( structuring->makeMimeObject ) {
1675       structuring->makeMultiMime  = GPGMEPLUG_ENC_MAKE_MULTI_MIME;
1676       storeNewCharPtr( &structuring->contentTypeMain,
1677                        GPGMEPLUG_ENC_CTYPE_MAIN );
1678       storeNewCharPtr( &structuring->contentDispMain,
1679                        GPGMEPLUG_ENC_CDISP_MAIN );
1680       storeNewCharPtr( &structuring->contentTEncMain,
1681                        GPGMEPLUG_ENC_CTENC_MAIN );
1682       if( structuring->makeMultiMime ) {
1683         storeNewCharPtr( &structuring->contentTypeVersion,
1684                          GPGMEPLUG_ENC_CTYPE_VERSION );
1685         storeNewCharPtr( &structuring->contentDispVersion,
1686                          GPGMEPLUG_ENC_CDISP_VERSION );
1687         storeNewCharPtr( &structuring->contentTEncVersion,
1688                          GPGMEPLUG_ENC_CTENC_VERSION );
1689         storeNewCharPtr( &structuring->bodyTextVersion,
1690                          GPGMEPLUG_ENC_BTEXT_VERSION );
1691         storeNewCharPtr( &structuring->contentTypeCode,
1692                          GPGMEPLUG_ENC_CTYPE_CODE );
1693         storeNewCharPtr( &structuring->contentDispCode,
1694                          GPGMEPLUG_ENC_CDISP_CODE );
1695         storeNewCharPtr( &structuring->contentTEncCode,
1696                          GPGMEPLUG_ENC_CTENC_CODE );
1697       }
1698     } else {
1699       storeNewCharPtr( &structuring->flatTextPrefix,
1700                        GPGMEPLUG_ENC_FLAT_PREFIX );
1701       storeNewCharPtr( &structuring->flatTextSeparator,
1702                        GPGMEPLUG_ENC_FLAT_SEPARATOR );
1703       storeNewCharPtr( &structuring->flatTextPostfix,
1704                        GPGMEPLUG_ENC_FLAT_POSTFIX );
1705     }
1706   }
1707   return bOk;
1708 }
1709
1710
1711 bool encryptAndSignMessage( const char* cleartext,
1712                             const char** ciphertext,
1713                             const char* certificate,
1714                             struct StructuringInfo* structuring )
1715 {
1716   bool bOk;
1717
1718   init_StructuringInfo( structuring );
1719
1720   bOk = false;
1721
1722   /* implementation of this function is still missing */
1723
1724   if( bOk && structuring ) {
1725     structuring->includeCleartext = GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT;
1726     structuring->makeMimeObject   = GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT;
1727     if( structuring->makeMimeObject ) {
1728       structuring->makeMultiMime  = GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME;
1729       storeNewCharPtr( &structuring->contentTypeMain,
1730                        GPGMEPLUG_ENCSIGN_CTYPE_MAIN );
1731       storeNewCharPtr( &structuring->contentDispMain,
1732                        GPGMEPLUG_ENCSIGN_CDISP_MAIN );
1733       storeNewCharPtr( &structuring->contentTEncMain,
1734                        GPGMEPLUG_ENCSIGN_CTENC_MAIN );
1735       if( structuring->makeMultiMime ) {
1736         storeNewCharPtr( &structuring->contentTypeVersion,
1737                          GPGMEPLUG_ENCSIGN_CTYPE_VERSION );
1738         storeNewCharPtr( &structuring->contentDispVersion,
1739                          GPGMEPLUG_ENCSIGN_CDISP_VERSION );
1740         storeNewCharPtr( &structuring->contentTEncVersion,
1741                          GPGMEPLUG_ENCSIGN_CTENC_VERSION );
1742         storeNewCharPtr( &structuring->bodyTextVersion,
1743                          GPGMEPLUG_ENCSIGN_BTEXT_VERSION );
1744         storeNewCharPtr( &structuring->contentTypeCode,
1745                          GPGMEPLUG_ENCSIGN_CTYPE_CODE );
1746         storeNewCharPtr( &structuring->contentDispCode,
1747                          GPGMEPLUG_ENCSIGN_CDISP_CODE );
1748         storeNewCharPtr( &structuring->contentTEncCode,
1749                          GPGMEPLUG_ENCSIGN_CTENC_CODE );
1750       }
1751     } else {
1752       storeNewCharPtr( &structuring->flatTextPrefix,
1753                        GPGMEPLUG_ENCSIGN_FLAT_PREFIX );
1754       storeNewCharPtr( &structuring->flatTextSeparator,
1755                        GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR );
1756       storeNewCharPtr( &structuring->flatTextPostfix,
1757                        GPGMEPLUG_ENCSIGN_FLAT_POSTFIX );
1758     }
1759   }
1760   return bOk;
1761 }
1762
1763
1764 bool decryptMessage( const char* ciphertext,
1765                      bool        cipherIsBinary,
1766                      int         cipherLen,
1767                      const char** cleartext,
1768                      const char* certificate )
1769 {
1770   GpgmeCtx ctx;
1771   GpgmeError err;
1772   GpgmeData gCiphertext, gPlaintext;
1773   size_t rCLen = 0;
1774   char*  rCiph = 0;
1775   bool bOk = false;
1776
1777   if( !ciphertext )
1778     return false;
1779
1780   err = gpgme_new (&ctx);
1781   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1782   
1783   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
1784   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
1785
1786   /*
1787   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
1788                            1+strlen( ciphertext ), 1 ); */
1789   gpgme_data_new_from_mem( &gCiphertext,
1790                            ciphertext,
1791                            cipherIsBinary
1792                            ? cipherLen
1793                            : strlen( ciphertext ),
1794                            1 );
1795
1796   gpgme_data_new( &gPlaintext );
1797
1798   gpgme_op_decrypt( ctx, gCiphertext, gPlaintext );
1799   gpgme_data_release( gCiphertext );
1800
1801   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
1802
1803   *cleartext = malloc( rCLen + 1 );
1804   if( *cleartext ) {
1805       if( rCLen ) {
1806           bOk = true;
1807           strncpy((char*)*cleartext, rCiph, rCLen );
1808       }
1809       ((char*)(*cleartext))[rCLen] = 0;
1810   }
1811
1812   free( rCiph );
1813   gpgme_release( ctx );
1814   return bOk;
1815 }
1816
1817 bool decryptAndCheckMessage( const char* ciphertext,
1818           const char** cleartext, const char* certificate,
1819           struct SignatureMetaData* sigmeta ){ return true; }
1820
1821
1822 const char* requestCertificateDialog(){ return 0; }
1823
1824 bool requestDecentralCertificate( const char* certparms, 
1825                                   char** generatedKey, int* length )
1826 {
1827     GpgmeError err;
1828     GpgmeCtx ctx;
1829     GpgmeData pub;
1830     int len;
1831
1832     err = gpgme_data_new (&pub);
1833     fprintf( stderr,  "1: gpgme returned %d\n", err );
1834     if( err != GPGME_No_Error )
1835         return false;
1836
1837     err = gpgme_new (&ctx);
1838     fprintf( stderr,  "2: gpgme returned %d\n", err );
1839     if( err != GPGME_No_Error ) {
1840         gpgme_data_release( pub );
1841         return false;
1842     }
1843
1844     gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
1845     /* Don't ASCII-armor, the MUA will use base64 encoding */
1846     /*    gpgme_set_armor (ctx, 1); */
1847     err = gpgme_op_genkey (ctx, certparms, pub, NULL );
1848     fprintf( stderr,  "3: gpgme returned %d\n", err );
1849     if( err != GPGME_No_Error ) {
1850         gpgme_data_release( pub );
1851         gpgme_release( ctx );
1852         return false;
1853     }
1854
1855     gpgme_release (ctx);
1856     *generatedKey = gpgme_data_release_and_get_mem (pub, &len);
1857     *length = len;
1858
1859     /* The buffer generatedKey contains the LEN bytes you want */
1860     // Caller is responsible for freeing
1861     return true;
1862 }
1863
1864 bool requestCentralCertificateAndPSE( const char* name,
1865           const char* email, const char* organization, const char* department,
1866           const char* ca_address ){ return true; }
1867
1868 bool createPSE(){ return true; }
1869
1870 bool registerCertificate( const char* certificate ){ return true; }
1871
1872 bool requestCertificateProlongation( const char* certificate,
1873                                      const char* ca_address ){ return true; }
1874
1875 const char* certificateChain(){ return 0; }
1876
1877 bool deleteCertificate( const char* certificate ){ return true; }
1878
1879 bool archiveCertificate( const char* certificate ){ return true; }
1880
1881
1882 const char* displayCRL(){ return 0; }
1883
1884 void updateCRL(){}
1885
1886 /*
1887  * Copyright (C) 2002 g10 Code GmbH
1888  * 
1889  *     This program is free software; you can redistribute it
1890  *     and/or modify it under the terms of the GNU General Public
1891  *     License as published by the Free Software Foundation; either
1892  *     version 2 of the License, or (at your option) any later
1893  *     version.
1894  * 
1895  *     This program is distributed in the hope that it will be
1896  *     useful, but WITHOUT ANY WARRANTY; without even the implied
1897  *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
1898  *     PURPOSE.  See the GNU General Public License for more
1899  *     details.
1900  * 
1901  *     You should have received a copy of the GNU General Public
1902  *     License along with this program; if not, write to the Free
1903  *     Software Foundation, Inc., 59 Temple Place - Suite 330,
1904  *     Boston, MA  02111, USA.
1905  */
1906
1907 /* Max number of parts in a DN */
1908 #define MAX_GPGME_IDX 20
1909
1910 /* some macros to replace ctype ones and avoid locale problems */
1911 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
1912 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
1913 #define hexdigitp(a) (digitp (a)                     \
1914                       || (*(a) >= 'A' && *(a) <= 'F')  \
1915                       || (*(a) >= 'a' && *(a) <= 'f'))
1916 /* the atoi macros assume that the buffer has only valid digits */
1917 #define atoi_1(p)   (*(p) - '0' )
1918 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
1919 #define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
1920 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
1921                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
1922 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
1923
1924 #define safe_malloc( x ) malloc( x )
1925 #define xstrdup( x ) (x)?strdup(x):0
1926
1927 static void 
1928 safe_free( void** x ) 
1929 {
1930   free( *x );
1931   *x = 0;
1932 }
1933 char *
1934 trim_trailing_spaces( char *string )
1935 {
1936     char *p, *mark;
1937
1938     for( mark = NULL, p = string; *p; p++ ) {
1939         if( isspace( *p ) ) {
1940             if( !mark )
1941                 mark = p;
1942         }
1943         else
1944             mark = NULL;
1945     }
1946     if( mark )
1947         *mark = '\0' ;
1948
1949     return string ;
1950 }
1951 /*#define safe_free( x ) free( x )*/
1952
1953 /* Parse a DN and return an array-ized one.  This is not a validating
1954    parser and it does not support any old-stylish syntax; gpgme is
1955    expected to return only rfc2253 compatible strings. */
1956 static const unsigned char *
1957 parse_dn_part (struct DnPair *array, const unsigned char *string)
1958 {
1959   const unsigned char *s, *s1;
1960   size_t n;
1961   unsigned char *p;
1962
1963   /* parse attributeType */
1964   for (s = string+1; *s && *s != '='; s++)
1965     ;
1966   if (!*s)
1967     return NULL; /* error */
1968   n = s - string;
1969   if (!n)
1970     return NULL; /* empty key */
1971   array->key = p = safe_malloc (n+1);
1972   
1973   
1974   memcpy (p, string, n);
1975   p[n] = 0;
1976   trim_trailing_spaces (p);
1977   if ( !strcmp (p, "1.2.840.113549.1.9.1") )
1978     strcpy (p, "EMail");
1979   string = s + 1;
1980
1981   if (*string == '#')
1982     { /* hexstring */
1983       string++;
1984       for (s=string; hexdigitp (s); s++)
1985         s++;
1986       n = s - string;
1987       if (!n || (n & 1))
1988         return NULL; /* empty or odd number of digits */
1989       n /= 2;
1990       array->value = p = safe_malloc (n+1);
1991       
1992       
1993       for (s1=string; n; s1 += 2, n--)
1994         *p++ = xtoi_2 (s1);
1995       *p = 0;
1996    }
1997   else
1998     { /* regular v3 quoted string */
1999       for (n=0, s=string; *s; s++)
2000         {
2001           if (*s == '\\')
2002             { /* pair */
2003               s++;
2004               if (*s == ',' || *s == '=' || *s == '+'
2005                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
2006                   || *s == '\\' || *s == '\"' || *s == ' ')
2007                 n++;
2008               else if (hexdigitp (s) && hexdigitp (s+1))
2009                 {
2010                   s++;
2011                   n++;
2012                 }
2013               else
2014                 return NULL; /* invalid escape sequence */
2015             }
2016           else if (*s == '\"')
2017             return NULL; /* invalid encoding */
2018           else if (*s == ',' || *s == '=' || *s == '+'
2019                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
2020             break; 
2021           else
2022             n++;
2023         }
2024
2025       array->value = p = safe_malloc (n+1);
2026       
2027       
2028       for (s=string; n; s++, n--)
2029         {
2030           if (*s == '\\')
2031             { 
2032               s++;
2033               if (hexdigitp (s))
2034                 {
2035                   *p++ = xtoi_2 (s);
2036                   s++;
2037                 }
2038               else
2039                 *p++ = *s;
2040             }
2041           else
2042             *p++ = *s;
2043         }
2044       *p = 0;
2045     }
2046   return s;
2047 }
2048
2049
2050 /* Parse a DN and return an array-ized one.  This is not a validating
2051    parser and it does not support any old-stylish syntax; gpgme is
2052    expected to return only rfc2253 compatible strings. */
2053 static struct DnPair *
2054 parse_dn (const unsigned char *string)
2055 {
2056   struct DnPair *array;
2057   size_t arrayidx, arraysize;
2058   int i;
2059
2060   if( !string )
2061     return NULL;
2062
2063   arraysize = 7; /* C,ST,L,O,OU,CN,email */
2064   arrayidx = 0;
2065   array = safe_malloc ((arraysize+1) * sizeof *array);
2066   
2067   
2068   while (*string)
2069     {
2070       while (*string == ' ')
2071         string++;
2072       if (!*string)
2073         break; /* ready */
2074       if (arrayidx >= arraysize)
2075         { /* mutt lacks a real safe_realoc - so we need to copy */
2076           struct DnPair *a2;
2077
2078           arraysize += 5;
2079           a2 = safe_malloc ((arraysize+1) * sizeof *array);
2080           for (i=0; i < arrayidx; i++)
2081             {
2082               a2[i].key = array[i].key;
2083               a2[i].value = array[i].value;
2084             }
2085           safe_free ((void **)&array);
2086           array = a2;
2087         }
2088       array[arrayidx].key = NULL;
2089       array[arrayidx].value = NULL;
2090       string = parse_dn_part (array+arrayidx, string);
2091       arrayidx++;
2092       if (!string)
2093         goto failure;
2094       while (*string == ' ')
2095         string++;
2096       if (*string && *string != ',' && *string != ';' && *string != '+')
2097         goto failure; /* invalid delimiter */
2098       if (*string)
2099         string++;
2100     }
2101   array[arrayidx].key = NULL;
2102   array[arrayidx].value = NULL;
2103   return array;
2104
2105  failure:
2106   for (i=0; i < arrayidx; i++)
2107     {
2108       safe_free ((void**)&array[i].key);
2109       safe_free ((void**)&array[i].value);
2110     }
2111   safe_free ((void**)&array);
2112   return NULL;
2113 }
2114
2115 static int 
2116 add_dn_part( char* result, struct DnPair* dn, const char* part )
2117 {
2118   int any = 0;
2119
2120   if( dn ) {
2121     for(; dn->key; ++dn ) {
2122       if( !strcmp( dn->key, part ) ) {
2123         if( any ) strcat( result, "+" );
2124         /* email hack */
2125         if( !strcmp( part, "1.2.840.113549.1.9.1" ) ) strcat( result, "EMail" );
2126         else strcat( result, part );
2127         strcat( result, "=" );
2128         strcat( result, dn->value );
2129         any = 1;
2130       }
2131     }
2132   }
2133   return any;
2134 }
2135
2136 static char* 
2137 reorder_dn( struct DnPair *dn )
2138 {
2139   // note: The must parts are: CN, L, OU, O, C
2140   const char* stdpart[] = {
2141     "CN", "S", "SN", "GN", "T", "UID",
2142           "MAIL", "EMAIL", "MOBILE", "TEL", "FAX", "STREET",
2143     "L",  "PC", "SP", "ST",
2144     "OU",
2145     "O",
2146     "C",
2147     NULL
2148   };
2149   int any=0, any2=0, len=0, i;
2150   char* result;
2151   if( dn ) {
2152     for( i = 0; dn[i].key; ++i ) {
2153       len += strlen( dn[i].key );
2154       len += strlen( dn[i].value );
2155       len += 4; /* ',' and '=', and possibly "(" and ")" */
2156     }
2157   }
2158   result = (char*)safe_malloc( (len+1)*sizeof(char) );
2159   *result = 0;
2160
2161   /* add standard parts */
2162   for( i = 0; stdpart[i]; ++i ) {
2163     if( any ) {
2164       strcat( result, "," );
2165     }
2166     any = add_dn_part( result, dn, stdpart[i] );
2167   }
2168
2169   /* add remaining parts in no particular order */
2170   if( dn ) {
2171     for(; dn->key; ++dn ) {
2172       for( i = 0; stdpart[i]; ++i ) {
2173         if( !strcmp( dn->key, stdpart[i] ) ) {
2174           break;
2175         }
2176       }
2177       if( !stdpart[i] ) {
2178         if( any ) strcat( result, "," );
2179         if( !any2 ) strcat( result, "(");
2180         any = add_dn_part( result, dn, dn->key );
2181         any2 = 1;
2182       }
2183     }
2184   }
2185   if( any2 ) strcat( result, ")");
2186   return result;
2187 }
2188
2189 struct CertIterator {
2190   GpgmeCtx ctx;  
2191   struct CertificateInfo info;
2192 };
2193
2194 struct CertIterator* 
2195 startListCertificates( const char* pattern, int remote )
2196 {
2197     GpgmeError err;
2198     struct CertIterator* it;
2199     /*fprintf( stderr,  "startListCertificates()" );*/
2200
2201     it = (struct CertIterator*)safe_malloc( sizeof( struct CertIterator ) );
2202
2203     err = gpgme_new (&(it->ctx));
2204     /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2205     if( err != GPGME_No_Error ) {
2206       free( it );
2207       return NULL;
2208     }
2209
2210     gpgme_set_protocol (it->ctx, GPGME_PROTOCOL_CMS);
2211     if( remote ) gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_EXTERN ); 
2212     else gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_LOCAL );
2213     err =  gpgme_op_keylist_start ( it->ctx, pattern, 0);
2214     if( err != GPGME_No_Error ) {
2215       endListCertificates( it );
2216       return NULL;
2217     }
2218     memset( &(it->info), 0, sizeof( struct CertificateInfo ) );
2219     return it;
2220 }
2221
2222 /* free() each string in a char*[] and the array itself */
2223 static void 
2224 freeStringArray( char** c )
2225 {
2226     char** _c = c;
2227     while( c && *c ) {
2228       /*fprintf( stderr, "freeing \"%s\"\n", *c );*/
2229       safe_free( (void**)&(*c) );
2230       ++c;
2231     }
2232     safe_free( (void**)&_c );
2233 }
2234
2235 /* free all malloc'ed data in a struct CertificateInfo */
2236 static void 
2237 freeInfo( struct CertificateInfo* info )
2238 {
2239   struct DnPair* a = info->dnarray;
2240   assert( info );
2241   if( info->userid ) freeStringArray( info->userid );
2242   if( info->serial ) safe_free( (void**)&(info->serial) );
2243   if( info->fingerprint ) safe_free( (void**)&(info->fingerprint) );
2244   if( info->issuer ) safe_free( (void**)&(info->issuer) );
2245   if( info->chainid ) safe_free( (void**)&(info->chainid) );
2246   if( info->caps ) safe_free( (void**)&(info->caps) );
2247   while( a && a->key && a->value ) {
2248     safe_free ((void**)&(a->key));
2249     safe_free ((void**)&(a->value));
2250     ++a;
2251   }
2252   if( info->dnarray ) safe_free ((void**)&(info->dnarray));
2253   memset( info, 0, sizeof( *info ) );
2254 }
2255
2256 /* Format the fingerprint nicely. The caller should
2257    free the returned value with safe_free() */
2258 static char* make_fingerprint( const char* fpr )
2259 {
2260   int len = strlen(fpr);
2261   int i = 0;
2262   char* result = safe_malloc( (len + len/2 + 1)*sizeof(char) );
2263   if( !result ) return NULL;
2264   for(; *fpr; ++fpr, ++i ) {
2265     if( i%3 == 2) {
2266       result[i] = ':'; ++i;
2267     }
2268     result[i] = *fpr;
2269   }
2270   result[i] = 0;
2271   return result;
2272 }
2273
2274 int 
2275 nextCertificate( struct CertIterator* it, struct CertificateInfo** result )
2276 {
2277   GpgmeError err;
2278   GpgmeKey   key;
2279   int retval = GPGME_No_Error;
2280   assert( it );
2281   err = gpgme_op_keylist_next ( it->ctx, &key);
2282   if( err != GPGME_EOF ) {   
2283     int idx;
2284     const char* s;
2285     unsigned long u;
2286     char* names[MAX_GPGME_IDX+1];
2287     struct DnPair *issuer_dn, *tmp_dn;
2288     retval = err;
2289     memset( names, 0, sizeof( names ) );
2290     freeInfo( &(it->info) );
2291
2292     for( idx = 0; (s = gpgme_key_get_string_attr (key, GPGME_ATTR_USERID, 0, idx)) && idx < MAX_GPGME_IDX; 
2293          ++idx ) {
2294       names[idx] = xstrdup( s );
2295     }
2296     
2297     it->info.userid = safe_malloc( sizeof( char* ) * (idx+1) );
2298     memset( it->info.userid, 0, sizeof( char* ) * (idx+1) );
2299     it->info.dnarray = 0;
2300     for( idx = 0; names[idx] != 0; ++idx ) {
2301       struct DnPair* a = parse_dn( names[idx] ); 
2302       if( idx == 0 ) {
2303         it->info.userid[idx] = reorder_dn( a );
2304         it->info.dnarray = a;
2305         safe_free( (void **)&(names[idx]) );
2306       } else {
2307         it->info.userid[idx] = names[idx];
2308       }
2309     }
2310     it->info.userid[idx] = 0;
2311
2312     s = gpgme_key_get_string_attr (key, GPGME_ATTR_SERIAL, 0, 0); 
2313     it->info.serial = xstrdup(s);
2314
2315     s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, 0, 0); 
2316     it->info.fingerprint = make_fingerprint( s );
2317
2318     s = gpgme_key_get_string_attr (key, GPGME_ATTR_ISSUER, 0, 0); 
2319     if( s ) {
2320       issuer_dn = tmp_dn = parse_dn( s );     
2321       /*it->info.issuer = xstrdup(s);*/
2322       it->info.issuer = reorder_dn( issuer_dn );
2323       while( tmp_dn->key ) {
2324         safe_free( (void**)&issuer_dn->key );
2325         safe_free( (void**)&issuer_dn->value );
2326         ++tmp_dn;
2327       }
2328       safe_free( (void**)&issuer_dn );
2329     } else {
2330       it->info.issuer = NULL;
2331     }
2332     s = gpgme_key_get_string_attr (key, GPGME_ATTR_CHAINID, 0, 0); 
2333     it->info.chainid = xstrdup(s);
2334
2335     s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEY_CAPS, 0, 0); 
2336     it->info.caps = xstrdup(s);
2337
2338     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_CREATED, 0, 0); 
2339     it->info.created = u;
2340
2341     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_EXPIRE, 0, 0); 
2342     it->info.expire = u;
2343
2344     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_IS_SECRET, 0, 0); 
2345     it->info.secret = u;
2346
2347     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_UID_INVALID, 0, 0); 
2348     it->info.invalid = u;
2349
2350     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_EXPIRED, 0, 0); 
2351     it->info.expired = u;
2352
2353     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_DISABLED, 0, 0); 
2354     it->info.disabled = u;
2355
2356     gpgme_key_release (key);
2357     /*return &(it->info);*/
2358     *result =  &(it->info);
2359   } else *result = NULL;
2360   return retval;
2361 }
2362
2363 void 
2364 endListCertificates( struct CertIterator* it )
2365 {
2366   /*fprintf( stderr,  "endListCertificates()\n" );*/
2367   assert(it);
2368   freeInfo( &(it->info) );
2369   gpgme_op_keylist_end(it->ctx);
2370   gpgme_release (it->ctx);
2371   free( it );
2372 }
2373
2374 int
2375 importCertificate( const char* fingerprint )
2376 {
2377   GpgmeError err;
2378   GpgmeCtx  ctx;
2379   GpgmeData keydata;
2380   GpgmeRecipients recips;
2381   char* buf;
2382   const char* tmp1;
2383   char* tmp2;
2384
2385   err = gpgme_new( &ctx );
2386   /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2387   if( err != GPGME_No_Error ) {
2388     return err;
2389   }
2390   gpgme_set_protocol( ctx, GPGME_PROTOCOL_CMS );
2391   gpgme_set_keylist_mode( ctx, GPGME_KEYLIST_MODE_LOCAL );
2392
2393   err = gpgme_data_new( &keydata );
2394   if( err ) {
2395     fprintf( stderr,  "gpgme_data_new returned %d\n", err );
2396     gpgme_release( ctx );
2397     return err;
2398   }
2399
2400   err = gpgme_recipients_new( &recips );
2401   if( err ) {
2402     fprintf( stderr,  "gpgme_recipients_new returned %d\n", err );
2403     gpgme_data_release( keydata );
2404     gpgme_release( ctx );
2405     return err;
2406   }
2407   
2408   buf = safe_malloc( sizeof(char)*( strlen( fingerprint ) + 1 ) );
2409   if( !buf ) {
2410     gpgme_recipients_release( recips );
2411     gpgme_data_release( keydata );    
2412     gpgme_release( ctx );
2413     return GPGME_Out_Of_Core;
2414   }
2415   tmp1 = fingerprint;
2416   tmp2 = buf;
2417   while( *tmp1 ) {
2418     if( *tmp1 != ':' ) *tmp2++ = *tmp1;
2419     tmp1++;
2420   }
2421   *tmp2 = 0;
2422   fprintf( stderr,  "calling gpgme_recipients_add_name( %s )\n", buf );  
2423   err = gpgme_recipients_add_name( recips, buf ); 
2424   if( err ) {
2425     fprintf( stderr,  "gpgme_recipients_add_name returned %d\n", err );
2426     safe_free( (void**)&buf );
2427     gpgme_recipients_release( recips );
2428     gpgme_data_release( keydata );    
2429     gpgme_release( ctx );
2430     return err;
2431   }
2432
2433   err = gpgme_op_export( ctx, recips, keydata );
2434   if( err ) {
2435     fprintf( stderr,  "gpgme_op_export returned %d\n", err );
2436     safe_free( (void**)&buf );
2437     gpgme_recipients_release( recips );
2438     gpgme_data_release( keydata );    
2439     gpgme_release( ctx );
2440     return err;
2441   }
2442   safe_free( (void**)&buf );
2443
2444   err = gpgme_op_import( ctx, keydata );
2445   if( err ) {    
2446     fprintf( stderr,  "gpgme_op_import returned %d\n", err );
2447     gpgme_recipients_release( recips );
2448     gpgme_data_release( keydata );    
2449     gpgme_release( ctx );
2450     return err;
2451   }
2452
2453   gpgme_recipients_release( recips );
2454   gpgme_data_release( keydata );    
2455   gpgme_release( ctx );
2456   return 0;
2457 }
2458
2459     // // // // // // // // // // // // // // // // // // // // // // // // //
2460    //                                                                      //
2461   //         Continuation of CryptPlug code                               //
2462  //                                                                      //
2463 // // // // // // // // // // // // // // // // // // // // // // // // //
2464
2465
2466 /*
2467   Find all certificate for a given addressee and return them in a
2468   '\1' separated list.
2469   NOTE: The certificate parameter must point to a not-yet allocated
2470         char*.  The function will allocate the memory needed and
2471         return the size in newSize.
2472   If secretOnly is true, only secret keys are returned.
2473 */
2474 bool findCertificates( const char* addressee,
2475                        char** certificates,
2476                        int* newSize,
2477                        bool secretOnly )
2478 {
2479   static int maxCerts = 1024;
2480   // use const char declarations since all of them are needed twice
2481   const char* delimiter = "\1";
2482   const char* openBracket = "    (";
2483   const char* closeBracket = ")";
2484
2485   GpgmeCtx ctx;
2486   GpgmeError err;
2487   GpgmeKey rKey;
2488   const char *s;
2489   const char *s2;
2490   char* dn;
2491   struct DnPair* a;
2492   int nFound = 0;
2493   int iFound = 0;
2494   int siz = 0;
2495   char* DNs[maxCerts];
2496   char* FPRs[maxCerts];
2497   
2498   if( ! certificates ){
2499     fprintf( stderr, "gpgme: findCertificates called with invalid *certificates pointer\n" );
2500     return false;
2501   }
2502
2503   if( ! newSize ){
2504     fprintf( stderr, "gpgme: findCertificates called with invalid newSize pointer\n" );
2505     return false;
2506   }
2507
2508   *certificates = 0;
2509   *newSize = 0;
2510   
2511   // calculate length of buffer needed for certs plus fingerprints
2512   memset( DNs,  0, sizeof( DNs  ) );
2513   memset( FPRs, 0, sizeof( FPRs ) );
2514   gpgme_new (&ctx);
2515   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
2516   err = gpgme_op_keylist_start(ctx, addressee, secretOnly ? 1 : 0);
2517   while( GPGME_No_Error == err ) {
2518     err = gpgme_op_keylist_next(ctx, &rKey);
2519     if( GPGME_No_Error == err ) {
2520       s = gpgme_key_get_string_attr (rKey, GPGME_ATTR_USERID, NULL, 0);
2521       if( s ) {
2522         dn = xstrdup( s );
2523         s2 = gpgme_key_get_string_attr (rKey, GPGME_ATTR_FPR, NULL, 0);
2524         if( s2 ) {
2525           if( nFound )
2526             siz += strlen( delimiter );
2527           a = parse_dn( dn );
2528           free( dn );
2529           dn = reorder_dn( a );
2530           siz += strlen( dn );
2531           siz += strlen( openBracket );
2532           siz += strlen( s2 );
2533           siz += strlen( closeBracket );
2534           DNs[ nFound ] = xstrdup( dn );
2535           FPRs[nFound ] = xstrdup( s2 );
2536           ++nFound;
2537           if( nFound >= maxCerts ) {
2538             fprintf( stderr,
2539                      "gpgme: findCertificates found too many certificates (%d)\n",
2540                      maxCerts );
2541             break;
2542           }
2543         }
2544         free( dn );
2545       }
2546     }
2547   }
2548   gpgme_op_keylist_end( ctx );
2549   gpgme_release (ctx);
2550   
2551   
2552   if( 0 < siz ) {
2553     // add one for trailing ZERO char
2554     ++siz;
2555     *newSize = siz;
2556     // allocate the buffer
2557     *certificates = malloc(   sizeof(char) * siz );
2558     memset( *certificates, 0, sizeof(char) * siz );
2559     // fill the buffer
2560     for( iFound=0; iFound < nFound; ++iFound ) {
2561       if( !iFound )
2562         strcpy(*certificates, DNs[iFound] );
2563       else {
2564         strcat(*certificates, delimiter );
2565         strcat(*certificates, DNs[iFound] );
2566       }
2567       strcat(  *certificates, openBracket );
2568       strcat(  *certificates, FPRs[iFound] );
2569       strcat(  *certificates, closeBracket );
2570       ++iFound;
2571       free( DNs[ iFound ] );
2572       free( FPRs[iFound ] );
2573     }
2574   }
2575     
2576   return ( 0 < nFound );
2577 }