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