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