* gpgmeplug.c (xmalloc): New.
[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 /* Please: Don't call an allocation function xfoo when it may return NULL. */
1730 /* Wrong: #define xstrdup( x ) (x)?strdup(x):0 */
1731 /* Right: */
1732 static char *
1733 xstrdup (const char *string)
1734 {
1735   char *p = xmalloc (strlen (string));
1736   strcpy (p, string);
1737   return p;
1738 }
1739     
1740
1741
1742 static void 
1743 safe_free( void** x ) 
1744 {
1745   free( *x );
1746   *x = 0;
1747 }
1748
1749 char *
1750 trim_trailing_spaces( char *string )
1751 {
1752     char *p, *mark;
1753
1754     for( mark = NULL, p = string; *p; p++ ) {
1755         if( isspace( *p ) ) {
1756             if( !mark )
1757                 mark = p;
1758         }
1759         else
1760             mark = NULL;
1761     }
1762     if( mark )
1763         *mark = '\0' ;
1764
1765     return string ;
1766 }
1767 /*#define safe_free( x ) free( x )*/
1768
1769 /* Parse a DN and return an array-ized one.  This is not a validating
1770    parser and it does not support any old-stylish syntax; gpgme is
1771    expected to return only rfc2253 compatible strings. */
1772 static const unsigned char *
1773 parse_dn_part (struct DnPair *array, const unsigned char *string)
1774 {
1775   const unsigned char *s, *s1;
1776   size_t n;
1777   unsigned char *p;
1778
1779   /* parse attributeType */
1780   for (s = string+1; *s && *s != '='; s++)
1781     ;
1782   if (!*s)
1783     return NULL; /* error */
1784   n = s - string;
1785   if (!n)
1786     return NULL; /* empty key */
1787   array->key = p = xmalloc (n+1);
1788   
1789   
1790   memcpy (p, string, n);
1791   p[n] = 0;
1792   trim_trailing_spaces (p);
1793   if ( !strcmp (p, "1.2.840.113549.1.9.1") )
1794     strcpy (p, "EMail");
1795   string = s + 1;
1796
1797   if (*string == '#')
1798     { /* hexstring */
1799       string++;
1800       for (s=string; hexdigitp (s); s++)
1801         s++;
1802       n = s - string;
1803       if (!n || (n & 1))
1804         return NULL; /* empty or odd number of digits */
1805       n /= 2;
1806       array->value = p = xmalloc (n+1);
1807       
1808       
1809       for (s1=string; n; s1 += 2, n--)
1810         *p++ = xtoi_2 (s1);
1811       *p = 0;
1812    }
1813   else
1814     { /* regular v3 quoted string */
1815       for (n=0, s=string; *s; s++)
1816         {
1817           if (*s == '\\')
1818             { /* pair */
1819               s++;
1820               if (*s == ',' || *s == '=' || *s == '+'
1821                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
1822                   || *s == '\\' || *s == '\"' || *s == ' ')
1823                 n++;
1824               else if (hexdigitp (s) && hexdigitp (s+1))
1825                 {
1826                   s++;
1827                   n++;
1828                 }
1829               else
1830                 return NULL; /* invalid escape sequence */
1831             }
1832           else if (*s == '\"')
1833             return NULL; /* invalid encoding */
1834           else if (*s == ',' || *s == '=' || *s == '+'
1835                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
1836             break; 
1837           else
1838             n++;
1839         }
1840
1841       array->value = p = xmalloc (n+1);
1842       
1843       
1844       for (s=string; n; s++, n--)
1845         {
1846           if (*s == '\\')
1847             { 
1848               s++;
1849               if (hexdigitp (s))
1850                 {
1851                   *p++ = xtoi_2 (s);
1852                   s++;
1853                 }
1854               else
1855                 *p++ = *s;
1856             }
1857           else
1858             *p++ = *s;
1859         }
1860       *p = 0;
1861     }
1862   return s;
1863 }
1864
1865
1866 /* Parse a DN and return an array-ized one.  This is not a validating
1867    parser and it does not support any old-stylish syntax; gpgme is
1868    expected to return only rfc2253 compatible strings. */
1869 static struct DnPair *
1870 parse_dn (const unsigned char *string)
1871 {
1872   struct DnPair *array;
1873   size_t arrayidx, arraysize;
1874   int i;
1875
1876   if( !string )
1877     return NULL;
1878
1879   arraysize = 7; /* C,ST,L,O,OU,CN,email */
1880   arrayidx = 0;
1881   array = xmalloc ((arraysize+1) * sizeof *array);
1882   
1883   
1884   while (*string)
1885     {
1886       while (*string == ' ')
1887         string++;
1888       if (!*string)
1889         break; /* ready */
1890       if (arrayidx >= arraysize)
1891         { /* mutt lacks a real safe_realoc - so we need to copy */
1892           struct DnPair *a2;
1893
1894           arraysize += 5;
1895           a2 = xmalloc ((arraysize+1) * sizeof *array);
1896           for (i=0; i < arrayidx; i++)
1897             {
1898               a2[i].key = array[i].key;
1899               a2[i].value = array[i].value;
1900             }
1901           safe_free ((void **)&array);
1902           array = a2;
1903         }
1904       array[arrayidx].key = NULL;
1905       array[arrayidx].value = NULL;
1906       string = parse_dn_part (array+arrayidx, string);
1907       arrayidx++;
1908       if (!string)
1909         goto failure;
1910       while (*string == ' ')
1911         string++;
1912       if (*string && *string != ',' && *string != ';' && *string != '+')
1913         goto failure; /* invalid delimiter */
1914       if (*string)
1915         string++;
1916     }
1917   array[arrayidx].key = NULL;
1918   array[arrayidx].value = NULL;
1919   return array;
1920
1921  failure:
1922   for (i=0; i < arrayidx; i++)
1923     {
1924       safe_free ((void**)&array[i].key);
1925       safe_free ((void**)&array[i].value);
1926     }
1927   safe_free ((void**)&array);
1928   return NULL;
1929 }
1930
1931 static int 
1932 add_dn_part( char* result, struct DnPair* dn, const char* part )
1933 {
1934   int any = 0;
1935
1936   if( dn ) {
1937     for(; dn->key; ++dn ) {
1938       if( !strcmp( dn->key, part ) ) {
1939         if( any ) strcat( result, "+" );
1940         /* email hack */
1941         if( !strcmp( part, "1.2.840.113549.1.9.1" ) ) strcat( result, "EMail" );
1942         else strcat( result, part );
1943         strcat( result, "=" );
1944         strcat( result, dn->value );
1945         any = 1;
1946       }
1947     }
1948   }
1949   return any;
1950 }
1951
1952 static char* 
1953 reorder_dn( struct DnPair *dn )
1954 {
1955   // note: The must parts are: CN, L, OU, O, C
1956   const char* stdpart[] = {
1957     "CN", "S", "SN", "GN", "T", "UID",
1958           "MAIL", "EMAIL", "MOBILE", "TEL", "FAX", "STREET",
1959     "L",  "PC", "SP", "ST",
1960     "OU",
1961     "O",
1962     "C",
1963     NULL
1964   };
1965   int any=0, any2=0, len=0, i;
1966   char* result;
1967   if( dn ) {
1968     for( i = 0; dn[i].key; ++i ) {
1969       len += strlen( dn[i].key );
1970       len += strlen( dn[i].value );
1971       len += 4; /* ',' and '=', and possibly "(" and ")" */
1972     }
1973   }
1974   result = xmalloc( (len+1)*sizeof(char) );
1975   *result = 0;
1976
1977   /* add standard parts */
1978   for( i = 0; stdpart[i]; ++i ) {
1979     if( any ) {
1980       strcat( result, "," );
1981     }
1982     any = add_dn_part( result, dn, stdpart[i] );
1983   }
1984
1985   /* add remaining parts in no particular order */
1986   if( dn ) {
1987     for(; dn->key; ++dn ) {
1988       for( i = 0; stdpart[i]; ++i ) {
1989         if( !strcmp( dn->key, stdpart[i] ) ) {
1990           break;
1991         }
1992       }
1993       if( !stdpart[i] ) {
1994         if( any ) strcat( result, "," );
1995         if( !any2 ) strcat( result, "(");
1996         any = add_dn_part( result, dn, dn->key );
1997         any2 = 1;
1998       }
1999     }
2000   }
2001   if( any2 ) strcat( result, ")");
2002   return result;
2003 }
2004
2005 struct CertIterator {
2006   GpgmeCtx ctx;  
2007   struct CertificateInfo info;
2008 };
2009
2010 struct CertIterator* 
2011 startListCertificates( const char* pattern, int remote )
2012 {
2013     GpgmeError err;
2014     struct CertIterator* it;
2015     const char* patterns[] = { pattern, NULL };
2016     fprintf( stderr,  "startListCertificates( \"%s\", %d )", pattern, remote );
2017
2018     it = xmalloc( sizeof( struct CertIterator ) );
2019
2020     err = gpgme_new (&(it->ctx));
2021     /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2022     if( err != GPGME_No_Error ) {
2023       free( it );
2024       return NULL;
2025     }
2026
2027     gpgme_set_protocol (it->ctx, GPGME_PROTOCOL_CMS);
2028     if( remote ) gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_EXTERN ); 
2029     else gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_LOCAL );
2030     err =  gpgme_op_keylist_ext_start ( it->ctx, patterns, 0, 0);
2031     if( err != GPGME_No_Error ) {
2032       endListCertificates( it );
2033       return NULL;
2034     }
2035     memset( &(it->info), 0, sizeof( struct CertificateInfo ) );
2036     return it;
2037 }
2038
2039 /* free() each string in a char*[] and the array itself */
2040 static void 
2041 freeStringArray( char** c )
2042 {
2043     char** _c = c;
2044     while( c && *c ) {
2045       /*fprintf( stderr, "freeing \"%s\"\n", *c );*/
2046       safe_free( (void**)&(*c) );
2047       ++c;
2048     }
2049     safe_free( (void**)&_c );
2050 }
2051
2052 /* free all malloc'ed data in a struct CertificateInfo */
2053 static void 
2054 freeInfo( struct CertificateInfo* info )
2055 {
2056   struct DnPair* a = info->dnarray;
2057   assert( info );
2058   if( info->userid ) freeStringArray( info->userid );
2059   if( info->serial ) safe_free( (void**)&(info->serial) );
2060   if( info->fingerprint ) safe_free( (void**)&(info->fingerprint) );
2061   if( info->issuer ) safe_free( (void**)&(info->issuer) );
2062   if( info->chainid ) safe_free( (void**)&(info->chainid) );
2063   if( info->caps ) safe_free( (void**)&(info->caps) );
2064   while( a && a->key && a->value ) {
2065     safe_free ((void**)&(a->key));
2066     safe_free ((void**)&(a->value));
2067     ++a;
2068   }
2069   if( info->dnarray ) safe_free ((void**)&(info->dnarray));
2070   memset( info, 0, sizeof( *info ) );
2071 }
2072
2073 /* Format the fingerprint nicely. The caller should
2074    free the returned value with safe_free() */
2075 static char* make_fingerprint( const char* fpr )
2076 {
2077   int len = strlen(fpr);
2078   int i = 0;
2079   char* result = xmalloc( (len + len/2 + 1)*sizeof(char) );
2080   if( !result ) return NULL;
2081   for(; *fpr; ++fpr, ++i ) {
2082     if( i%3 == 2) {
2083       result[i] = ':'; ++i;
2084     }
2085     result[i] = *fpr;
2086   }
2087   result[i] = 0;
2088   return result;
2089 }
2090
2091 int 
2092 nextCertificate( struct CertIterator* it, struct CertificateInfo** result )
2093 {
2094   GpgmeError err;
2095   GpgmeKey   key;
2096   int retval = GPGME_No_Error;
2097   assert( it );
2098   err = gpgme_op_keylist_next ( it->ctx, &key);
2099   if( err != GPGME_EOF ) {   
2100     int idx;
2101     const char* s;
2102     unsigned long u;
2103     char* names[MAX_GPGME_IDX+1];
2104     struct DnPair *issuer_dn, *tmp_dn;
2105     retval = err;
2106     memset( names, 0, sizeof( names ) );
2107     freeInfo( &(it->info) );
2108
2109     for( idx = 0; (s = gpgme_key_get_string_attr (key, GPGME_ATTR_USERID, 0, idx)) && idx < MAX_GPGME_IDX; 
2110          ++idx ) {
2111       names[idx] = xstrdup( s );
2112     }
2113     
2114     it->info.userid = xmalloc( sizeof( char* ) * (idx+1) );
2115     memset( it->info.userid, 0, sizeof( char* ) * (idx+1) );
2116     it->info.dnarray = 0;
2117     for( idx = 0; names[idx] != 0; ++idx ) {
2118       struct DnPair* a = parse_dn( names[idx] ); 
2119       if( idx == 0 ) {
2120         it->info.userid[idx] = reorder_dn( a );
2121         it->info.dnarray = a;
2122         safe_free( (void **)&(names[idx]) );
2123       } else {
2124         it->info.userid[idx] = names[idx];
2125       }
2126     }
2127     it->info.userid[idx] = 0;
2128
2129     s = gpgme_key_get_string_attr (key, GPGME_ATTR_SERIAL, 0, 0); 
2130     it->info.serial = s? xstrdup(s) : NULL;
2131
2132     s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, 0, 0); 
2133     it->info.fingerprint = make_fingerprint( s );
2134
2135     s = gpgme_key_get_string_attr (key, GPGME_ATTR_ISSUER, 0, 0); 
2136     if( s ) {
2137       issuer_dn = tmp_dn = parse_dn( s );     
2138       /*it->info.issuer = xstrdup(s);*/
2139       it->info.issuer = reorder_dn( issuer_dn );
2140       while( tmp_dn->key ) {
2141         safe_free( (void**)&issuer_dn->key );
2142         safe_free( (void**)&issuer_dn->value );
2143         ++tmp_dn;
2144       }
2145       safe_free( (void**)&issuer_dn );
2146     } else {
2147       it->info.issuer = NULL;
2148     }
2149     s = gpgme_key_get_string_attr (key, GPGME_ATTR_CHAINID, 0, 0); 
2150     it->info.chainid = s? xstrdup(s): NULL;
2151
2152     s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEY_CAPS, 0, 0); 
2153     it->info.caps = s? xstrdup(s) : NULL;
2154
2155     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_CREATED, 0, 0); 
2156     it->info.created = u;
2157
2158     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_EXPIRE, 0, 0); 
2159     it->info.expire = u;
2160
2161     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_IS_SECRET, 0, 0); 
2162     it->info.secret = u;
2163
2164     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_UID_INVALID, 0, 0); 
2165     it->info.invalid = u;
2166
2167     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_EXPIRED, 0, 0); 
2168     it->info.expired = u;
2169
2170     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_DISABLED, 0, 0); 
2171     it->info.disabled = u;
2172
2173     gpgme_key_release (key);
2174     /*return &(it->info);*/
2175     *result =  &(it->info);
2176   } else {
2177     *result = NULL;
2178   }
2179   return retval;
2180 }
2181
2182 int
2183 endListCertificates( struct CertIterator* it )
2184 {
2185   /*fprintf( stderr,  "endListCertificates()\n" );*/
2186   char *s = gpgme_get_op_info (it->ctx, 0);
2187   int truncated = s && strstr (s, "<truncated/>");
2188   if( s ) free( s );
2189   assert(it);
2190   freeInfo( &(it->info) );
2191   gpgme_op_keylist_end(it->ctx);
2192   gpgme_release (it->ctx);
2193   free( it );
2194   return truncated;
2195 }
2196
2197 int
2198 importCertificate( const char* fingerprint )
2199 {
2200   GpgmeError err;
2201   GpgmeCtx  ctx;
2202   GpgmeData keydata;
2203   GpgmeRecipients recips;
2204   char* buf;
2205   const char* tmp1;
2206   char* tmp2;
2207
2208   err = gpgme_new( &ctx );
2209   /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2210   if( err != GPGME_No_Error ) {
2211     return err;
2212   }
2213   gpgme_set_protocol( ctx, GPGME_PROTOCOL_CMS );
2214   gpgme_set_keylist_mode( ctx, GPGME_KEYLIST_MODE_LOCAL );
2215
2216   err = gpgme_data_new( &keydata );
2217   if( err ) {
2218     fprintf( stderr,  "gpgme_data_new returned %d\n", err );
2219     gpgme_release( ctx );
2220     return err;
2221   }
2222
2223   err = gpgme_recipients_new( &recips );
2224   if( err ) {
2225     fprintf( stderr,  "gpgme_recipients_new returned %d\n", err );
2226     gpgme_data_release( keydata );
2227     gpgme_release( ctx );
2228     return err;
2229   }
2230   
2231   buf = malloc( sizeof(char)*( strlen( fingerprint ) + 1 ) );
2232   if( !buf ) {
2233     gpgme_recipients_release( recips );
2234     gpgme_data_release( keydata );    
2235     gpgme_release( ctx );
2236     return GPGME_Out_Of_Core;
2237   }
2238   tmp1 = fingerprint;
2239   tmp2 = buf;
2240   while( *tmp1 ) {
2241     if( *tmp1 != ':' ) *tmp2++ = *tmp1;
2242     tmp1++;
2243   }
2244   *tmp2 = 0;
2245   fprintf( stderr,  "calling gpgme_recipients_add_name( %s )\n", buf );  
2246   err = gpgme_recipients_add_name( recips, buf ); 
2247   if( err ) {
2248     fprintf( stderr,  "gpgme_recipients_add_name returned %d\n", err );
2249     safe_free( (void**)&buf );
2250     gpgme_recipients_release( recips );
2251     gpgme_data_release( keydata );    
2252     gpgme_release( ctx );
2253     return err;
2254   }
2255
2256   err = gpgme_op_export( ctx, recips, keydata );
2257   if( err ) {
2258     fprintf( stderr,  "gpgme_op_export returned %d\n", err );
2259     safe_free( (void**)&buf );
2260     gpgme_recipients_release( recips );
2261     gpgme_data_release( keydata );    
2262     gpgme_release( ctx );
2263     return err;
2264   }
2265   safe_free( (void**)&buf );
2266
2267   err = gpgme_op_import( ctx, keydata );
2268   if( err ) {    
2269     fprintf( stderr,  "gpgme_op_import returned %d\n", err );
2270     gpgme_recipients_release( recips );
2271     gpgme_data_release( keydata );    
2272     gpgme_release( ctx );
2273     return err;
2274   }
2275
2276   gpgme_recipients_release( recips );
2277   gpgme_data_release( keydata );    
2278   gpgme_release( ctx );
2279   return 0;
2280 }
2281
2282 /*  // // // // // // // // // // // // // // // // // // // // // // // // //
2283    //                                                                      //
2284   //         Continuation of CryptPlug code                               //
2285  //                                                                      //
2286 // // // // // // // // // // // // // // // // // // // // // // // // //*/
2287
2288
2289 /*
2290   Find all certificate for a given addressee and return them in a
2291   '\1' separated list.
2292   NOTE: The certificate parameter must point to a not-yet allocated
2293         char*.  The function will allocate the memory needed and
2294         return the size in newSize.
2295   If secretOnly is true, only secret keys are returned.
2296 */
2297 bool findCertificates( const char* addressee,
2298                        char** certificates,
2299                        int* newSize,
2300                        bool secretOnly )
2301 {
2302 #define MAXCERTS 1024;
2303   /* use const char declarations since all of them are needed twice *.
2304   const char* delimiter = "\1";
2305   const char* openBracket = "    (";
2306   const char* closeBracket = ")";
2307
2308   GpgmeCtx ctx;
2309   GpgmeError err;
2310   GpgmeKey rKey;
2311   const char *s;
2312   const char *s2;
2313   char* dn;
2314   struct DnPair* a;
2315   int nFound = 0;
2316   int iFound = 0;
2317   int siz = 0;
2318   char* DNs[MAXCERTS];
2319   char* FPRs[MAXCERTS];
2320   
2321   if( ! certificates ){
2322     fprintf( stderr, "gpgme: findCertificates called with invalid *certificates pointer\n" );
2323     return false;
2324   }
2325
2326   if( ! newSize ){
2327     fprintf( stderr, "gpgme: findCertificates called with invalid newSize pointer\n" );
2328     return false;
2329   }
2330
2331   *certificates = 0;
2332   *newSize = 0;
2333   
2334   /* calculate length of buffer needed for certs plus fingerprints */
2335   gpgme_new (&ctx);
2336   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
2337   err = gpgme_op_keylist_start(ctx, addressee, secretOnly ? 1 : 0);
2338   while( GPGME_No_Error == err ) {
2339     err = gpgme_op_keylist_next(ctx, &rKey);
2340     if( GPGME_No_Error == err ) {
2341       s = gpgme_key_get_string_attr (rKey, GPGME_ATTR_USERID, NULL, 0);
2342       if( s ) {
2343         dn = xstrdup( s );
2344         s2 = gpgme_key_get_string_attr (rKey, GPGME_ATTR_FPR, NULL, 0);
2345         if( s2 ) {
2346           if( nFound )
2347             siz += strlen( delimiter );
2348           a = parse_dn( dn );
2349           free( dn );
2350           dn = reorder_dn( a );
2351           siz += strlen( dn );
2352           siz += strlen( openBracket );
2353           siz += strlen( s2 );
2354           siz += strlen( closeBracket );
2355           DNs[ nFound ] = dn;
2356           dn = NULL;
2357           FPRs[nFound ] = xstrdup( s2 );
2358           ++nFound;
2359           if( nFound >= maxCerts ) {
2360             fprintf( stderr,
2361                      "gpgme: findCertificates found too many certificates (%d)\n",
2362                      MAXCERTS );
2363             break;
2364           }
2365         }
2366         free( dn );
2367       }
2368     }
2369   }
2370   gpgme_op_keylist_end( ctx );
2371   gpgme_release (ctx);
2372   
2373   
2374   if( 0 < siz ) {
2375     /* add one for trailing ZERO char */
2376     ++siz;
2377     *newSize = siz;
2378     /* allocate the buffer */
2379     *certificates = xmalloc(   sizeof(char) * siz );
2380     memset( *certificates, 0, sizeof(char) * siz );
2381     /* fill the buffer */
2382     for( iFound=0; iFound < nFound; ++iFound ) {
2383       if( !iFound )
2384         strcpy(*certificates, DNs[iFound] );
2385       else {
2386         strcat(*certificates, delimiter );
2387         strcat(*certificates, DNs[iFound] );
2388       }
2389       strcat(  *certificates, openBracket );
2390       strcat(  *certificates, FPRs[iFound] );
2391       strcat(  *certificates, closeBracket );
2392       ++iFound;
2393       free( DNs[ iFound ] );
2394       free( FPRs[iFound ] );
2395     }
2396   }
2397     
2398   return ( 0 < nFound );
2399 }
2400
2401
2402 static const char*
2403 sig_status_to_string( GpgmeSigStat status )
2404 {
2405   const char *result;
2406
2407   switch (status) {
2408     case GPGME_SIG_STAT_NONE:
2409       result = "Oops: Signature not verified";
2410       break;
2411     case GPGME_SIG_STAT_NOSIG:
2412       result = "No signature found";
2413       break;
2414     case GPGME_SIG_STAT_GOOD:
2415       result = "Good signature";
2416       break;
2417     case GPGME_SIG_STAT_BAD:
2418       result = "BAD signature";
2419       break;
2420     case GPGME_SIG_STAT_NOKEY:
2421       result = "No public key to verify the signature";
2422       break;
2423     case GPGME_SIG_STAT_ERROR:
2424       result = "Error verifying the signature";
2425       break;
2426     case GPGME_SIG_STAT_DIFF:
2427       result = "Different results for signatures";
2428       break;
2429     default:
2430       result = "Error: Unknown status";
2431       break;
2432   }
2433
2434   return result;
2435 }
2436
2437
2438 bool checkMessageSignature( char** cleartext,
2439                             const char* signaturetext,
2440                             bool signatureIsBinary,
2441                             int signatureLen,
2442                             struct SignatureMetaData* sigmeta )
2443 {
2444   GpgmeCtx ctx;
2445   GpgmeSigStat status;
2446   unsigned long sumGPGME;
2447   SigStatusFlags sumPlug;
2448   GpgmeData datapart, sigpart;
2449   char* rClear = 0;
2450   size_t clearLen;
2451   GpgmeError err;
2452   GpgmeKey key;
2453   time_t created;
2454   struct DnPair* a;
2455   char* dn;
2456   int sig_idx=0;
2457   int UID_idx=0;
2458   const char* statusStr;
2459   const char* fpr;
2460   bool isOpaqueSigned;
2461   
2462   if( !cleartext ) {
2463     if( sigmeta )
2464       storeNewCharPtr( &sigmeta->status,
2465                         __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO );
2466
2467     return false;
2468   }
2469
2470   isOpaqueSigned = !*cleartext;
2471
2472   gpgme_new( &ctx );
2473   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
2474   gpgme_set_armor (ctx,    signatureIsBinary ? 0 : 1);
2475   /*  gpgme_set_textmode (ctx, signatureIsBinary ? 0 : 1); */
2476
2477   if( isOpaqueSigned )
2478     gpgme_data_new( &datapart );
2479   else
2480     gpgme_data_new_from_mem( &datapart, *cleartext,
2481                              strlen( *cleartext ), 1 );
2482
2483   gpgme_data_new_from_mem( &sigpart,
2484                            signaturetext,
2485                            signatureIsBinary
2486                            ? signatureLen
2487                            : strlen( signaturetext ),
2488                            1 );
2489
2490   gpgme_op_verify( ctx, sigpart, datapart, &status );
2491
2492   if( isOpaqueSigned ) {
2493     rClear = gpgme_data_release_and_get_mem( datapart, &clearLen );
2494     *cleartext = malloc( clearLen + 1 );
2495     if( *cleartext ) {
2496       if( clearLen )
2497         strncpy(*cleartext, rClear, clearLen );
2498       (*cleartext)[clearLen] = '\0';
2499     }
2500     free( rClear );
2501   }
2502   else
2503     gpgme_data_release( datapart );
2504
2505   gpgme_data_release( sigpart );
2506
2507   /* Provide information in the sigmeta struct */
2508   /* the status string */
2509   statusStr = sig_status_to_string( status );
2510   sigmeta->status = malloc( strlen( statusStr ) + 1 );
2511   if( sigmeta->status ) {
2512     strcpy( sigmeta->status, statusStr );
2513     sigmeta->status[strlen( statusStr )] = '\0';
2514   } else
2515     ; /* nothing to do, is already 0 */
2516
2517   /* Extended information for any number of signatures. */
2518   fpr = gpgme_get_sig_status( ctx, sig_idx, &status, &created );
2519   sigmeta->extended_info = 0;
2520   while( fpr != NULL ) {
2521     struct tm* ctime_val;
2522     const char* sig_status;
2523
2524     void* alloc_return = realloc( sigmeta->extended_info,
2525                                   sizeof( struct SignatureMetaDataExtendedInfo )
2526                                   * ( sig_idx + 1 ) );
2527     if( alloc_return ) {
2528       sigmeta->extended_info = alloc_return;
2529
2530       /* clear the data area */
2531       memset( &sigmeta->extended_info[sig_idx], 
2532               0,
2533               sizeof (struct SignatureMetaDataExtendedInfo) );
2534
2535       /* the creation time */
2536       sigmeta->extended_info[sig_idx].creation_time = malloc( sizeof( struct tm ) );
2537       if( sigmeta->extended_info[sig_idx].creation_time ) {
2538         ctime_val = localtime( &created );
2539         memcpy( sigmeta->extended_info[sig_idx].creation_time,
2540                 ctime_val, sizeof( struct tm ) );
2541       }
2542
2543       /* the extended signature verification status */
2544       sumGPGME = gpgme_get_sig_ulong_attr( ctx,
2545                                            sig_idx,
2546                                            GPGME_ATTR_SIG_SUMMARY,
2547                                            0 );
2548       fprintf( stderr, "gpgmeplug checkMessageSignature status flags: %lX\n", sumGPGME );
2549       // translate GPGME status flags to common CryptPlug status flags
2550       sumPlug = 0;
2551       if( sumGPGME & GPGME_SIGSUM_VALID       ) sumPlug |= SigStat_VALID      ;
2552       if( sumGPGME & GPGME_SIGSUM_GREEN       ) sumPlug |= SigStat_GREEN      ;
2553       if( sumGPGME & GPGME_SIGSUM_RED         ) sumPlug |= SigStat_RED        ;
2554       if( sumGPGME & GPGME_SIGSUM_KEY_REVOKED ) sumPlug |= SigStat_KEY_REVOKED;
2555       if( sumGPGME & GPGME_SIGSUM_KEY_EXPIRED ) sumPlug |= SigStat_KEY_EXPIRED;
2556       if( sumGPGME & GPGME_SIGSUM_SIG_EXPIRED ) sumPlug |= SigStat_SIG_EXPIRED;
2557       if( sumGPGME & GPGME_SIGSUM_KEY_MISSING ) sumPlug |= SigStat_KEY_MISSING;
2558       if( sumGPGME & GPGME_SIGSUM_CRL_MISSING ) sumPlug |= SigStat_CRL_MISSING;
2559       if( sumGPGME & GPGME_SIGSUM_CRL_TOO_OLD ) sumPlug |= SigStat_CRL_TOO_OLD;
2560       if( sumGPGME & GPGME_SIGSUM_BAD_POLICY  ) sumPlug |= SigStat_BAD_POLICY ;
2561       if( sumGPGME & GPGME_SIGSUM_SYS_ERROR   ) sumPlug |= SigStat_SYS_ERROR  ;
2562       if( !sumPlug )
2563         sumPlug = SigStat_NUMERICAL_CODE | sumGPGME;
2564       sigmeta->extended_info[sig_idx].sigStatusFlags = sumPlug;
2565
2566       sigmeta->extended_info[sig_idx].validity = GPGME_VALIDITY_UNKNOWN;
2567
2568       err = gpgme_get_sig_key (ctx, sig_idx, &key);
2569
2570       if ( err == GPGME_No_Error) {
2571         const char* attr_string;
2572         unsigned long attr_ulong;
2573
2574         /* extract key identidy */
2575         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_KEYID, 0, 0);
2576         if (attr_string != 0)
2577             storeNewCharPtr( &sigmeta->extended_info[sig_idx].keyid, attr_string );
2578
2579         /* extract finger print */
2580         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_FPR, 0, 0);
2581         if (attr_string != 0)
2582             storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint,
2583                             attr_string );
2584
2585         /* algorithms useable with this key */
2586         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_ALGO, 0, 0);
2587         if (attr_string != 0)
2588             storeNewCharPtr( &sigmeta->extended_info[sig_idx].algo,
2589                             attr_string );
2590         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_ALGO, 0, 0);
2591         sigmeta->extended_info[sig_idx].algo_num = attr_ulong;
2592
2593         /* extract key validity */
2594         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_VALIDITY, 0, 0);
2595         sigmeta->extended_info[sig_idx].validity = attr_ulong;
2596
2597         /* extract user id, according to the documentation it's representable
2598         * as a number, but it seems that it also has a string representation
2599         */
2600         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_USERID, 0, 0);
2601         if (attr_string != 0) {
2602             a = parse_dn( attr_string );
2603             dn = reorder_dn( a );
2604             storeNewCharPtr( &sigmeta->extended_info[sig_idx].userid,
2605                              dn );
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             dn = reorder_dn( a );
2628             storeNewCharPtr( &sigmeta->extended_info[sig_idx].name,
2629                              dn );
2630         }
2631
2632         /* extract email(s) */
2633         sigmeta->extended_info[sig_idx].emailCount = 0;
2634         sigmeta->extended_info[sig_idx].emailList = 0;
2635         for( UID_idx=0; 
2636              (attr_string = gpgme_key_get_string_attr(key,
2637                               GPGME_ATTR_EMAIL, 0, UID_idx)); 
2638              ++UID_idx ){
2639           if (*attr_string) {
2640             fprintf( stderr, "gpgmeplug checkMessageSignature found email: %s\n", attr_string );
2641             if( sigmeta->extended_info[sig_idx].emailCount )
2642                 alloc_return = 
2643                     malloc( sizeof( char*) );
2644             else
2645                 alloc_return = 
2646                     realloc( sigmeta->extended_info[sig_idx].emailList,
2647                              sizeof( char*)
2648                              * (sigmeta->extended_info[sig_idx].emailCount + 1) );
2649             if( alloc_return ) {
2650               sigmeta->extended_info[sig_idx].emailList = alloc_return;
2651               storeNewCharPtr( 
2652                   &( sigmeta->extended_info[sig_idx].emailList[
2653                           sigmeta->extended_info[sig_idx].emailCount ] ),
2654                   attr_string );
2655               ++sigmeta->extended_info[sig_idx].emailCount;
2656             }
2657           }
2658         }
2659         if( !sigmeta->extended_info[sig_idx].emailCount )
2660           fprintf( stderr, "gpgmeplug checkMessageSignature found NO EMAIL\n" );
2661
2662         /* extract the comment */
2663         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_COMMENT, 0, 0);
2664         if (attr_string != 0)
2665             storeNewCharPtr( &sigmeta->extended_info[sig_idx].comment,
2666                             attr_string );
2667       }
2668       else
2669         storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint, fpr );
2670
2671       sig_status = sig_status_to_string( status );
2672       storeNewCharPtr( &sigmeta->extended_info[sig_idx].status_text,
2673                        sig_status );
2674
2675     } else
2676       break; /* if allocation fails once, it isn't likely to
2677                 succeed the next time either */
2678
2679     fpr = gpgme_get_sig_status (ctx, ++sig_idx, &status, &created);
2680   }
2681   sigmeta->extended_info_count = sig_idx;
2682   sigmeta->nota_xml = gpgme_get_notation( ctx );
2683   sigmeta->status_code = status;
2684
2685   gpgme_release( ctx );
2686   return ( status == GPGME_SIG_STAT_GOOD );
2687 }
2688