doc/
[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   Copyright (C) 2002 g10 Code GmbH
10
11   GPGMEPLUG is free software; you can redistribute it and/or modify
12   it under the terms of GNU General Public License as published by
13   the Free Software Foundation; version 2 of the License.
14
15   GPGMEPLUG is distributed in the hope that it will be useful,
16   it under the terms of GNU General Public License as published by
17   the Free Software Foundation; version 2 of the License
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20   GNU General Public License for more details.
21
22   You should have received a copy of the GNU General Public License
23   along with this program; if not, write to the Free Software
24   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
25 */
26
27
28
29 /*! \file gpgmeplug.c
30     \brief GPGME implementation of CRYPTPLUG following the
31     specification located in common API header cryptplug.h.
32
33     CRYPTPLUG is an independent cryptography plug-in API
34     developed for Sphinx-enabeling KMail and Mutt.
35
36     CRYPTPLUG was designed for the Aegypten project, but it may
37     be used by 3rd party developers as well to design pluggable
38     crypto backends for the above mentioned MUAs.
39
40     \note All string parameters appearing in this API are to be
41     interpreted as UTF-8 encoded.
42
43     \see cryptplug.h
44 */
45
46 #ifdef HAVE_CONFIG_H
47 #include <config.h>
48 #endif
49 #include <stdio.h>
50 #include <string.h>
51 #include <assert.h>
52 #include <errno.h>
53 #include <time.h>
54 #include <ctype.h>
55
56 #ifndef BUG_URL
57 #define BUG_URL "http:://www.gnupg.org/aegypten/"
58 #endif
59
60 #include "gpgme.h"
61 #ifndef GPGMEPLUG_PROTOCOL
62 #define GPGMEPLUG_PROTOCOL GPGME_PROTOCOL_OpenPGP
63 #endif
64
65 /* definitions for signing */
66 /* 1. opaque signatures (only used for S/MIME). */
67 #ifndef GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT
68 #define GPGMEPLUG_OPA_SIGN_INCLUDE_CLEARTEXT false
69 #define GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT  false
70 #define GPGMEPLUG_OPA_SIGN_MAKE_MULTI_MIME   false
71 #define GPGMEPLUG_OPA_SIGN_CTYPE_MAIN        ""
72 #define GPGMEPLUG_OPA_SIGN_CDISP_MAIN        ""
73 #define GPGMEPLUG_OPA_SIGN_CTENC_MAIN        ""
74 #define GPGMEPLUG_OPA_SIGN_CTYPE_VERSION     ""
75 #define GPGMEPLUG_OPA_SIGN_CDISP_VERSION     ""
76 #define GPGMEPLUG_OPA_SIGN_CTENC_VERSION     ""
77 #define GPGMEPLUG_OPA_SIGN_BTEXT_VERSION     ""
78 #define GPGMEPLUG_OPA_SIGN_CTYPE_CODE        ""
79 #define GPGMEPLUG_OPA_SIGN_CDISP_CODE        ""
80 #define GPGMEPLUG_OPA_SIGN_CTENC_CODE        ""
81 #define GPGMEPLUG_OPA_SIGN_FLAT_PREFIX       ""
82 #define GPGMEPLUG_OPA_SIGN_FLAT_SEPARATOR    ""
83 #define GPGMEPLUG_OPA_SIGN_FLAT_POSTFIX      ""
84 #endif
85 /* 2. detached signatures (used for S/MIME and for OpenPGP) */
86 #ifndef GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT
87 #define GPGMEPLUG_DET_SIGN_INCLUDE_CLEARTEXT true
88 #define GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT  true
89 #define GPGMEPLUG_DET_SIGN_MAKE_MULTI_MIME   true
90 #define GPGMEPLUG_DET_SIGN_CTYPE_MAIN        "multipart/signed;protocol=application/pgp-signature;micalg=pgp-sha1"
91 #define GPGMEPLUG_DET_SIGN_CDISP_MAIN        ""
92 #define GPGMEPLUG_DET_SIGN_CTENC_MAIN        ""
93 #define GPGMEPLUG_DET_SIGN_CTYPE_VERSION     ""
94 #define GPGMEPLUG_DET_SIGN_CDISP_VERSION     ""
95 #define GPGMEPLUG_DET_SIGN_CTENC_VERSION     ""
96 #define GPGMEPLUG_DET_SIGN_BTEXT_VERSION     ""
97 #define GPGMEPLUG_DET_SIGN_CTYPE_CODE        "application/pgp-signature"
98 #define GPGMEPLUG_DET_SIGN_CDISP_CODE        ""
99 #define GPGMEPLUG_DET_SIGN_CTENC_CODE        ""
100 #define GPGMEPLUG_DET_SIGN_FLAT_PREFIX       ""
101 #define GPGMEPLUG_DET_SIGN_FLAT_SEPARATOR    ""
102 #define GPGMEPLUG_DET_SIGN_FLAT_POSTFIX      ""
103 #endif
104 /* 3. common definitions for opaque and detached signing */
105 #ifndef __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY
106 #define __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY false
107 #endif
108
109 #define __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO "Error: Cannot run checkMessageSignature() with cleartext == 0"
110
111 /* definitions for encoding */
112 #ifndef GPGMEPLUG_ENC_MAKE_MIME_OBJECT
113 #define GPGMEPLUG_ENC_INCLUDE_CLEARTEXT  false
114 #define GPGMEPLUG_ENC_MAKE_MIME_OBJECT   true
115 #define GPGMEPLUG_ENC_MAKE_MULTI_MIME    true
116 #define GPGMEPLUG_ENC_CTYPE_MAIN         "multipart/encrypted; protocol=application/pgp-encrypted"
117 #define GPGMEPLUG_ENC_CDISP_MAIN         ""
118 #define GPGMEPLUG_ENC_CTENC_MAIN         ""
119 #define GPGMEPLUG_ENC_CTYPE_VERSION      "application/pgp-encrypted"
120 #define GPGMEPLUG_ENC_CDISP_VERSION      "attachment"
121 #define GPGMEPLUG_ENC_CTENC_VERSION      ""
122 #define GPGMEPLUG_ENC_BTEXT_VERSION      "Version: 1"
123 #define GPGMEPLUG_ENC_CTYPE_CODE         "application/octet-stream"
124 #define GPGMEPLUG_ENC_CDISP_CODE         "inline; filename=\"msg.asc\""
125 #define GPGMEPLUG_ENC_CTENC_CODE         ""
126 #define GPGMEPLUG_ENC_FLAT_PREFIX        ""
127 #define GPGMEPLUG_ENC_FLAT_SEPARATOR     ""
128 #define GPGMEPLUG_ENC_FLAT_POSTFIX       ""
129 #define __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY false
130 #endif
131 /* Note: The following specification will result in
132        function encryptAndSignMessage() producing
133        _empty_ mails.
134        This must be changed as soon as our plugin
135        is supporting the encryptAndSignMessage() function. */
136 #ifndef GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT
137 #define GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT false
138 #define GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT  false
139 #define GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME   false
140 #define GPGMEPLUG_ENCSIGN_CTYPE_MAIN        ""
141 #define GPGMEPLUG_ENCSIGN_CDISP_MAIN        ""
142 #define GPGMEPLUG_ENCSIGN_CTENC_MAIN        ""
143 #define GPGMEPLUG_ENCSIGN_CTYPE_VERSION     ""
144 #define GPGMEPLUG_ENCSIGN_CDISP_VERSION     ""
145 #define GPGMEPLUG_ENCSIGN_CTENC_VERSION     ""
146 #define GPGMEPLUG_ENCSIGN_BTEXT_VERSION     ""
147 #define GPGMEPLUG_ENCSIGN_CTYPE_CODE        ""
148 #define GPGMEPLUG_ENCSIGN_CDISP_CODE        ""
149 #define GPGMEPLUG_ENCSIGN_CTENC_CODE        ""
150 #define GPGMEPLUG_ENCSIGN_FLAT_PREFIX       ""
151 #define GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR    ""
152 #define GPGMEPLUG_ENCSIGN_FLAT_POSTFIX      ""
153 #endif
154
155 #include "cryptplug.h"
156
157
158 #define days_from_seconds(x) ((x)/86400)
159
160
161 typedef struct {
162   const char*             bugURL;
163   const char*             signatureKeyCertificate;
164   SignatureAlgorithm      signatureAlgorithm;
165   SignatureCompoundMode   signatureCompoundMode;
166   SendCertificates        sendCertificates;
167   SignEmail               signEmail;
168   bool                    saveSentSignatures;
169   bool                    warnNoCertificate;
170   PinRequests             numPINRequests;
171   bool                    checkSignatureCertificatePathToRoot;
172   bool                    signatureUseCRLs;
173   EncryptionAlgorithm     encryptionAlgorithm;
174   EncryptEmail            encryptEmail;
175   bool                    saveMessagesEncrypted;
176   bool                    checkEncryptionCertificatePathToRoot;
177   bool                    encryptionUseCRLs;
178   bool                    encryptionCRLExpiryNearWarning;
179   int                     encryptionCRLNearExpiryInterval;
180   struct DirectoryServer *directoryServers;
181   unsigned int            numDirectoryServers;
182   CertificateSource       certificateSource;
183   CertificateSource       cRLSource;
184   bool                    warnSendUnsigned;
185   int                     numPINRequestsInterval;
186   bool                    signatureCertificateExpiryNearWarning;
187   int                     signatureCertificateExpiryNearInterval;
188   bool                    cACertificateExpiryNearWarning;
189   int                     cACertificateExpiryNearInterval;
190   bool                    rootCertificateExpiryNearWarning;
191   int                     rootCertificateExpiryNearInterval;
192   bool                    warnSendUnencrypted;
193   bool                    checkCertificatePath;
194   bool                    receiverCertificateExpiryNearWarning;
195   int                     receiverCertificateExpiryNearWarningInterval;
196   bool                    certificateInChainExpiryNearWarning;
197   int                     certificateInChainExpiryNearWarningInterval;
198   bool                    receiverEmailAddressNotInCertificateWarning;
199   const char* libVersion; /* a statically allocated string with the GPGME Version used */
200 } Config;
201
202
203 Config config;
204
205 #define NEAR_EXPIRY 14
206
207 /* Max number of parts in a DN */
208 #define MAX_GPGME_IDX 20
209
210 /* some macros to replace ctype ones and avoid locale problems */
211 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
212 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
213 #define hexdigitp(a) (digitp (a)                     \
214                       || (*(a) >= 'A' && *(a) <= 'F')  \
215                       || (*(a) >= 'a' && *(a) <= 'f'))
216 /* the atoi macros assume that the buffer has only valid digits */
217 #define atoi_1(p)   (*(p) - '0' )
218 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
219 #define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
220 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
221                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
222 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
223
224 static void *
225 xmalloc (size_t n)
226 {
227   char *p = malloc (n);
228   if (!p)
229     { 
230       fputs ("\nfatal: out of core\n", stderr);
231       exit (4);
232     }
233   return p;
234 }
235
236 /* Please: Don't call an allocation function xfoo when it may return NULL. */
237 /* Wrong: #define xstrdup( x ) (x)?strdup(x):0 */
238 /* Right: */
239 static char *
240 xstrdup (const char *string)
241 {
242   char *p = xmalloc (strlen (string)+1);
243   strcpy (p, string);
244   return p;
245 }
246
247
248
249 bool initialize()
250 {
251   int engineCheckVersion = gpgme_engine_check_version (GPGMEPLUG_PROTOCOL);
252   config.bugURL                               = malloc( strlen( BUG_URL ) + 1 );
253   strcpy( (char* )config.bugURL,                BUG_URL );
254   config.signatureKeyCertificate              = malloc( 1 );
255   strcpy( (char* )config.signatureKeyCertificate, "" );
256   config.signatureAlgorithm                   = SignAlg_SHA1;
257   if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
258     config.signatureCompoundMode              = SignatureCompoundMode_Opaque;
259   else
260     config.signatureCompoundMode              = SignatureCompoundMode_Detached;
261   config.sendCertificates                     = SendCert_SendChainWithRoot;
262   config.signEmail                            = SignEmail_SignAll;
263   config.saveSentSignatures                   = true;
264   config.warnNoCertificate                    = true;
265   config.numPINRequests                       = PinRequest_Always;
266   config.checkSignatureCertificatePathToRoot  = true;
267   config.signatureUseCRLs                     = true;
268   config.encryptionAlgorithm                  = EncryptAlg_RSA;
269   config.encryptEmail                         = EncryptEmail_Ask;
270   config.saveMessagesEncrypted                = true;
271   config.checkEncryptionCertificatePathToRoot = true;
272   config.encryptionUseCRLs                    = true;
273   config.encryptionCRLExpiryNearWarning       = true;
274   config.encryptionCRLNearExpiryInterval      = NEAR_EXPIRY;
275   config.directoryServers                     = NULL;
276   config.numDirectoryServers                  = 0;
277   config.certificateSource                    = CertSrc_Server;
278   config.cRLSource                            = CertSrc_Server;
279   config.warnSendUnsigned                             = true;
280   config.numPINRequestsInterval                       = NEAR_EXPIRY;
281   config.signatureCertificateExpiryNearWarning        = true;
282   config.signatureCertificateExpiryNearInterval       = NEAR_EXPIRY;
283   config.cACertificateExpiryNearWarning               = true;
284   config.cACertificateExpiryNearInterval              = NEAR_EXPIRY;
285   config.rootCertificateExpiryNearWarning             = true;
286   config.rootCertificateExpiryNearInterval            = NEAR_EXPIRY;
287   config.warnSendUnencrypted                          = false;
288   config.checkCertificatePath                         = true;
289   config.receiverCertificateExpiryNearWarning         = true;
290   config.receiverCertificateExpiryNearWarningInterval = NEAR_EXPIRY;
291   config.certificateInChainExpiryNearWarning          = true;
292   config.certificateInChainExpiryNearWarningInterval  = NEAR_EXPIRY;
293   config.receiverEmailAddressNotInCertificateWarning  = true;
294   config.libVersion = gpgme_check_version (NULL);
295   if( engineCheckVersion != GPGME_No_Error )
296     fprintf( stderr, "gpgmeplug initialize() returned %i\n", engineCheckVersion );
297   return (engineCheckVersion == GPGME_No_Error);
298 };
299
300
301 void deinitialize()
302 {
303   unsigned int i;
304   for( i = 0; i < config.numDirectoryServers; ++i ) {
305     free( (char *)config.directoryServers[i].servername );
306     free( (char *)config.directoryServers[i].description );
307   }
308   free( config.directoryServers );
309 }
310
311
312 bool hasFeature( Feature flag )
313 {
314   /* our own plugins are supposed to support everything */
315   switch ( flag ) {
316   case Feature_SignMessages:              return true;
317   case Feature_VerifySignatures:          return true;
318   case Feature_EncryptMessages:           return true;
319   case Feature_DecryptMessages:           return true;
320   case Feature_SendCertificates:          return true;
321   case Feature_WarnSignCertificateExpiry: return true;
322   case Feature_WarnSignEmailNotInCertificate: return true;
323   case Feature_PinEntrySettings:          return true;
324   case Feature_StoreMessagesWithSigs:     return true;
325   case Feature_EncryptionCRLs:            return true;
326   case Feature_WarnEncryptCertificateExpiry: return true;
327   case Feature_WarnEncryptEmailNotInCertificate: return true;
328   case Feature_StoreMessagesEncrypted:    return true;
329   case Feature_CheckCertificatePath:      return true;
330   case Feature_CertificateDirectoryService: return false;
331   case Feature_CRLDirectoryService:       return false;
332   /* undefined or not yet implemented: */
333   case Feature_undef:                     return false;
334   default:                                      return false;
335   }
336 }
337
338
339 const char* libVersion(){ return config.libVersion; }
340
341
342 const char* bugURL(){ return config.bugURL; }
343
344
345 void unsafeStationery( void** pixmap, const char** menutext, char* accel,
346           const char** tooltip, const char** statusbartext ){}
347
348 void signedStationery( void** pixmap, const char** menutext, char* accel,
349           const char** tooltip, const char** statusbartext ){}
350
351 void encryptedStationery( void** pixmap, const char**
352           menutext, char* accel,
353           const char** tooltip, const char** statusbartext ){}
354
355 void signedEncryptedStationery( void** pixmap, const char**
356           menutext, char* accel,
357           const char** tooltip, const char** statusbartext ){}
358
359 const char* signatureConfigurationDialog(){ return 0; }
360
361 const char* signatureKeySelectionDialog(){ return 0; }
362
363 const char* signatureAlgorithmDialog(){ return 0; }
364
365 const char* signatureHandlingDialog(){ return 0; }
366
367 void setSignatureKeyCertificate( const char* certificate )
368 {
369   config.signatureKeyCertificate = certificate;
370 }
371
372 const char* signatureKeyCertificate()
373 {
374   return config.signatureKeyCertificate;
375 }
376
377 void setSignatureAlgorithm( SignatureAlgorithm sigAlg )
378 {
379   config.signatureAlgorithm = sigAlg;
380 }
381
382 SignatureAlgorithm signatureAlgorithm()
383 {
384   return config.signatureAlgorithm;
385 }
386
387 void setSignatureCompoundMode( SignatureCompoundMode signComp )
388 {
389   config.signatureCompoundMode = signComp;
390 }
391
392 SignatureCompoundMode signatureCompoundMode()
393 {
394   return config.signatureCompoundMode;
395 }
396
397 void setSendCertificates( SendCertificates sendCert )
398 {
399   config.sendCertificates = sendCert;
400 }
401
402 SendCertificates sendCertificates()
403 {
404   return config.sendCertificates;
405 }
406
407 void setSignEmail( SignEmail signMail )
408 {
409   config.signEmail = signMail;
410 }
411
412 SignEmail signEmail()
413 {
414   return config.signEmail;
415 }
416
417
418
419
420
421 void setWarnSendUnsigned( bool flag )
422 {
423   config.warnSendUnsigned = flag;
424 }
425
426 bool warnSendUnsigned()
427 {
428   return config.warnSendUnsigned;
429 }
430
431
432
433
434
435
436 void setSaveSentSignatures( bool flag )
437 {
438   config.saveSentSignatures = flag;
439 }
440
441 bool saveSentSignatures()
442 {
443   return config.saveSentSignatures;
444 }
445
446 void setWarnNoCertificate( bool flag )
447 {
448   config.warnNoCertificate = flag;
449 }
450
451 bool warnNoCertificate()
452 {
453   return config.warnNoCertificate;
454 }
455
456
457 bool isEmailInCertificate( const char* email, const char* fingerprint )
458 {
459   bool bOk = false;
460   if( searchEmail && fingerprint ){
461     GpgmeCtx ctx;
462     GpgmeError err;
463     GpgmeKey rKey;
464     int UID_idx;
465     const char* attr_string;
466     const char* email = searchEmail;
467     int emailLen = strlen( email );
468     int emailCount = 0;
469
470     if (email && *email == '<'){
471       ++email;
472       emailLen -= 2;
473     }
474     
475     fprintf( stderr, "gpgmeplug isEmailInCertificate looking address %s\nin certificate with fingerprint %s\n", email, fingerprint );
476
477     gpgme_new( &ctx );
478     gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
479
480     err = gpgme_op_keylist_start( ctx, fingerprint, 0 );
481     if ( GPGME_No_Error == err ) {
482       err = gpgme_op_keylist_next( ctx, &rKey );
483       gpgme_op_keylist_end( ctx );
484       if ( GPGME_No_Error == err ) {
485         /* extract email(s) */
486         for( UID_idx = 0; 
487              (attr_string = gpgme_key_get_string_attr(
488                               rKey, GPGME_ATTR_EMAIL, 0, UID_idx));
489              ++UID_idx ){
490           if( !attr_string || !*attr_string )
491             attr_string = gpgme_key_get_string_attr(
492                             rKey, GPGME_ATTR_USERID, 0, UID_idx );
493           if( attr_string ){
494             if( *attr_string == '<' )
495               ++attr_string;
496             if( *attr_string ){
497               ++emailCount;
498               fprintf( stderr, "gpgmeplug isEmailInCertificate found email: %s\n", attr_string );
499               if( 0 == strncasecmp(attr_string, email, emailLen) ){
500                 bOk = true;
501                 break;
502               }
503             }
504           }
505         }
506         if( !emailCount )
507           fprintf( stderr, "gpgmeplug isEmailInCertificate found NO EMAIL\n" );
508         else if( !bOk )
509           fprintf( stderr, "gpgmeplug isEmailInCertificate found NO MATCHING email\n" );
510         gpgme_key_release( rKey );
511       }else{
512         fprintf( stderr, "gpgmeplug isEmailInCertificate found NO CERTIFICATE for fingerprint %s\n", fingerprint );
513       }
514     }else{
515       fprintf( stderr, "gpgmeplug isEmailInCertificate could NOT open KEYLIST for fingerprint %s\n", fingerprint );
516     }
517     gpgme_release( ctx );
518   }else{
519     if( searchEmail )
520       fprintf( stderr, "gpgmeplug isEmailInCertificate called with parameter FINGERPRINT being EMPTY\n" );
521     else
522       fprintf( stderr, "gpgmeplug isEmailInCertificate called with parameter EMAIL being EMPTY\n" );
523   }
524   return bOk;
525 }
526
527
528 void setNumPINRequests( PinRequests reqMode )
529 {
530   config.numPINRequests = reqMode;
531
532   /* PENDING(g10) Put this value into gpg and make it ask for the pin
533      according to this. Note that there is also
534      setNumPINRequestsInterval() which is only used if reqMode ==
535      PinRequest_AfterMinutes.
536   */
537 }
538
539 PinRequests numPINRequests()
540 {
541   return config.numPINRequests;
542 }
543
544
545
546 void setNumPINRequestsInterval( int interval )
547 {
548   config.numPINRequestsInterval = interval;
549
550   /* PENDING(g10) Put this value into gpg and make it ask for the pin
551      according to this. Note that this should only be used if
552      config.numPINRequests (set with setNumPINRequests()) has the
553      value PinRequest_AfterMinutes.
554   */
555 }
556
557 int numPINRequestsInterval()
558 {
559   return config.numPINRequestsInterval;
560 }
561
562
563
564 void setCheckSignatureCertificatePathToRoot( bool flag )
565 {
566   config.checkSignatureCertificatePathToRoot = flag;
567 }
568
569 bool checkSignatureCertificatePathToRoot()
570 {
571   return config.checkSignatureCertificatePathToRoot;
572 }
573
574 void setSignatureUseCRLs( bool flag )
575 {
576   config.signatureUseCRLs = flag;
577 }
578
579 bool signatureUseCRLs()
580 {
581   return config.signatureUseCRLs;
582 }
583
584
585
586
587
588
589 void setSignatureCertificateExpiryNearWarning( bool flag )
590 {
591   config.signatureCertificateExpiryNearWarning = flag;
592 }
593
594 bool signatureCertificateExpiryNearWarning( void )
595 {
596   return config.signatureCertificateExpiryNearWarning;
597 }
598
599
600 int signatureCertificateDaysLeftToExpiry( const char* certificate )
601 {
602   GpgmeCtx ctx;
603   GpgmeError err;
604   GpgmeKey rKey;
605   int daysLeft = CRYPTPLUG_CERT_DOES_NEVER_EXPIRE;
606
607   gpgme_new( &ctx );
608   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
609
610   err = gpgme_op_keylist_start( ctx, certificate, 0 );
611   if ( GPGME_No_Error == err ) {
612     err = gpgme_op_keylist_next( ctx, &rKey );
613     gpgme_op_keylist_end( ctx );
614     if ( GPGME_No_Error == err ) {
615       time_t expire_time = gpgme_key_get_ulong_attr(
616                              rKey, GPGME_ATTR_EXPIRE, NULL, 0 );
617       if ( 0 != expire_time ) {
618         time_t cur_time = time (NULL);
619         if( cur_time > expire_time ) {
620           daysLeft = days_from_seconds(cur_time - expire_time);
621           daysLeft *= -1;
622         }
623         else
624           daysLeft = days_from_seconds(expire_time - cur_time);
625       }
626       gpgme_key_release( rKey );
627     }
628   }
629   gpgme_release( ctx );
630     
631   /* 
632   fprintf( stderr, "gpgmeplug signatureCertificateDaysLeftToExpiry returned %d\n", daysLeft );
633   */
634
635   return daysLeft;
636 }
637
638
639 void setSignatureCertificateExpiryNearInterval( int interval )
640 {
641   config.signatureCertificateExpiryNearInterval = interval;
642 }
643
644 int signatureCertificateExpiryNearInterval( void )
645 {
646   return config.signatureCertificateExpiryNearInterval;
647 }
648
649 void setCACertificateExpiryNearWarning( bool flag )
650 {
651   config.cACertificateExpiryNearWarning = flag;
652 }
653
654 bool caCertificateExpiryNearWarning( void )
655 {
656   return config.cACertificateExpiryNearWarning;
657 }
658
659 int caCertificateDaysLeftToExpiry( const char* certificate )
660 {
661     /* PENDING(g10)
662        Please return the number of days that are left until the
663        CA certificate for the certificate specified in the parameter
664        certificate expires.
665     */
666   /*
667   GpgmeCtx ctx;
668   GpgmeError err;
669   GpgmeKey rKey;
670   time_t daysLeft = 0;
671
672   gpgme_new( &ctx );
673   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
674
675   err = gpgme_op_keylist_start( ctx, certificate, 0 );
676   if ( GPGME_No_Error == err ) {
677     err = gpgme_op_keylist_next( ctx, &rKey );
678     gpgme_op_keylist_end( ctx );
679     if ( GPGME_No_Error == err ) {
680       time_t expire_time = gpgme_key_get_ulong_attr(
681                              rKey,
682                              
683 ??????????????????????? GPGME_ATTR_EXPIRE,  ???????????????????????
684                              
685                              NULL, 0 );
686       time_t cur_time = time (NULL);
687       daysLeft = days_from_seconds(expire_time - cur_time);
688       gpgme_key_release( rKey );
689     }
690   }
691   gpgme_release( ctx );
692     
693    
694   // fprintf( stderr, "gpgmeplug caCertificateDaysLeftToExpiry returned %d\n", daysLeft );
695   return daysLeft;
696   */
697   
698   return 10; /* dummy that triggers a warning in the MUA */
699 }
700
701 void setCACertificateExpiryNearInterval( int interval )
702 {
703   config.cACertificateExpiryNearInterval = interval;
704 }
705
706 int caCertificateExpiryNearInterval( void )
707 {
708   return config.cACertificateExpiryNearInterval;
709 }
710
711 void setRootCertificateExpiryNearWarning( bool flag )
712 {
713   config.rootCertificateExpiryNearWarning = flag;
714 }
715
716 bool rootCertificateExpiryNearWarning( void )
717 {
718   return config.rootCertificateExpiryNearWarning;
719 }
720
721 int rootCertificateDaysLeftToExpiry( const char* certificate )
722 {
723     /* PENDING(g10)
724        Please return the number of days that are left until the
725        root certificate for the certificate specified in the parameter
726        certificate expires.
727     */
728   /*
729   GpgmeCtx ctx;
730   GpgmeError err;
731   GpgmeKey rKey;
732   time_t daysLeft = 0;
733
734   gpgme_new( &ctx );
735   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
736
737   err = gpgme_op_keylist_start( ctx, certificate, 0 );
738   if ( GPGME_No_Error == err ) {
739     err = gpgme_op_keylist_next( ctx, &rKey );
740     gpgme_op_keylist_end( ctx );
741     if ( GPGME_No_Error == err ) {
742       time_t expire_time = gpgme_key_get_ulong_attr(
743                              rKey,
744                              
745 ??????????????????????? GPGME_ATTR_EXPIRE,  ???????????????????????
746                              
747                              NULL, 0 );
748       time_t cur_time = time (NULL);
749       daysLeft = days_from_seconds(expire_time - cur_time);
750       gpgme_key_release( rKey );
751     }
752   }
753   gpgme_release( ctx );
754     
755    
756   // fprintf( stderr, "gpgmeplug rootCertificateDaysLeftToExpiry returned %d\n", daysLeft );
757   return daysLeft;
758   */
759   
760   return 10; /* dummy that triggers a warning in the MUA */
761 }
762
763
764 void setRootCertificateExpiryNearInterval( int interval )
765 {
766   config.rootCertificateExpiryNearInterval = interval;
767 }
768
769 int rootCertificateExpiryNearInterval( void )
770 {
771   return config.rootCertificateExpiryNearInterval;
772 }
773
774
775
776
777
778
779
780
781 const char* encryptionConfigurationDialog(){ return 0; }
782
783 const char* encryptionAlgorithmDialog(){ return 0; }
784
785 const char* encryptionHandlingDialog(){ return 0; }
786
787 const char* encryptionReceiverDialog(){ return 0; }
788
789 void setEncryptionAlgorithm( EncryptionAlgorithm cryptAlg )
790 {
791   config.encryptionAlgorithm = cryptAlg;
792 }
793
794 EncryptionAlgorithm encryptionAlgorithm()
795 {
796   return config.encryptionAlgorithm;
797 }
798
799 void setEncryptEmail( EncryptEmail cryptMode )
800 {
801   config.encryptEmail = cryptMode;
802 }
803
804 EncryptEmail encryptEmail()
805 {
806   return config.encryptEmail;
807 }
808
809
810
811
812
813
814 void setWarnSendUnencrypted( bool flag )
815 {
816   config.warnSendUnencrypted = flag;
817 }
818
819 bool warnSendUnencrypted()
820 {
821   return config.warnSendUnencrypted;
822 }
823
824
825
826
827
828
829
830
831
832 void setSaveMessagesEncrypted( bool flag )
833 {
834   config.saveMessagesEncrypted = flag;
835 }
836
837 bool saveMessagesEncrypted()
838 {
839   return config.saveMessagesEncrypted;
840 }
841
842
843
844
845
846
847
848 void setCheckCertificatePath( bool flag )
849 {
850   config.checkCertificatePath = flag;
851 }
852
853 bool checkCertificatePath()
854 {
855   return config.checkCertificatePath;
856 }
857
858
859
860
861
862
863
864
865 void setCheckEncryptionCertificatePathToRoot( bool flag )
866 {
867   config.checkEncryptionCertificatePathToRoot = flag;
868 }
869
870 bool checkEncryptionCertificatePathToRoot()
871 {
872   return config.checkEncryptionCertificatePathToRoot;
873 }
874
875
876
877
878
879
880
881 void setReceiverCertificateExpiryNearWarning( bool flag )
882 {
883   config.receiverCertificateExpiryNearWarning = flag;
884 }
885
886 bool receiverCertificateExpiryNearWarning()
887 {
888   return config.receiverCertificateExpiryNearWarning;
889 }
890
891
892 int receiverCertificateDaysLeftToExpiry( const char* certificate )
893 {
894   GpgmeCtx ctx;
895   GpgmeError err;
896   GpgmeKey rKey;
897   int daysLeft = CRYPTPLUG_CERT_DOES_NEVER_EXPIRE;
898
899   gpgme_new( &ctx );
900   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
901
902   err = gpgme_op_keylist_start( ctx, certificate, 0 );
903   if ( GPGME_No_Error == err ) {
904     err = gpgme_op_keylist_next( ctx, &rKey );
905     gpgme_op_keylist_end( ctx );
906     if ( GPGME_No_Error == err ) {
907       time_t expire_time = gpgme_key_get_ulong_attr(
908                              rKey,GPGME_ATTR_EXPIRE, NULL, 0 );
909       if ( 0 != expire_time ) {
910         time_t cur_time = time (NULL);
911         if( cur_time > expire_time ) {
912           daysLeft = days_from_seconds(cur_time - expire_time);
913           daysLeft *= -1;
914         }
915         else
916           daysLeft = days_from_seconds(expire_time - cur_time);
917       }
918       gpgme_key_release( rKey );
919     }
920   }
921   gpgme_release( ctx );
922     
923   /*
924   fprintf( stderr, "gpgmeplug receiverCertificateDaysLeftToExpiry returned %d\n", daysLeft );
925   */
926
927   return daysLeft;
928 }
929
930
931 void setReceiverCertificateExpiryNearWarningInterval( int interval )
932 {
933   config.receiverCertificateExpiryNearWarningInterval = interval;
934 }
935
936 int receiverCertificateExpiryNearWarningInterval()
937 {
938   return config.receiverCertificateExpiryNearWarningInterval;
939 }
940
941 void setCertificateInChainExpiryNearWarning( bool flag )
942 {
943   config.certificateInChainExpiryNearWarning = flag;
944 }
945
946 bool certificateInChainExpiryNearWarning()
947 {
948   return config.certificateInChainExpiryNearWarning;
949 }
950
951
952 int certificateInChainDaysLeftToExpiry( const char* certificate )
953 {
954     /* PENDING(g10)
955        Please return the number of days that are left until the
956        the first certificate in the chain of the specified certificate
957        expires.
958     */
959   return 10; /* dummy that triggers a warning in the MUA */
960 }
961
962
963 void setCertificateInChainExpiryNearWarningInterval( int interval )
964 {
965   config.certificateInChainExpiryNearWarningInterval = interval;
966 }
967
968 int certificateInChainExpiryNearWarningInterval()
969 {
970   return config.certificateInChainExpiryNearWarningInterval;
971 }
972
973 void setReceiverEmailAddressNotInCertificateWarning( bool flag )
974 {
975   config.receiverEmailAddressNotInCertificateWarning = flag;
976 }
977
978 bool receiverEmailAddressNotInCertificateWarning()
979 {
980   return config.receiverEmailAddressNotInCertificateWarning;
981 }
982
983
984
985
986
987
988
989
990 void setEncryptionUseCRLs( bool flag )
991 {
992   config.encryptionUseCRLs = flag;
993
994   /* PENDING(g10) Store this setting in gpgme and use it. If true,
995      every certificate used for encryption should be checked against
996      applicable CRLs.
997   */
998 }
999
1000 bool encryptionUseCRLs()
1001 {
1002   return config.encryptionUseCRLs;
1003 }
1004
1005
1006 int encryptionCRLsDaysLeftToExpiry()
1007 {
1008     /* PENDING(g10)
1009        Please return the number of days that are left until the
1010        CRL used for encryption expires.
1011     */
1012   return 10; /* dummy that triggers a warning in the MUA */
1013 }
1014
1015 void setEncryptionCRLExpiryNearWarning( bool flag )
1016 {
1017   config.encryptionCRLExpiryNearWarning = flag;
1018 }
1019
1020 bool encryptionCRLExpiryNearWarning()
1021 {
1022   return config.encryptionCRLExpiryNearWarning;
1023 }
1024
1025 void setEncryptionCRLNearExpiryInterval( int interval )
1026 {
1027   config.encryptionCRLNearExpiryInterval = interval;
1028 }
1029
1030 int encryptionCRLNearExpiryInterval()
1031 {
1032   return config.encryptionCRLNearExpiryInterval;
1033 }
1034
1035
1036 const char* directoryServiceConfigurationDialog(){ return 0; }
1037
1038 void appendDirectoryServer( const char* servername,
1039                             int         port,
1040                             const char* description )
1041 {
1042   struct DirectoryServer *newServers = NULL;
1043   newServers = realloc( config.directoryServers,
1044                         (1+config.numDirectoryServers) * sizeof *newServers );
1045   if( newServers ) {
1046     config.directoryServers = newServers;
1047     newServers[ config.numDirectoryServers ].servername =
1048       malloc( 1+strlen( servername ) );
1049     if( newServers[ config.numDirectoryServers ].servername ) {
1050       strcpy( (char *)newServers[ config.numDirectoryServers ].servername,
1051         servername );
1052       newServers[ config.numDirectoryServers ].description =
1053         malloc( 1+strlen(  description ) );
1054       if( newServers[ config.numDirectoryServers ].description ) {
1055         strcpy( (char *)newServers[ config.numDirectoryServers ].description,
1056           description );
1057         newServers[ config.numDirectoryServers ].port = port;
1058         config.numDirectoryServers += 1;
1059       }
1060     }
1061   }
1062 }
1063
1064 void setDirectoryServers( struct DirectoryServer server[], unsigned int size )
1065 {
1066   unsigned int i;
1067   int oldSize = config.numDirectoryServers;
1068   struct DirectoryServer *newServers = NULL;
1069   newServers = calloc ( size, sizeof *newServers );
1070   if( newServers ) {
1071     for( i=0; i < oldSize; ++i ) {
1072       free( (char *)config.directoryServers[i].servername );
1073       free( (char *)config.directoryServers[i].description );
1074     }
1075     free( config.directoryServers );
1076     for( i=0; i < size; ++i ) {
1077       newServers[ i ].servername = malloc( 1+strlen( server[i].servername ) );
1078       if( newServers[ i ].servername ) {
1079         strcpy( (char *)newServers[ i ].servername, server[i].servername );
1080         newServers[ i ].description = malloc( 1+strlen( server[i].description ) );
1081         if( newServers[ i ].description ) {
1082           strcpy( (char *)newServers[ i ].description, server[i].description );
1083           newServers[ i ].port = server[i].port;
1084         }
1085       }
1086     }
1087     config.directoryServers = newServers;
1088     config.numDirectoryServers = size;
1089   }
1090 }
1091
1092 struct DirectoryServer * directoryServers( int* numServers )
1093 {
1094   if( numServers )
1095     *numServers = config.numDirectoryServers;
1096   return config.directoryServers;
1097 };
1098
1099 void setCertificateSource( CertificateSource source )
1100 {
1101   config.certificateSource = source;
1102 }
1103
1104 CertificateSource certificateSource()
1105 {
1106   return config.certificateSource;
1107 }
1108
1109 void setCRLSource( CertificateSource source )
1110 {
1111   config.cRLSource = source;
1112 }
1113
1114 CertificateSource crlSource()
1115 {
1116   return config.cRLSource;
1117 }
1118
1119
1120 bool certificateValidity( const char* certificate,
1121                           int* level ){ return true; }
1122
1123
1124 void storeNewCharPtr( char** dest, const char* src )
1125 {
1126   int sLen = strlen( src );
1127   *dest = xmalloc( sLen + 1 );
1128   strcpy( *dest, src );
1129 }
1130
1131
1132 bool signMessage( const char*  cleartext,
1133                   char** ciphertext,
1134                   const size_t* cipherLen,
1135                   const char*  certificate,
1136                   struct StructuringInfo* structuring,
1137                   int* errId,
1138                   char** errTxt )
1139 {
1140   bool bIsOpaque;
1141   GpgmeCtx ctx;
1142   GpgmeError err;
1143   GpgmeKey rKey;
1144   GpgmeData data,  sig;
1145   char* rSig  = 0;
1146   bool  bOk   = false;
1147   int sendCerts = 1;
1148
1149   init_StructuringInfo( structuring );
1150
1151   if( !ciphertext )
1152     return false;
1153
1154   err = gpgme_new (&ctx);
1155   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1156
1157   gpgme_set_armor (ctx, __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ? 0 : 1);
1158   /*  gpgme_set_textmode (ctx, 1); */
1159
1160   switch ( config.sendCertificates ) {
1161     case SendCert_undef:
1162       break;
1163     case SendCert_DontSend:
1164       sendCerts = 0;
1165       break;
1166     case SendCert_SendOwn:
1167       sendCerts = 1;
1168       break;
1169     case SendCert_SendChainWithoutRoot:
1170       sendCerts = -2;
1171       break;
1172     case SendCert_SendChainWithRoot:
1173       sendCerts = -1;
1174       break;
1175     default:
1176       sendCerts = 0;
1177       break;
1178   }
1179   gpgme_set_include_certs (ctx, sendCerts);
1180
1181   /* select the signer's key if provided */
1182   if (certificate != 0) {
1183       err = gpgme_op_keylist_start(ctx, certificate, 0);
1184       while (err == GPGME_No_Error) {
1185           err = gpgme_op_keylist_next(ctx, &rKey);
1186           if (err == GPGME_No_Error) {
1187               unsigned long u;
1188               u = gpgme_key_get_ulong_attr(rKey, GPGME_ATTR_CAN_SIGN, 0, 0);
1189               if( u ) {
1190
1191 //                const char* s;
1192 //                s = gpgme_key_get_string_attr(rKey, GPGME_ATTR_FPR, 0, 0);
1193 //                fprintf( stderr, "gpgmeplug signMessage signing with key: %s\n", s );
1194
1195                   /* clear existing signers */
1196                   gpgme_signers_clear(ctx);
1197                   /* set the signing key */
1198                   gpgme_signers_add(ctx, rKey);
1199                   /* we only support one signer for now */
1200                   break;
1201               }
1202           }
1203       }
1204       gpgme_op_keylist_end(ctx);
1205   }
1206
1207   /* PENDING(g10) Implement this
1208
1209      gpgme_set_signature_algorithm( ctx, config.signatureAlgorithm )
1210      --> This does not make sense.  The algorithm is a property of
1211      the certificate used [wk 2002-03-23] */
1212
1213   gpgme_data_new_from_mem (&data, cleartext,
1214                             strlen( cleartext ), 1 );
1215   gpgme_data_new ( &sig );
1216
1217   /* NOTE: Currently we support Opaque signed messages only for S/MIME,
1218      but not for OpenPGP mode! */
1219   if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
1220     bIsOpaque = (SignatureCompoundMode_Opaque == signatureCompoundMode());
1221   else
1222     bIsOpaque = false;
1223
1224   err = gpgme_op_sign ( ctx,
1225                         data,
1226                         sig,
1227                         bIsOpaque
1228                         ? GPGME_SIG_MODE_NORMAL
1229                         : GPGME_SIG_MODE_DETACH );
1230
1231   if ( err == GPGME_No_Error ) {
1232     if( __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ) {
1233       *ciphertext = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen );
1234       bOk = true;
1235     }
1236     else {
1237       rSig = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen );
1238       *ciphertext = malloc( *cipherLen + 1 );
1239       if( *ciphertext ) {
1240         if( *cipherLen ) {
1241           bOk = true;
1242           strncpy((char*)*ciphertext, rSig, *cipherLen );
1243         }
1244         (*ciphertext)[*cipherLen] = '\0';
1245       }
1246       free( rSig );
1247     }
1248   }
1249   else {
1250     gpgme_data_release( sig );
1251 /*
1252 *ciphertext = malloc( 70 );
1253 strcpy((char*)*ciphertext, "xyz\nsig-dummy\nzyx" );
1254 (*ciphertext)[17] = '\0';
1255 err = 0;
1256 {
1257 */
1258     *ciphertext = 0;
1259     fprintf( stderr, "\n\n    gpgme_op_sign() returned this error code:  %i\n\n", err );
1260     if( errId )
1261       *errId = err;
1262     if( errTxt ) {
1263       const char* _errTxt = gpgme_strerror( err );
1264       *errTxt = malloc( strlen( _errTxt ) + 1 );
1265       if( *errTxt )
1266         strcpy(*errTxt, _errTxt );
1267     }
1268 /*
1269 }
1270 */
1271   }
1272   gpgme_data_release( data );
1273   gpgme_release (ctx);
1274
1275   if( bOk && structuring ) {
1276     if( bIsOpaque ) {
1277       structuring->includeCleartext = GPGMEPLUG_OPA_SIGN_INCLUDE_CLEARTEXT;
1278       structuring->makeMimeObject   = GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT;
1279       if( structuring->makeMimeObject ) {
1280         structuring->makeMultiMime  = GPGMEPLUG_OPA_SIGN_MAKE_MULTI_MIME;
1281         storeNewCharPtr( &structuring->contentTypeMain,
1282                         GPGMEPLUG_OPA_SIGN_CTYPE_MAIN );
1283         storeNewCharPtr( &structuring->contentDispMain,
1284                         GPGMEPLUG_OPA_SIGN_CDISP_MAIN );
1285         storeNewCharPtr( &structuring->contentTEncMain,
1286                         GPGMEPLUG_OPA_SIGN_CTENC_MAIN );
1287         if( structuring->makeMultiMime ) {
1288             storeNewCharPtr( &structuring->contentTypeVersion,
1289                             GPGMEPLUG_OPA_SIGN_CTYPE_VERSION );
1290             storeNewCharPtr( &structuring->contentDispVersion,
1291                             GPGMEPLUG_OPA_SIGN_CDISP_VERSION );
1292             storeNewCharPtr( &structuring->contentTEncVersion,
1293                             GPGMEPLUG_OPA_SIGN_CTENC_VERSION );
1294             storeNewCharPtr( &structuring->bodyTextVersion,
1295                             GPGMEPLUG_OPA_SIGN_BTEXT_VERSION );
1296             storeNewCharPtr( &structuring->contentTypeCode,
1297                             GPGMEPLUG_OPA_SIGN_CTYPE_CODE );
1298             storeNewCharPtr( &structuring->contentDispCode,
1299                             GPGMEPLUG_OPA_SIGN_CDISP_CODE );
1300             storeNewCharPtr( &structuring->contentTEncCode,
1301                             GPGMEPLUG_OPA_SIGN_CTENC_CODE );
1302         }
1303       } else {
1304         storeNewCharPtr( &structuring->flatTextPrefix,
1305                         GPGMEPLUG_OPA_SIGN_FLAT_PREFIX );
1306         storeNewCharPtr( &structuring->flatTextSeparator,
1307                         GPGMEPLUG_OPA_SIGN_FLAT_SEPARATOR );
1308         storeNewCharPtr( &structuring->flatTextPostfix,
1309                         GPGMEPLUG_OPA_SIGN_FLAT_POSTFIX );
1310       }
1311     } else {
1312       structuring->includeCleartext = GPGMEPLUG_DET_SIGN_INCLUDE_CLEARTEXT;
1313       structuring->makeMimeObject   = GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT;
1314       if( structuring->makeMimeObject ) {
1315         structuring->makeMultiMime  = GPGMEPLUG_DET_SIGN_MAKE_MULTI_MIME;
1316         storeNewCharPtr( &structuring->contentTypeMain,
1317                         GPGMEPLUG_DET_SIGN_CTYPE_MAIN );
1318         storeNewCharPtr( &structuring->contentDispMain,
1319                         GPGMEPLUG_DET_SIGN_CDISP_MAIN );
1320         storeNewCharPtr( &structuring->contentTEncMain,
1321                         GPGMEPLUG_DET_SIGN_CTENC_MAIN );
1322         if( structuring->makeMultiMime ) {
1323             storeNewCharPtr( &structuring->contentTypeVersion,
1324                             GPGMEPLUG_DET_SIGN_CTYPE_VERSION );
1325             storeNewCharPtr( &structuring->contentDispVersion,
1326                             GPGMEPLUG_DET_SIGN_CDISP_VERSION );
1327             storeNewCharPtr( &structuring->contentTEncVersion,
1328                             GPGMEPLUG_DET_SIGN_CTENC_VERSION );
1329             storeNewCharPtr( &structuring->bodyTextVersion,
1330                             GPGMEPLUG_DET_SIGN_BTEXT_VERSION );
1331             storeNewCharPtr( &structuring->contentTypeCode,
1332                             GPGMEPLUG_DET_SIGN_CTYPE_CODE );
1333             storeNewCharPtr( &structuring->contentDispCode,
1334                             GPGMEPLUG_DET_SIGN_CDISP_CODE );
1335             storeNewCharPtr( &structuring->contentTEncCode,
1336                             GPGMEPLUG_DET_SIGN_CTENC_CODE );
1337         }
1338       } else {
1339         storeNewCharPtr( &structuring->flatTextPrefix,
1340                         GPGMEPLUG_DET_SIGN_FLAT_PREFIX );
1341         storeNewCharPtr( &structuring->flatTextSeparator,
1342                         GPGMEPLUG_DET_SIGN_FLAT_SEPARATOR );
1343         storeNewCharPtr( &structuring->flatTextPostfix,
1344                         GPGMEPLUG_DET_SIGN_FLAT_POSTFIX );
1345       }
1346     }
1347   }
1348   return bOk;
1349 }
1350
1351
1352
1353 bool storeCertificatesFromMessage(
1354         const char* ciphertext ){ return true; }
1355
1356
1357 /* returns address if address doesn't contain a <xxx> part
1358  * else it returns a new string xxx and frees address
1359  */
1360 static char* parseAddress( char* address )
1361 {
1362   char* result = address;
1363   char* i;
1364   char* j;
1365   if( !result ) return result;
1366   i = index( address, '<' );
1367   if( i ) {
1368     j = index( i+1, '>' );
1369     if( j == NULL ) j = address+strlen(address);
1370     result = xmalloc( j-i );
1371     strncpy( result, i+1, j-i-1 );
1372     result[j-i-1] = '\0';
1373     free( address );
1374   } else {
1375     i = address;
1376     j = i+strlen(address);
1377   }
1378   {
1379     /* remove surrounding whitespace */
1380     char* k = result+(j-i-1);
1381     char* l = result;
1382     while( isspace( *l ) ) ++l;
1383     while( isspace( *k ) ) --k;
1384     if( l != result || k != result+(j-i-1) ) {
1385       char* result2 = xmalloc( k-l+2 );
1386       strncpy( result2, l, k-l+1 );
1387       result2[k-l+1] = '\0';
1388       free(result);
1389       result = result2;
1390     }
1391   }
1392   return result;
1393 }
1394
1395 static char* nextAddress( const char** address )
1396 {
1397   const char *start = *address;
1398   char* result = NULL;
1399   int quote = 0;
1400   int comment = 0;
1401   int found = 0;
1402   if( *address == NULL ) return NULL;
1403   while( **address ) {
1404
1405     switch( **address ) {
1406     case '\\': /* escaped character */
1407       ++(*address);
1408       break;
1409     case '"':
1410       if( comment == 0 ) {
1411         if( quote > 0 ) --quote;
1412         else ++quote;
1413       }
1414       break;
1415     case '(': /* comment start */
1416       if( quote == 0 ) ++comment;
1417       break;
1418     case ')': /* comment end */
1419       if( quote == 0 ) --comment;
1420       break;
1421     case '\0':
1422     case '\1': /* delimiter */
1423       if( quote == 0 && comment == 0 ) {
1424         found = 1;
1425       }
1426       break;
1427     }
1428     ++(*address);
1429     if( found ) break;
1430   }
1431   if( found || **address == 0 ) {
1432     size_t len;
1433     len = *address - start;
1434     if( len > 0 ) {
1435       if( **address != 0 ) --len;
1436       result = xmalloc( len*sizeof(char)+1 );
1437       strncpy( result, start, len );
1438       result[len] = '\0';
1439     }
1440   }
1441   return parseAddress(result);
1442 }
1443
1444 bool encryptMessage( const char*  cleartext,
1445                      const char** ciphertext,
1446                      const size_t* cipherLen,
1447                      const char*  certificate,
1448                      struct StructuringInfo* structuring,
1449                      int* errId,
1450                      char** errTxt )
1451 {
1452   GpgmeCtx ctx;
1453   GpgmeError err;
1454   GpgmeData gCiphertext, gPlaintext;
1455   GpgmeRecipients rset;
1456   char*  rCiph = 0;
1457   bool   bOk   = false;
1458
1459   init_StructuringInfo( structuring );
1460
1461   gpgme_new (&ctx);
1462   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1463
1464   gpgme_set_armor (ctx, __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ? 0 : 1);
1465   /*  gpgme_set_textmode (ctx, 1); */
1466
1467   gpgme_data_new_from_mem (&gPlaintext, cleartext,
1468                             1+strlen( cleartext ), 1 );
1469   err = gpgme_data_new ( &gCiphertext );
1470
1471   gpgme_recipients_new (&rset);
1472
1473   /*
1474   if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
1475   {
1476     gpgme_recipients_add_name (rset,
1477       "/CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=DÃ?sseldorf,C=DE" );
1478
1479     fputs( "\nGPGSMPLUG encryptMessage() using test key of Aegypten Project\n", stderr );
1480   }
1481   else
1482   */
1483   {
1484     const char* p = certificate;
1485     char* tok;
1486     while( (tok = nextAddress( &p ) ) != 0 ) {
1487       gpgme_recipients_add_name (rset, tok );
1488       fprintf( stderr, "\nGPGMEPLUG encryptMessage() using addressee %s\n", tok );
1489       free(tok);
1490     }
1491   }
1492
1493   /* PENDING(g10) Implement this
1494      Possible values: RSA = 1, SHA1 = 2, TripleDES = 3
1495      gpgme_set_encryption_algorithm( ctx, config.encryptionAlgorithm );
1496
1497      -> Your are mixing public key and symmetric algorithms.  The
1498      latter may be configured but the sphix specifications do opnly
1499      allow 3-DES so this is not nothing we need to do.  The proper way
1500      to select the symmetric algorithm is anyway by looking at the
1501      capabilities of the certificate because this is the only way to
1502      know what the recipient can accept. [wk 2002-03-23]
1503
1504      PENDING(g10) Implement this
1505      gpgme_set_encryption_check_certificate_path(
1506      config.checkCertificatePath )
1507
1508      PENDING(g10) Implement this
1509      gpgme_set_encryption_check_certificate_path_to_root(
1510      config.checkEncryptionCertificatePathToRoot )
1511
1512      -> Not checking a certificate up to the ROOT CA is dangerous and
1513      stupid. There is no need for those options.  [wk 2002-03-23] */
1514
1515
1516
1517   err = gpgme_op_encrypt (ctx, rset, gPlaintext, gCiphertext );
1518   if( err ) {
1519     fprintf( stderr, "\ngpgme_op_encrypt() returned this error code:  %i\n", err );
1520     if( errId )
1521       *errId = err;
1522     if( errTxt ) {
1523       const char* _errTxt = gpgme_strerror( err );
1524       *errTxt = malloc( strlen( _errTxt ) + 100 ); // leave room for reason string
1525       if( *errTxt ) {
1526         char* opInfo;
1527         strcpy(*errTxt, _errTxt );
1528         opInfo = gpgme_get_op_info(ctx, 0);
1529         if( NULL != opInfo && *opInfo ){
1530           const int opLen = strlen( opInfo );
1531           const int reasonLen = 8;
1532           char reason[ 1+reasonLen ];
1533           char* pos1;
1534           strcpy( reason, "<reason>" );
1535           pos1 = strstr( opInfo, reason );
1536           if( NULL != pos1 && 
1537               opLen > reasonLen + (pos1 - opInfo) ){
1538             char* pos2;
1539             pos1 += reasonLen;
1540             pos2 = strchr( pos1, '<' );
1541             if( NULL != pos2 &&
1542                 pos1 < pos2 ){
1543               long int reasonId;
1544               strcat( *errTxt, " - " );
1545               *pos2 = '\0';
1546               fprintf( stderr, "                        and this reason code:  %s\n\n", pos1 );
1547               reasonId = strtol( pos1, NULL, 10 );
1548               switch( reasonId ) {
1549                 case  0: strcat( *errTxt, "No specific reason given" );
1550                          break;
1551                 case  1: strcat( *errTxt, "Not Found" );
1552                          break;
1553                 case  2: strcat( *errTxt, "Ambigious specification" );
1554                          break;
1555                 case  3: strcat( *errTxt, "Key can't be used for operation" );
1556                          break;
1557                 case  4: strcat( *errTxt, "Key has been revoked" );
1558                          break;
1559                 case  5: strcat( *errTxt, "Key has expired" );
1560                          break;
1561                 case  6: strcat( *errTxt, "No CRL known for certificate" );
1562                          break;
1563                 case  7: strcat( *errTxt, "No current CRL available" );
1564                          break;
1565                 case  8: strcat( *errTxt, "Contraints not matched" );
1566                          break;
1567                 default: {
1568                            strcat( *errTxt, "Extended error Id: #" );
1569                            strcat( *errTxt, pos1 );
1570                          }  
1571               }
1572               *pos2 = '<';
1573             }
1574           }
1575           free( opInfo );
1576         }
1577       }
1578     }
1579   }
1580
1581   gpgme_recipients_release (rset);
1582   gpgme_data_release (gPlaintext);
1583
1584   if( err == GPGME_No_Error ) {
1585     if( __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ) {
1586       *ciphertext = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1587       bOk = true;
1588     }
1589     else {
1590       rCiph = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1591       *ciphertext = malloc( *cipherLen + 1 );
1592       if( *ciphertext ) {
1593         if( *cipherLen ) {
1594           bOk = true;
1595           strncpy((char*)*ciphertext, rCiph, *cipherLen );
1596         }
1597         ((char*)(*ciphertext))[*cipherLen] = 0;
1598       }
1599       free( rCiph );
1600     }
1601   }
1602   else {
1603     gpgme_data_release ( gCiphertext );
1604     *ciphertext = 0;
1605     /* error handling is missing: if only one untrusted key was found
1606       (or none at all), gpg won't sign the message.  (hier fehlt eine
1607       Fehlerbehandlung: fuer einen Recipient nur ein untrusted key
1608       (oder gar keiner) gefunden wurde, verweigert gpg das signieren.)
1609     */
1610   }
1611
1612   gpgme_release (ctx);
1613
1614   fflush( stderr );
1615
1616   if( bOk && structuring ) {
1617     structuring->includeCleartext = GPGMEPLUG_ENC_INCLUDE_CLEARTEXT;
1618     structuring->makeMimeObject   = GPGMEPLUG_ENC_MAKE_MIME_OBJECT;
1619     if( structuring->makeMimeObject ) {
1620       structuring->makeMultiMime  = GPGMEPLUG_ENC_MAKE_MULTI_MIME;
1621       storeNewCharPtr( &structuring->contentTypeMain,
1622                        GPGMEPLUG_ENC_CTYPE_MAIN );
1623       storeNewCharPtr( &structuring->contentDispMain,
1624                        GPGMEPLUG_ENC_CDISP_MAIN );
1625       storeNewCharPtr( &structuring->contentTEncMain,
1626                        GPGMEPLUG_ENC_CTENC_MAIN );
1627       if( structuring->makeMultiMime ) {
1628         storeNewCharPtr( &structuring->contentTypeVersion,
1629                          GPGMEPLUG_ENC_CTYPE_VERSION );
1630         storeNewCharPtr( &structuring->contentDispVersion,
1631                          GPGMEPLUG_ENC_CDISP_VERSION );
1632         storeNewCharPtr( &structuring->contentTEncVersion,
1633                          GPGMEPLUG_ENC_CTENC_VERSION );
1634         storeNewCharPtr( &structuring->bodyTextVersion,
1635                          GPGMEPLUG_ENC_BTEXT_VERSION );
1636         storeNewCharPtr( &structuring->contentTypeCode,
1637                          GPGMEPLUG_ENC_CTYPE_CODE );
1638         storeNewCharPtr( &structuring->contentDispCode,
1639                          GPGMEPLUG_ENC_CDISP_CODE );
1640         storeNewCharPtr( &structuring->contentTEncCode,
1641                          GPGMEPLUG_ENC_CTENC_CODE );
1642       }
1643     } else {
1644       storeNewCharPtr( &structuring->flatTextPrefix,
1645                        GPGMEPLUG_ENC_FLAT_PREFIX );
1646       storeNewCharPtr( &structuring->flatTextSeparator,
1647                        GPGMEPLUG_ENC_FLAT_SEPARATOR );
1648       storeNewCharPtr( &structuring->flatTextPostfix,
1649                        GPGMEPLUG_ENC_FLAT_POSTFIX );
1650     }
1651   }
1652   return bOk;
1653 }
1654
1655
1656 bool encryptAndSignMessage( const char* cleartext,
1657                             const char** ciphertext,
1658                             const char* certificate,
1659                             struct StructuringInfo* structuring )
1660 {
1661   bool bOk;
1662
1663   init_StructuringInfo( structuring );
1664
1665   bOk = false;
1666
1667   /* implementation of this function is still missing */
1668
1669   if( bOk && structuring ) {
1670     structuring->includeCleartext = GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT;
1671     structuring->makeMimeObject   = GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT;
1672     if( structuring->makeMimeObject ) {
1673       structuring->makeMultiMime  = GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME;
1674       storeNewCharPtr( &structuring->contentTypeMain,
1675                        GPGMEPLUG_ENCSIGN_CTYPE_MAIN );
1676       storeNewCharPtr( &structuring->contentDispMain,
1677                        GPGMEPLUG_ENCSIGN_CDISP_MAIN );
1678       storeNewCharPtr( &structuring->contentTEncMain,
1679                        GPGMEPLUG_ENCSIGN_CTENC_MAIN );
1680       if( structuring->makeMultiMime ) {
1681         storeNewCharPtr( &structuring->contentTypeVersion,
1682                          GPGMEPLUG_ENCSIGN_CTYPE_VERSION );
1683         storeNewCharPtr( &structuring->contentDispVersion,
1684                          GPGMEPLUG_ENCSIGN_CDISP_VERSION );
1685         storeNewCharPtr( &structuring->contentTEncVersion,
1686                          GPGMEPLUG_ENCSIGN_CTENC_VERSION );
1687         storeNewCharPtr( &structuring->bodyTextVersion,
1688                          GPGMEPLUG_ENCSIGN_BTEXT_VERSION );
1689         storeNewCharPtr( &structuring->contentTypeCode,
1690                          GPGMEPLUG_ENCSIGN_CTYPE_CODE );
1691         storeNewCharPtr( &structuring->contentDispCode,
1692                          GPGMEPLUG_ENCSIGN_CDISP_CODE );
1693         storeNewCharPtr( &structuring->contentTEncCode,
1694                          GPGMEPLUG_ENCSIGN_CTENC_CODE );
1695       }
1696     } else {
1697       storeNewCharPtr( &structuring->flatTextPrefix,
1698                        GPGMEPLUG_ENCSIGN_FLAT_PREFIX );
1699       storeNewCharPtr( &structuring->flatTextSeparator,
1700                        GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR );
1701       storeNewCharPtr( &structuring->flatTextPostfix,
1702                        GPGMEPLUG_ENCSIGN_FLAT_POSTFIX );
1703     }
1704   }
1705   return bOk;
1706 }
1707
1708
1709 bool decryptMessage( const char* ciphertext,
1710                      bool        cipherIsBinary,
1711                      int         cipherLen,
1712                      const char** cleartext,
1713                      const char* certificate,
1714                      int* errId,
1715                      char** errTxt )
1716 {
1717   GpgmeCtx ctx;
1718   GpgmeError err;
1719   GpgmeData gCiphertext, gPlaintext;
1720   size_t rCLen = 0;
1721   char*  rCiph = 0;
1722   bool bOk = false;
1723
1724   if( !ciphertext )
1725     return false;
1726
1727   err = gpgme_new (&ctx);
1728   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1729   
1730   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
1731   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
1732
1733   /*
1734   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
1735                            1+strlen( ciphertext ), 1 ); */
1736   gpgme_data_new_from_mem( &gCiphertext,
1737                            ciphertext,
1738                            cipherIsBinary
1739                            ? cipherLen
1740                            : strlen( ciphertext ),
1741                            1 );
1742
1743   gpgme_data_new( &gPlaintext );
1744
1745   err = err = gpgme_op_decrypt( ctx, gCiphertext, gPlaintext );
1746   if( err ) {
1747     fprintf( stderr, "\ngpgme_op_decrypt() returned this error code:  %i\n\n", err );
1748     if( errId )
1749       *errId = err;
1750     if( errTxt ) {
1751       const char* _errTxt = gpgme_strerror( err );
1752       *errTxt = malloc( strlen( _errTxt ) + 1 );
1753       if( *errTxt )
1754         strcpy(*errTxt, _errTxt );
1755     }
1756   }
1757   
1758   gpgme_data_release( gCiphertext );
1759
1760   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
1761
1762   *cleartext = malloc( rCLen + 1 );
1763   if( *cleartext ) {
1764       if( rCLen ) {
1765           bOk = true;
1766           strncpy((char*)*cleartext, rCiph, rCLen );
1767       }
1768       ((char*)(*cleartext))[rCLen] = 0;
1769   }
1770
1771   free( rCiph );
1772   gpgme_release( ctx );
1773   return bOk;
1774 }
1775
1776
1777 const char* requestCertificateDialog(){ return 0; }
1778
1779
1780 /* The buffer generatedKey contains the LEN bytes you want.
1781    Caller is responsible for freeing. */
1782 bool requestDecentralCertificate( const char* certparms, 
1783                                   char** generatedKey, int* length )
1784 {
1785     GpgmeError err;
1786     GpgmeCtx ctx;
1787     GpgmeData pub;
1788     int len;
1789
1790     err = gpgme_data_new (&pub);
1791     fprintf( stderr,  "1: gpgme returned %d\n", err );
1792     if( err != GPGME_No_Error )
1793         return false;
1794
1795     err = gpgme_new (&ctx);
1796     fprintf( stderr,  "2: gpgme returned %d\n", err );
1797     if( err != GPGME_No_Error ) {
1798         gpgme_data_release( pub );
1799         return false;
1800     }
1801
1802     gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
1803     /* Don't ASCII-armor, the MUA will use base64 encoding */
1804     /*    gpgme_set_armor (ctx, 1); */
1805     err = gpgme_op_genkey (ctx, certparms, pub, NULL, NULL);
1806     fprintf( stderr,  "3: gpgme returned %d\n", err );
1807     if( err != GPGME_No_Error ) {
1808         gpgme_data_release( pub );
1809         gpgme_release( ctx );
1810         return false;
1811     }
1812
1813     gpgme_release (ctx);
1814     *generatedKey = gpgme_data_release_and_get_mem (pub, &len);
1815     *length = len;
1816
1817     return true;
1818 }
1819
1820 bool requestCentralCertificateAndPSE( const char* name,
1821           const char* email, const char* organization, const char* department,
1822           const char* ca_address ){ return true; }
1823
1824 bool createPSE(){ return true; }
1825
1826 bool registerCertificate( const char* certificate ){ return true; }
1827
1828 bool requestCertificateProlongation( const char* certificate,
1829                                      const char* ca_address ){ return true; }
1830
1831 const char* certificateChain(){ return 0; }
1832
1833 bool deleteCertificate( const char* certificate ){ return true; }
1834
1835 bool archiveCertificate( const char* certificate ){ return true; }
1836
1837
1838 const char* displayCRL(){ return 0; }
1839
1840 void updateCRL(){}
1841
1842
1843 char *
1844 trim_trailing_spaces( char *string )
1845 {
1846     char *p, *mark;
1847
1848     for( mark = NULL, p = string; *p; p++ ) {
1849         if( isspace( *p ) ) {
1850             if( !mark )
1851                 mark = p;
1852         }
1853         else
1854             mark = NULL;
1855     }
1856     if( mark )
1857         *mark = '\0' ;
1858
1859     return string ;
1860 }
1861
1862 /* Parse a DN and return an array-ized one.  This is not a validating
1863    parser and it does not support any old-stylish syntax; gpgme is
1864    expected to return only rfc2253 compatible strings. */
1865 static const unsigned char *
1866 parse_dn_part (struct DnPair *array, const unsigned char *string)
1867 {
1868   const unsigned char *s, *s1;
1869   size_t n;
1870   unsigned char *p;
1871
1872   /* parse attributeType */
1873   for (s = string+1; *s && *s != '='; s++)
1874     ;
1875   if (!*s)
1876     return NULL; /* error */
1877   n = s - string;
1878   if (!n)
1879     return NULL; /* empty key */
1880   array->key = p = xmalloc (n+1);
1881   
1882   
1883   memcpy (p, string, n);
1884   p[n] = 0;
1885   trim_trailing_spaces (p);
1886   if ( !strcmp (p, "1.2.840.113549.1.9.1") )
1887     strcpy (p, "EMail");
1888   string = s + 1;
1889
1890   if (*string == '#')
1891     { /* hexstring */
1892       string++;
1893       for (s=string; hexdigitp (s); s++)
1894         s++;
1895       n = s - string;
1896       if (!n || (n & 1))
1897         return NULL; /* empty or odd number of digits */
1898       n /= 2;
1899       array->value = p = xmalloc (n+1);
1900       
1901       
1902       for (s1=string; n; s1 += 2, n--)
1903         *p++ = xtoi_2 (s1);
1904       *p = 0;
1905    }
1906   else
1907     { /* regular v3 quoted string */
1908       for (n=0, s=string; *s; s++)
1909         {
1910           if (*s == '\\')
1911             { /* pair */
1912               s++;
1913               if (*s == ',' || *s == '=' || *s == '+'
1914                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
1915                   || *s == '\\' || *s == '\"' || *s == ' ')
1916                 n++;
1917               else if (hexdigitp (s) && hexdigitp (s+1))
1918                 {
1919                   s++;
1920                   n++;
1921                 }
1922               else
1923                 return NULL; /* invalid escape sequence */
1924             }
1925           else if (*s == '\"')
1926             return NULL; /* invalid encoding */
1927           else if (*s == ',' || *s == '=' || *s == '+'
1928                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
1929             break; 
1930           else
1931             n++;
1932         }
1933
1934       array->value = p = xmalloc (n+1);
1935       
1936       
1937       for (s=string; n; s++, n--)
1938         {
1939           if (*s == '\\')
1940             { 
1941               s++;
1942               if (hexdigitp (s))
1943                 {
1944                   *p++ = xtoi_2 (s);
1945                   s++;
1946                 }
1947               else
1948                 *p++ = *s;
1949             }
1950           else
1951             *p++ = *s;
1952         }
1953       *p = 0;
1954     }
1955   return s;
1956 }
1957
1958
1959 /* Parse a DN and return an array-ized one.  This is not a validating
1960    parser and it does not support any old-stylish syntax; gpgme is
1961    expected to return only rfc2253 compatible strings. */
1962 static struct DnPair *
1963 parse_dn (const unsigned char *string)
1964 {
1965   struct DnPair *array;
1966   size_t arrayidx, arraysize;
1967   int i;
1968
1969   if( !string )
1970     return NULL;
1971
1972   arraysize = 7; /* C,ST,L,O,OU,CN,email */
1973   arrayidx = 0;
1974   array = xmalloc ((arraysize+1) * sizeof *array);
1975   
1976   
1977   while (*string)
1978     {
1979       while (*string == ' ')
1980         string++;
1981       if (!*string)
1982         break; /* ready */
1983       if (arrayidx >= arraysize)
1984         { /* mutt lacks a real safe_realoc - so we need to copy */
1985           struct DnPair *a2;
1986
1987           arraysize += 5;
1988           a2 = xmalloc ((arraysize+1) * sizeof *array);
1989           for (i=0; i < arrayidx; i++)
1990             {
1991               a2[i].key = array[i].key;
1992               a2[i].value = array[i].value;
1993             }
1994           free (array);
1995           array = a2;
1996         }
1997       array[arrayidx].key = NULL;
1998       array[arrayidx].value = NULL;
1999       string = parse_dn_part (array+arrayidx, string);
2000       arrayidx++;
2001       if (!string)
2002         goto failure;
2003       while (*string == ' ')
2004         string++;
2005       if (*string && *string != ',' && *string != ';' && *string != '+')
2006         goto failure; /* invalid delimiter */
2007       if (*string)
2008         string++;
2009     }
2010   array[arrayidx].key = NULL;
2011   array[arrayidx].value = NULL;
2012   return array;
2013
2014  failure:
2015   for (i=0; i < arrayidx; i++)
2016     {
2017       free (array[i].key);
2018       free (array[i].value);
2019     }
2020   free (array);
2021   return NULL;
2022 }
2023
2024 static int 
2025 add_dn_part( char* result, struct DnPair* dn, const char* part )
2026 {
2027   int any = 0;
2028
2029   if( dn ) {
2030     for(; dn->key; ++dn ) {
2031       if( !strcmp( dn->key, part ) ) {
2032         if( any ) strcat( result, "+" );
2033         /* email hack */
2034         if( !strcmp( part, "1.2.840.113549.1.9.1" ) ) strcat( result, "EMail" );
2035         else strcat( result, part );
2036         strcat( result, "=" );
2037         strcat( result, dn->value );
2038         any = 1;
2039       }
2040     }
2041   }
2042   return any;
2043 }
2044
2045 static char* 
2046 reorder_dn( struct DnPair *dn )
2047 {
2048   /* note: The must parts are: CN, L, OU, O, C */
2049   const char* stdpart[] = {
2050     "CN", "S", "SN", "GN", "T", "UID",
2051           "MAIL", "EMAIL", "MOBILE", "TEL", "FAX", "STREET",
2052     "L",  "PC", "SP", "ST",
2053     "OU",
2054     "O",
2055     "C",
2056     NULL
2057   };
2058   int any=0, any2=0, len=0, i;
2059   char* result;
2060   if( dn ) {
2061     for( i = 0; dn[i].key; ++i ) {
2062       len += strlen( dn[i].key );
2063       len += strlen( dn[i].value );
2064       len += 4; /* ',' and '=', and possibly "(" and ")" */
2065     }
2066   }
2067   result = xmalloc( (len+1)*sizeof(char) );
2068   *result = 0;
2069
2070   /* add standard parts */
2071   for( i = 0; stdpart[i]; ++i ) {
2072     if( any ) {
2073       strcat( result, "," );
2074     }
2075     any = add_dn_part( result, dn, stdpart[i] );
2076   }
2077
2078   /* add remaining parts in no particular order */
2079   if( dn ) {
2080     for(; dn->key; ++dn ) {
2081       for( i = 0; stdpart[i]; ++i ) {
2082         if( !strcmp( dn->key, stdpart[i] ) ) {
2083           break;
2084         }
2085       }
2086       if( !stdpart[i] ) {
2087         if( any ) strcat( result, "," );
2088         if( !any2 ) strcat( result, "(");
2089         any = add_dn_part( result, dn, dn->key );
2090         any2 = 1;
2091       }
2092     }
2093   }
2094   if( any2 ) strcat( result, ")");
2095   return result;
2096 }
2097
2098 struct CertIterator {
2099   GpgmeCtx ctx;  
2100   struct CertificateInfo info;
2101 };
2102
2103 struct CertIterator* 
2104 startListCertificates( const char* pattern, int remote )
2105 {
2106     GpgmeError err;
2107     struct CertIterator* it;
2108     const char* patterns[] = { pattern, NULL };
2109     fprintf( stderr,  "startListCertificates( \"%s\", %d )\n", pattern, remote );
2110
2111     it = xmalloc( sizeof( struct CertIterator ) );
2112
2113     err = gpgme_new (&(it->ctx));
2114     /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2115     if( err != GPGME_No_Error ) {
2116       free( it );
2117       return NULL;
2118     }
2119
2120     gpgme_set_protocol (it->ctx, GPGME_PROTOCOL_CMS);
2121     if( remote ) gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_EXTERN ); 
2122     else gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_LOCAL );
2123     err =  gpgme_op_keylist_ext_start ( it->ctx, patterns, 0, 0);
2124     if( err != GPGME_No_Error ) {
2125       fprintf( stderr,  "gpgme_op_keylist_ext_start returned %d", err );
2126       endListCertificates( it );
2127       return NULL;
2128     }
2129     memset( &(it->info), 0, sizeof( struct CertificateInfo ) );
2130     return it;
2131 }
2132
2133 /* free() each string in a char*[] and the array itself */
2134 static void 
2135 freeStringArray( char** c )
2136 {
2137     char** _c = c;
2138
2139     while( c && *c ) {
2140       /*fprintf( stderr, "freeing \"%s\"\n", *c );*/
2141       free( *c );
2142       ++c;
2143     }
2144     free( _c );
2145 }
2146
2147 /* free all malloc'ed data in a struct CertificateInfo */
2148 static void 
2149 freeInfo( struct CertificateInfo* info )
2150 {
2151   struct DnPair* a = info->dnarray;
2152   assert( info );
2153   freeStringArray( info->userid );
2154   free( info->serial);
2155   free( info->fingerprint );
2156   free( info->issuer );
2157   free( info->chainid );
2158   free( info->caps );
2159   while( a && a->key && a->value ) {
2160     free (a->key);
2161     free (a->value);
2162     ++a;
2163   }
2164   free (info->dnarray);
2165   memset( info, 0, sizeof( *info ) );
2166 }
2167
2168 /* Format the fingerprint nicely. The caller should
2169    free the returned value using free() */
2170 static char* make_fingerprint( const char* fpr )
2171 {
2172   int len = strlen(fpr);
2173   int i = 0;
2174   char* result = xmalloc( (len + len/2 + 1)*sizeof(char) );
2175
2176   for(; *fpr; ++fpr, ++i ) {
2177     if( i%3 == 2) {
2178       result[i] = ':'; ++i;
2179     }
2180     result[i] = *fpr;
2181   }
2182   result[i] = 0;
2183   return result;
2184 }
2185
2186 int 
2187 nextCertificate( struct CertIterator* it, struct CertificateInfo** result )
2188 {
2189   GpgmeError err;
2190   GpgmeKey   key;
2191   int retval = GPGME_No_Error;
2192   assert( it );
2193   fprintf( stderr,  "nextCertificates( %p, %p )\n", it, result );
2194   err = gpgme_op_keylist_next ( it->ctx, &key);
2195   if( err != GPGME_EOF ) {   
2196     int idx;
2197     const char* s;
2198     unsigned long u;
2199     char* names[MAX_GPGME_IDX+1];
2200     struct DnPair *issuer_dn, *tmp_dn;
2201     retval = err;
2202     memset( names, 0, sizeof( names ) );
2203     freeInfo( &(it->info) );
2204
2205     for( idx = 0; (s = gpgme_key_get_string_attr (key, GPGME_ATTR_USERID, 0, idx)) && idx < MAX_GPGME_IDX; 
2206          ++idx ) {
2207       names[idx] = xstrdup( s );
2208     }
2209     
2210     it->info.userid = xmalloc( sizeof( char* ) * (idx+1) );
2211     memset( it->info.userid, 0, sizeof( char* ) * (idx+1) );
2212     it->info.dnarray = 0;
2213     for( idx = 0; names[idx] != 0; ++idx ) {
2214       struct DnPair* a = parse_dn( names[idx] ); 
2215       if( idx == 0 ) {
2216         it->info.userid[idx] = reorder_dn( a );
2217         it->info.dnarray = a;
2218         free (names[idx]);
2219         names[idx] = NULL;
2220       } else {
2221         it->info.userid[idx] = names[idx];
2222       }
2223     }
2224     it->info.userid[idx] = 0;
2225
2226     s = gpgme_key_get_string_attr (key, GPGME_ATTR_SERIAL, 0, 0); 
2227     it->info.serial = s? xstrdup(s) : NULL;
2228
2229     s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, 0, 0); 
2230     it->info.fingerprint = make_fingerprint( s );
2231
2232     s = gpgme_key_get_string_attr (key, GPGME_ATTR_ISSUER, 0, 0); 
2233     if( s ) {
2234       issuer_dn = tmp_dn = parse_dn( s );     
2235       /*it->info.issuer = xstrdup(s);*/
2236       it->info.issuer = reorder_dn( issuer_dn );
2237       while( tmp_dn && tmp_dn->key ) {
2238         free( tmp_dn->key );
2239         free( tmp_dn->value );
2240         ++tmp_dn;
2241       }
2242       free( issuer_dn );
2243       issuer_dn = tmp_dn = NULL;
2244     } else {
2245       it->info.issuer = NULL;
2246     }
2247     s = gpgme_key_get_string_attr (key, GPGME_ATTR_CHAINID, 0, 0); 
2248     it->info.chainid = s? xstrdup(s): NULL;
2249
2250     s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEY_CAPS, 0, 0); 
2251     it->info.caps = s? xstrdup(s) : NULL;
2252
2253     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_CREATED, 0, 0); 
2254     it->info.created = u;
2255
2256     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_EXPIRE, 0, 0); 
2257     it->info.expire = u;
2258
2259     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_IS_SECRET, 0, 0); 
2260     it->info.secret = u;
2261
2262     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_UID_INVALID, 0, 0); 
2263     it->info.invalid = u;
2264
2265     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_EXPIRED, 0, 0); 
2266     it->info.expired = u;
2267
2268     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_DISABLED, 0, 0); 
2269     it->info.disabled = u;
2270
2271     gpgme_key_release (key);
2272     /*return &(it->info);*/
2273     *result =  &(it->info);
2274   } else {
2275     *result = NULL;
2276   }
2277   return retval;
2278 }
2279
2280 int
2281 endListCertificates( struct CertIterator* it )
2282 {
2283   char *s = gpgme_get_op_info (it->ctx, 0);
2284   int truncated = s && strstr (s, "<truncated/>");
2285   fprintf( stderr,  "endListCertificates( %p )\n", it );
2286   if( s ) free( s );
2287   assert(it);
2288   freeInfo( &(it->info) );
2289   gpgme_op_keylist_end(it->ctx);
2290   gpgme_release (it->ctx);
2291   free( it );
2292   return truncated;
2293 }
2294
2295 int
2296 importCertificateWithFPR( const char* fingerprint, char** additional_info )
2297 {
2298   GpgmeError err;
2299   GpgmeCtx  ctx;
2300   GpgmeData keydata;
2301   GpgmeRecipients recips;
2302   char* buf;
2303   const char* tmp1;
2304   char* tmp2;
2305   int count = 0;
2306
2307   err = gpgme_new( &ctx );
2308   /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2309   if( err != GPGME_No_Error ) {
2310     return err;
2311   }
2312   gpgme_set_protocol( ctx, GPGME_PROTOCOL_CMS );
2313   gpgme_set_keylist_mode( ctx, GPGME_KEYLIST_MODE_LOCAL );
2314
2315   err = gpgme_data_new( &keydata );
2316   if( err ) {
2317     fprintf( stderr,  "gpgme_data_new returned %d\n", err );
2318     gpgme_release( ctx );
2319     return err;
2320   }
2321
2322   err = gpgme_recipients_new( &recips );
2323   if( err ) {
2324     fprintf( stderr,  "gpgme_recipients_new returned %d\n", err );
2325     gpgme_data_release( keydata );
2326     gpgme_release( ctx );
2327     return err;
2328   }
2329   
2330   buf = malloc( sizeof(char)*( strlen( fingerprint ) + 1 ) );
2331   if( !buf ) {
2332     gpgme_recipients_release( recips );
2333     gpgme_data_release( keydata );    
2334     gpgme_release( ctx );
2335     return GPGME_Out_Of_Core;
2336   }
2337   tmp1 = fingerprint;
2338   tmp2 = buf;
2339   while( *tmp1 ) {
2340     if( *tmp1 != ':' ) *tmp2++ = *tmp1;
2341     tmp1++;
2342   }
2343   *tmp2 = 0;
2344   fprintf( stderr,  "calling gpgme_recipients_add_name( %s )\n", buf );  
2345   err = gpgme_recipients_add_name( recips, buf ); 
2346   if( err ) {
2347     fprintf( stderr,  "gpgme_recipients_add_name returned %d\n", err );
2348     free (buf);
2349     gpgme_recipients_release( recips );
2350     gpgme_data_release( keydata );    
2351     gpgme_release( ctx );
2352     return err;
2353   }
2354
2355   err = gpgme_op_export( ctx, recips, keydata );
2356   if( err ) {
2357     fprintf( stderr,  "gpgme_op_export returned %d\n", err );
2358     free (buf);
2359     *additional_info = gpgme_get_op_info( ctx, 0 );
2360     gpgme_recipients_release( recips );
2361     gpgme_data_release( keydata );    
2362     gpgme_release( ctx );
2363     return err;
2364   }
2365   free (buf);
2366   buf = NULL;
2367
2368   err = gpgme_op_import_ext( ctx, keydata, &count );
2369   *additional_info = gpgme_get_op_info( ctx, 0 );
2370   if( err ) {    
2371     fprintf( stderr,  "gpgme_op_import_ext returned %d\n", err );
2372     gpgme_recipients_release( recips );
2373     gpgme_data_release( keydata );
2374     gpgme_release( ctx );
2375     return err;
2376   }
2377   if( count < 1 ) {
2378     /* we didn't import anything?!? */
2379     fprintf( stderr,  "gpgme_op_import_ext did not import any certificates\n" );
2380     gpgme_recipients_release( recips );
2381     gpgme_data_release( keydata );
2382     gpgme_release( ctx );
2383     return -1; /* FIXME */
2384   }
2385
2386   gpgme_recipients_release( recips );
2387   gpgme_data_release( keydata );    
2388   gpgme_release( ctx );
2389   return 0;
2390 }
2391 int
2392 importCertificateFromMem( const char* data, size_t length , char** additional_info )
2393 {
2394   GpgmeError err;
2395   GpgmeCtx  ctx;
2396   GpgmeData keydata;
2397   int count = 0;
2398
2399   err = gpgme_new( &ctx );
2400   /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2401   if( err != GPGME_No_Error ) {
2402     return err;
2403   }
2404   gpgme_set_protocol( ctx, GPGME_PROTOCOL_CMS );
2405   gpgme_set_keylist_mode( ctx, GPGME_KEYLIST_MODE_LOCAL );
2406
2407   err = gpgme_data_new_from_mem( &keydata, data, length, 0 );
2408   if( err ) {
2409     fprintf( stderr,  "gpgme_data_new returned %d\n", err );
2410     gpgme_release( ctx );
2411     return err;
2412   }
2413
2414   err = gpgme_op_import_ext( ctx, keydata, &count );
2415   *additional_info = gpgme_get_op_info( ctx, 0 );
2416   if( err) {
2417     fprintf( stderr,  "gpgme_op_import_ext returned %d\n", err );
2418     gpgme_data_release( keydata );    
2419     gpgme_release( ctx );
2420     return err;
2421   }
2422   if( count < 1 ) {
2423     /* we didn't import anything?!? */
2424     fprintf( stderr,  "gpgme_op_import_ext did not import any certificate\n" );    
2425     gpgme_data_release( keydata );    
2426     gpgme_release( ctx );
2427     return -1; /* FIXME */
2428   }
2429
2430   gpgme_data_release( keydata );    
2431   gpgme_release( ctx );
2432   return 0;
2433 }
2434
2435 /*  == == == == == == == == == == == == == == == == == == == == == == == == ==
2436    ==                                                                      ==
2437   ==         Continuation of CryptPlug code                               ==
2438  ==                                                                      ==
2439 == == == == == == == == == == == == == == == == == == == == == == == == ==  */
2440
2441
2442 /*
2443   Find all certificate for a given addressee and return them in a
2444   '\1' separated list.
2445   NOTE: The certificate parameter must point to a not-yet allocated
2446         char*.  The function will allocate the memory needed and
2447         return the size in newSize.
2448   If secretOnly is true, only secret keys are returned.
2449 */
2450 bool findCertificates( const char* addressee,
2451                        char** certificates,
2452                        int* newSize,
2453                        bool secretOnly )
2454 {
2455 #define MAXCERTS 1024
2456   /* use const char declarations since all of them are needed twice */
2457   const char* delimiter = "\1";
2458   const char* openBracket = "    (";
2459   const char* closeBracket = ")";
2460
2461   GpgmeCtx ctx;
2462   GpgmeError err;
2463   GpgmeKey rKey;
2464   const char *s;
2465   const char *s2;
2466   char* dn;
2467   struct DnPair* a;
2468   int nFound = 0;
2469   int iFound = 0;
2470   int siz = 0;
2471   char* DNs[MAXCERTS];
2472   char* FPRs[MAXCERTS];
2473   
2474   if( ! certificates ){
2475     fprintf( stderr, "gpgme: findCertificates called with invalid *certificates pointer\n" );
2476     return false;
2477   }
2478
2479   if( ! newSize ){
2480     fprintf( stderr, "gpgme: findCertificates called with invalid newSize pointer\n" );
2481     return false;
2482   }
2483
2484   *certificates = 0;
2485   *newSize = 0;
2486   
2487   /* calculate length of buffer needed for certs plus fingerprints */
2488   gpgme_new (&ctx);
2489   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
2490   err = gpgme_op_keylist_start(ctx, addressee, secretOnly ? 1 : 0);
2491   while( GPGME_No_Error == err ) {
2492     err = gpgme_op_keylist_next(ctx, &rKey);
2493     if( GPGME_No_Error == err ) {
2494       s = gpgme_key_get_string_attr (rKey, GPGME_ATTR_USERID, NULL, 0);
2495       if( s ) {
2496         dn = xstrdup( s );
2497         s2 = gpgme_key_get_string_attr (rKey, GPGME_ATTR_FPR, NULL, 0);
2498         if( s2 ) {
2499           if( nFound )
2500             siz += strlen( delimiter );
2501           a = parse_dn( dn );
2502           free( dn );
2503           dn = reorder_dn( a );
2504           siz += strlen( dn );
2505           siz += strlen( openBracket );
2506           siz += strlen( s2 );
2507           siz += strlen( closeBracket );
2508           DNs[ nFound ] = dn;
2509           dn = NULL; /* prevent it from being free'ed below. */
2510           FPRs[nFound ] = xstrdup( s2 );
2511           ++nFound;
2512           if( nFound >= MAXCERTS ) {
2513             fprintf( stderr,
2514                      "gpgme: findCertificates found too many certificates (%d)\n",
2515                      MAXCERTS );
2516             break;
2517           }
2518         }
2519         free (dn); 
2520       }
2521     }
2522   }
2523   gpgme_op_keylist_end( ctx );
2524   gpgme_release (ctx);
2525   
2526   
2527   if( 0 < siz ) {
2528     /* add one for trailing ZERO char */
2529     ++siz;
2530     *newSize = siz;
2531     /* allocate the buffer */
2532     *certificates = xmalloc( sizeof(char) * siz );
2533     memset( *certificates, 0, sizeof(char) * siz );
2534     /* fill the buffer */
2535     for (iFound=0; iFound < nFound; iFound++) {
2536       if( !iFound )
2537         strcpy(*certificates, DNs[iFound] );
2538       else {
2539         strcat(*certificates, delimiter );
2540         strcat(*certificates, DNs[iFound] );
2541       }
2542       strcat(  *certificates, openBracket );
2543       strcat(  *certificates, FPRs[iFound] );
2544       strcat(  *certificates, closeBracket );
2545       free( DNs[ iFound ] );
2546       free( FPRs[iFound ] );
2547     }
2548   }
2549     
2550   return ( 0 < nFound );
2551 }
2552
2553
2554 static const char*
2555 sig_status_to_string( GpgmeSigStat status )
2556 {
2557   const char *result;
2558
2559   switch (status) {
2560     case GPGME_SIG_STAT_NONE:
2561       result = "Oops: Signature not verified";
2562       break;
2563     case GPGME_SIG_STAT_NOSIG:
2564       result = "No signature found";
2565       break;
2566     case GPGME_SIG_STAT_GOOD:
2567       result = "Good signature";
2568       break;
2569     case GPGME_SIG_STAT_BAD:
2570       result = "BAD signature";
2571       break;
2572     case GPGME_SIG_STAT_NOKEY:
2573       result = "No public key to verify the signature";
2574       break;
2575     case GPGME_SIG_STAT_ERROR:
2576       result = "Error verifying the signature";
2577       break;
2578     case GPGME_SIG_STAT_DIFF:
2579       result = "Different results for signatures";
2580       break;
2581     default:
2582       result = "Error: Unknown status";
2583       break;
2584   }
2585
2586   return result;
2587 }
2588
2589
2590 void obtain_signature_information( GpgmeCtx * ctx,
2591                                    GpgmeSigStat status,
2592                                    struct SignatureMetaData* sigmeta )
2593 {
2594   GpgmeError err;
2595   GpgmeKey key;
2596   const char* statusStr;
2597   const char* fpr;
2598   unsigned long sumGPGME;
2599   SigStatusFlags sumPlug;
2600   time_t created;
2601   struct DnPair* a;
2602   int sig_idx=0;
2603   int UID_idx=0;
2604   
2605   /* Provide information in the sigmeta struct */
2606   /* the status string */
2607   statusStr = sig_status_to_string( status );
2608   sigmeta->status = malloc( strlen( statusStr ) + 1 );
2609   if( sigmeta->status ) {
2610     strcpy( sigmeta->status, statusStr );
2611     sigmeta->status[strlen( statusStr )] = '\0';
2612   } else
2613     ; /* nothing to do, is already 0 */
2614
2615   /* Extended information for any number of signatures. */
2616   fpr = gpgme_get_sig_status( *ctx, sig_idx, &status, &created );
2617   sigmeta->extended_info = 0;
2618   while( fpr != NULL ) {
2619     struct tm* ctime_val;
2620     const char* sig_status;
2621
2622     void* alloc_return = realloc( sigmeta->extended_info,
2623                                   sizeof( struct SignatureMetaDataExtendedInfo )
2624                                   * ( sig_idx + 1 ) );
2625     if( alloc_return ) {
2626       sigmeta->extended_info = alloc_return;
2627
2628       /* clear the data area */
2629       memset( &sigmeta->extended_info[sig_idx], 
2630               0,
2631               sizeof (struct SignatureMetaDataExtendedInfo) );
2632
2633       /* the creation time */
2634       sigmeta->extended_info[sig_idx].creation_time = malloc( sizeof( struct tm ) );
2635       if( sigmeta->extended_info[sig_idx].creation_time ) {
2636         ctime_val = localtime( &created );
2637         memcpy( sigmeta->extended_info[sig_idx].creation_time,
2638                 ctime_val, sizeof( struct tm ) );
2639       }
2640
2641       /* the extended signature verification status */
2642       sumGPGME = gpgme_get_sig_ulong_attr( *ctx,
2643                                            sig_idx,
2644                                            GPGME_ATTR_SIG_SUMMARY,
2645                                            0 );
2646       fprintf( stderr, "gpgmeplug checkMessageSignature status flags: %lX\n", sumGPGME );
2647       /* translate GPGME status flags to common CryptPlug status flags */
2648       sumPlug = 0;
2649       if( sumGPGME & GPGME_SIGSUM_VALID       ) sumPlug |= SigStat_VALID      ;
2650       if( sumGPGME & GPGME_SIGSUM_GREEN       ) sumPlug |= SigStat_GREEN      ;
2651       if( sumGPGME & GPGME_SIGSUM_RED         ) sumPlug |= SigStat_RED        ;
2652       if( sumGPGME & GPGME_SIGSUM_KEY_REVOKED ) sumPlug |= SigStat_KEY_REVOKED;
2653       if( sumGPGME & GPGME_SIGSUM_KEY_EXPIRED ) sumPlug |= SigStat_KEY_EXPIRED;
2654       if( sumGPGME & GPGME_SIGSUM_SIG_EXPIRED ) sumPlug |= SigStat_SIG_EXPIRED;
2655       if( sumGPGME & GPGME_SIGSUM_KEY_MISSING ) sumPlug |= SigStat_KEY_MISSING;
2656       if( sumGPGME & GPGME_SIGSUM_CRL_MISSING ) sumPlug |= SigStat_CRL_MISSING;
2657       if( sumGPGME & GPGME_SIGSUM_CRL_TOO_OLD ) sumPlug |= SigStat_CRL_TOO_OLD;
2658       if( sumGPGME & GPGME_SIGSUM_BAD_POLICY  ) sumPlug |= SigStat_BAD_POLICY ;
2659       if( sumGPGME & GPGME_SIGSUM_SYS_ERROR   ) sumPlug |= SigStat_SYS_ERROR  ;
2660       if( !sumPlug )
2661         sumPlug = SigStat_NUMERICAL_CODE | sumGPGME;
2662       sigmeta->extended_info[sig_idx].sigStatusFlags = sumPlug;
2663
2664       sigmeta->extended_info[sig_idx].validity = GPGME_VALIDITY_UNKNOWN;
2665
2666       err = gpgme_get_sig_key (*ctx, sig_idx, &key);
2667
2668       if ( err == GPGME_No_Error) {
2669         const char* attr_string;
2670         unsigned long attr_ulong;
2671
2672         /* extract key identidy */
2673         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_KEYID, 0, 0);
2674         if (attr_string != 0)
2675             storeNewCharPtr( &sigmeta->extended_info[sig_idx].keyid, attr_string );
2676
2677         /* extract finger print */
2678         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_FPR, 0, 0);
2679         if (attr_string != 0)
2680             storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint,
2681                             attr_string );
2682
2683         /* algorithms useable with this key */
2684         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_ALGO, 0, 0);
2685         if (attr_string != 0)
2686             storeNewCharPtr( &sigmeta->extended_info[sig_idx].algo,
2687                             attr_string );
2688         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_ALGO, 0, 0);
2689         sigmeta->extended_info[sig_idx].algo_num = attr_ulong;
2690
2691         /* extract key validity */
2692         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_VALIDITY, 0, 0);
2693         sigmeta->extended_info[sig_idx].validity = attr_ulong;
2694
2695         /* extract user id, according to the documentation it's representable
2696         * as a number, but it seems that it also has a string representation
2697         */
2698         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_USERID, 0, 0);
2699         if (attr_string != 0) {
2700             a = parse_dn( attr_string );
2701             sigmeta->extended_info[sig_idx].userid = reorder_dn( a );
2702         }
2703         
2704         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_USERID, 0, 0);
2705         sigmeta->extended_info[sig_idx].userid_num = attr_ulong;
2706
2707         /* extract the length */
2708           sigmeta->extended_info[sig_idx].keylen = attr_ulong;
2709
2710         /* extract the creation time of the key */
2711         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_CREATED, 0, 0);
2712         sigmeta->extended_info[sig_idx].key_created = attr_ulong;
2713
2714         /* extract the expiration time of the key */
2715         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_EXPIRE, 0, 0);
2716         sigmeta->extended_info[sig_idx].key_expires = attr_ulong;
2717
2718         /* extract user name */
2719         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_NAME, 0, 0);
2720         if (attr_string != 0) {
2721             a = parse_dn( attr_string );
2722             sigmeta->extended_info[sig_idx].name = reorder_dn( a );
2723         }
2724
2725         /* extract email(s) */
2726         sigmeta->extended_info[sig_idx].emailCount = 0;
2727         sigmeta->extended_info[sig_idx].emailList = 0;
2728         for( UID_idx=0; 
2729              (attr_string = gpgme_key_get_string_attr(key,
2730                               GPGME_ATTR_EMAIL, 0, UID_idx)); 
2731              ++UID_idx ){
2732           if (*attr_string) {
2733             fprintf( stderr, "gpgmeplug checkMessageSignature found email: %s\n", attr_string );
2734             if( !sigmeta->extended_info[sig_idx].emailCount )
2735                 alloc_return = 
2736                     malloc( sizeof( char*) );
2737             else
2738                 alloc_return = 
2739                     realloc( sigmeta->extended_info[sig_idx].emailList,
2740                              sizeof( char*)
2741                              * (sigmeta->extended_info[sig_idx].emailCount + 1) );
2742             if( alloc_return ) {
2743               sigmeta->extended_info[sig_idx].emailList = alloc_return;
2744               storeNewCharPtr( 
2745                   &( sigmeta->extended_info[sig_idx].emailList[
2746                           sigmeta->extended_info[sig_idx].emailCount ] ),
2747                   attr_string );
2748               ++sigmeta->extended_info[sig_idx].emailCount;
2749             }
2750           }
2751         }
2752         if( !sigmeta->extended_info[sig_idx].emailCount )
2753           fprintf( stderr, "gpgmeplug checkMessageSignature found NO EMAIL\n" );
2754
2755         /* extract the comment */
2756         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_COMMENT, 0, 0);
2757         if (attr_string != 0)
2758             storeNewCharPtr( &sigmeta->extended_info[sig_idx].comment,
2759                             attr_string );
2760       }
2761       else
2762         storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint, fpr );
2763
2764       sig_status = sig_status_to_string( status );
2765       storeNewCharPtr( &sigmeta->extended_info[sig_idx].status_text,
2766                        sig_status );
2767
2768     } else
2769       break; /* if allocation fails once, it isn't likely to
2770                 succeed the next time either */
2771
2772     fpr = gpgme_get_sig_status (*ctx, ++sig_idx, &status, &created);
2773   }
2774   sigmeta->extended_info_count = sig_idx;
2775   sigmeta->nota_xml = gpgme_get_notation( *ctx );
2776   sigmeta->status_code = status;
2777 }
2778
2779
2780 bool checkMessageSignature( char** cleartext,
2781                             const char* signaturetext,
2782                             bool signatureIsBinary,
2783                             int signatureLen,
2784                             struct SignatureMetaData* sigmeta )
2785 {
2786   GpgmeCtx ctx;
2787   GpgmeSigStat status;
2788   GpgmeData datapart, sigpart;
2789   char* rClear = 0;
2790   size_t clearLen;
2791   bool isOpaqueSigned;
2792   
2793   if( !cleartext ) {
2794     if( sigmeta )
2795       storeNewCharPtr( &sigmeta->status,
2796                         __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO );
2797
2798     return false;
2799   }
2800
2801   isOpaqueSigned = !*cleartext;
2802
2803   gpgme_new( &ctx );
2804   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
2805   gpgme_set_armor (ctx,    signatureIsBinary ? 0 : 1);
2806   /*  gpgme_set_textmode (ctx, signatureIsBinary ? 0 : 1); */
2807
2808   if( isOpaqueSigned )
2809     gpgme_data_new( &datapart );
2810   else
2811     gpgme_data_new_from_mem( &datapart, *cleartext,
2812                              strlen( *cleartext ), 1 );
2813
2814   gpgme_data_new_from_mem( &sigpart,
2815                            signaturetext,
2816                            signatureIsBinary
2817                            ? signatureLen
2818                            : strlen( signaturetext ),
2819                            1 );
2820
2821   gpgme_op_verify( ctx, sigpart, isOpaqueSigned ? NULL : datapart,
2822                    isOpaqueSigned ? datapart : NULL, &status );
2823
2824   if( isOpaqueSigned ) {
2825     rClear = gpgme_data_release_and_get_mem( datapart, &clearLen );
2826     *cleartext = malloc( clearLen + 1 );
2827     if( *cleartext ) {
2828       if( clearLen )
2829         strncpy(*cleartext, rClear, clearLen );
2830       (*cleartext)[clearLen] = '\0';
2831     }
2832     free( rClear );
2833   }
2834   else
2835     gpgme_data_release( datapart );
2836
2837   gpgme_data_release( sigpart );
2838
2839   obtain_signature_information( &ctx, status, sigmeta );
2840   
2841   gpgme_release( ctx );
2842   return ( status == GPGME_SIG_STAT_GOOD );
2843 }
2844
2845
2846 bool decryptAndCheckMessage( const char*  ciphertext,
2847                              bool         cipherIsBinary,
2848                              int          cipherLen,
2849                              const char** cleartext,
2850                              const char*  certificate,
2851                              bool*        signatureFound,
2852                              struct SignatureMetaData* sigmeta,
2853                              int*   errId,
2854                              char** errTxt )
2855 {
2856   GpgmeCtx ctx;
2857   GpgmeError err;
2858   GpgmeSigStat sigstatus;
2859   GpgmeData gCiphertext, gPlaintext;
2860   size_t rCLen = 0;
2861   char*  rCiph = 0;
2862   bool bOk = false;
2863
2864   if( !ciphertext )
2865     return false;
2866
2867   err = gpgme_new (&ctx);
2868   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
2869   
2870   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
2871   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
2872
2873   /*
2874   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
2875                            1+strlen( ciphertext ), 1 ); */
2876   gpgme_data_new_from_mem( &gCiphertext,
2877                            ciphertext,
2878                            cipherIsBinary
2879                            ? cipherLen
2880                            : strlen( ciphertext ),
2881                            1 );
2882
2883   gpgme_data_new( &gPlaintext );
2884
2885   err = gpgme_op_decrypt_verify( ctx, gCiphertext, gPlaintext, &sigstatus );
2886   gpgme_data_release( gCiphertext );
2887   if( err ) {
2888     fprintf( stderr, "\ngpgme_op_decrypt_verify() returned this error code:  %i\n\n", err );
2889     if( errId )
2890       *errId = err;
2891     if( errTxt ) {
2892       const char* _errTxt = gpgme_strerror( err );
2893       *errTxt = malloc( strlen( _errTxt ) + 1 );
2894       if( *errTxt )
2895         strcpy(*errTxt, _errTxt );
2896     }
2897     gpgme_data_release( gPlaintext );
2898     gpgme_release( ctx );
2899     return bOk;
2900   }
2901
2902   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
2903
2904   *cleartext = malloc( rCLen + 1 );
2905   if( *cleartext ) {
2906       if( rCLen ) {
2907           bOk = true;
2908           strncpy((char*)*cleartext, rCiph, rCLen );
2909       }
2910       ((char*)(*cleartext))[rCLen] = 0;
2911   }
2912   free( rCiph );
2913
2914   if( signatureFound )
2915     *signatureFound = sigstatus != GPGME_SIG_STAT_NONE;
2916   if( sigmeta && sigstatus != GPGME_SIG_STAT_NONE )
2917     obtain_signature_information( &ctx, sigstatus, sigmeta );
2918   
2919   gpgme_release( ctx );
2920   return bOk;
2921 }