f603008395183fd4d7175fd292a868ed0335f0b5
[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", err );
1457     if( errId )
1458       *errId = err;
1459     if( errTxt ) {
1460       const char* _errTxt = gpgme_strerror( err );
1461       *errTxt = malloc( strlen( _errTxt ) + 100 ); // leave room for reason string
1462       if( *errTxt ) {
1463         char* opInfo;
1464         strcpy(*errTxt, _errTxt );
1465         opInfo = gpgme_get_op_info(ctx, 0);
1466         if( NULL != opInfo && *opInfo ){
1467           const int opLen = strlen( opInfo );
1468           const int reasonLen = 8;
1469           char reason[ 1+reasonLen ];
1470           char* pos1;
1471           strcpy( reason, "<reason>" );
1472           pos1 = strstr( opInfo, reason );
1473           if( NULL != pos1 && 
1474               opLen > reasonLen + (pos1 - opInfo) ){
1475             char* pos2;
1476             pos1 += reasonLen;
1477             pos2 = strchr( pos1, '<' );
1478             if( NULL != pos2 &&
1479                 pos1 < pos2 ){
1480               long int reasonId;
1481               strcat( *errTxt, " - " );
1482               *pos2 = '\0';
1483               fprintf( stderr, "                        and this reason code:  %s\n\n", pos1 );
1484               reasonId = strtol( pos1, NULL, 10 );
1485               switch( reasonId ) {
1486                 case  0: strcat( *errTxt, "No specific reason given" );
1487                          break;
1488                 case  1: strcat( *errTxt, "Not Found" );
1489                          break;
1490                 case  2: strcat( *errTxt, "Ambigious specification" );
1491                          break;
1492                 case  3: strcat( *errTxt, "Key can't be used for operation" );
1493                          break;
1494                 case  4: strcat( *errTxt, "Key has been revoked" );
1495                          break;
1496                 case  5: strcat( *errTxt, "Key has expired" );
1497                          break;
1498                 case  6: strcat( *errTxt, "No CRL known for certificate" );
1499                          break;
1500                 case  7: strcat( *errTxt, "No current CRL available" );
1501                          break;
1502                 case  8: strcat( *errTxt, "Contraints not matched" );
1503                          break;
1504                 default: {
1505                            strcat( *errTxt, "Extended error Id: #" );
1506                            strcat( *errTxt, pos1 );
1507                          }  
1508               }
1509               *pos2 = '<';
1510             }
1511           }
1512           free( opInfo );
1513         }
1514       }
1515     }
1516   }
1517
1518   gpgme_recipients_release (rset);
1519   gpgme_data_release (gPlaintext);
1520
1521   if( err == GPGME_No_Error ) {
1522     if( __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ) {
1523       *ciphertext = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1524       bOk = true;
1525     }
1526     else {
1527       rCiph = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1528       *ciphertext = malloc( *cipherLen + 1 );
1529       if( *ciphertext ) {
1530         if( *cipherLen ) {
1531           bOk = true;
1532           strncpy((char*)*ciphertext, rCiph, *cipherLen );
1533         }
1534         ((char*)(*ciphertext))[*cipherLen] = 0;
1535       }
1536       free( rCiph );
1537     }
1538   }
1539   else {
1540     gpgme_data_release ( gCiphertext );
1541     *ciphertext = 0;
1542     /* error handling is missing: if only one untrusted key was found
1543       (or none at all), gpg won't sign the message.  (hier fehlt eine
1544       Fehlerbehandlung: fuer einen Recipient nur ein untrusted key
1545       (oder gar keiner) gefunden wurde, verweigert gpg das signieren.)
1546     */
1547   }
1548
1549   gpgme_release (ctx);
1550
1551   fflush( stderr );
1552
1553   if( bOk && structuring ) {
1554     structuring->includeCleartext = GPGMEPLUG_ENC_INCLUDE_CLEARTEXT;
1555     structuring->makeMimeObject   = GPGMEPLUG_ENC_MAKE_MIME_OBJECT;
1556     if( structuring->makeMimeObject ) {
1557       structuring->makeMultiMime  = GPGMEPLUG_ENC_MAKE_MULTI_MIME;
1558       storeNewCharPtr( &structuring->contentTypeMain,
1559                        GPGMEPLUG_ENC_CTYPE_MAIN );
1560       storeNewCharPtr( &structuring->contentDispMain,
1561                        GPGMEPLUG_ENC_CDISP_MAIN );
1562       storeNewCharPtr( &structuring->contentTEncMain,
1563                        GPGMEPLUG_ENC_CTENC_MAIN );
1564       if( structuring->makeMultiMime ) {
1565         storeNewCharPtr( &structuring->contentTypeVersion,
1566                          GPGMEPLUG_ENC_CTYPE_VERSION );
1567         storeNewCharPtr( &structuring->contentDispVersion,
1568                          GPGMEPLUG_ENC_CDISP_VERSION );
1569         storeNewCharPtr( &structuring->contentTEncVersion,
1570                          GPGMEPLUG_ENC_CTENC_VERSION );
1571         storeNewCharPtr( &structuring->bodyTextVersion,
1572                          GPGMEPLUG_ENC_BTEXT_VERSION );
1573         storeNewCharPtr( &structuring->contentTypeCode,
1574                          GPGMEPLUG_ENC_CTYPE_CODE );
1575         storeNewCharPtr( &structuring->contentDispCode,
1576                          GPGMEPLUG_ENC_CDISP_CODE );
1577         storeNewCharPtr( &structuring->contentTEncCode,
1578                          GPGMEPLUG_ENC_CTENC_CODE );
1579       }
1580     } else {
1581       storeNewCharPtr( &structuring->flatTextPrefix,
1582                        GPGMEPLUG_ENC_FLAT_PREFIX );
1583       storeNewCharPtr( &structuring->flatTextSeparator,
1584                        GPGMEPLUG_ENC_FLAT_SEPARATOR );
1585       storeNewCharPtr( &structuring->flatTextPostfix,
1586                        GPGMEPLUG_ENC_FLAT_POSTFIX );
1587     }
1588   }
1589   return bOk;
1590 }
1591
1592
1593 bool encryptAndSignMessage( const char* cleartext,
1594                             const char** ciphertext,
1595                             const char* certificate,
1596                             struct StructuringInfo* structuring )
1597 {
1598   bool bOk;
1599
1600   init_StructuringInfo( structuring );
1601
1602   bOk = false;
1603
1604   /* implementation of this function is still missing */
1605
1606   if( bOk && structuring ) {
1607     structuring->includeCleartext = GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT;
1608     structuring->makeMimeObject   = GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT;
1609     if( structuring->makeMimeObject ) {
1610       structuring->makeMultiMime  = GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME;
1611       storeNewCharPtr( &structuring->contentTypeMain,
1612                        GPGMEPLUG_ENCSIGN_CTYPE_MAIN );
1613       storeNewCharPtr( &structuring->contentDispMain,
1614                        GPGMEPLUG_ENCSIGN_CDISP_MAIN );
1615       storeNewCharPtr( &structuring->contentTEncMain,
1616                        GPGMEPLUG_ENCSIGN_CTENC_MAIN );
1617       if( structuring->makeMultiMime ) {
1618         storeNewCharPtr( &structuring->contentTypeVersion,
1619                          GPGMEPLUG_ENCSIGN_CTYPE_VERSION );
1620         storeNewCharPtr( &structuring->contentDispVersion,
1621                          GPGMEPLUG_ENCSIGN_CDISP_VERSION );
1622         storeNewCharPtr( &structuring->contentTEncVersion,
1623                          GPGMEPLUG_ENCSIGN_CTENC_VERSION );
1624         storeNewCharPtr( &structuring->bodyTextVersion,
1625                          GPGMEPLUG_ENCSIGN_BTEXT_VERSION );
1626         storeNewCharPtr( &structuring->contentTypeCode,
1627                          GPGMEPLUG_ENCSIGN_CTYPE_CODE );
1628         storeNewCharPtr( &structuring->contentDispCode,
1629                          GPGMEPLUG_ENCSIGN_CDISP_CODE );
1630         storeNewCharPtr( &structuring->contentTEncCode,
1631                          GPGMEPLUG_ENCSIGN_CTENC_CODE );
1632       }
1633     } else {
1634       storeNewCharPtr( &structuring->flatTextPrefix,
1635                        GPGMEPLUG_ENCSIGN_FLAT_PREFIX );
1636       storeNewCharPtr( &structuring->flatTextSeparator,
1637                        GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR );
1638       storeNewCharPtr( &structuring->flatTextPostfix,
1639                        GPGMEPLUG_ENCSIGN_FLAT_POSTFIX );
1640     }
1641   }
1642   return bOk;
1643 }
1644
1645
1646 bool decryptMessage( const char* ciphertext,
1647                      bool        cipherIsBinary,
1648                      int         cipherLen,
1649                      const char** cleartext,
1650                      const char* certificate,
1651                      int* errId,
1652                      char** errTxt )
1653 {
1654   GpgmeCtx ctx;
1655   GpgmeError err;
1656   GpgmeData gCiphertext, gPlaintext;
1657   size_t rCLen = 0;
1658   char*  rCiph = 0;
1659   bool bOk = false;
1660
1661   if( !ciphertext )
1662     return false;
1663
1664   err = gpgme_new (&ctx);
1665   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1666   
1667   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
1668   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
1669
1670   /*
1671   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
1672                            1+strlen( ciphertext ), 1 ); */
1673   gpgme_data_new_from_mem( &gCiphertext,
1674                            ciphertext,
1675                            cipherIsBinary
1676                            ? cipherLen
1677                            : strlen( ciphertext ),
1678                            1 );
1679
1680   gpgme_data_new( &gPlaintext );
1681
1682   err = err = gpgme_op_decrypt( ctx, gCiphertext, gPlaintext );
1683   if( err ) {
1684     fprintf( stderr, "\ngpgme_op_decrypt() returned this error code:  %i\n\n", err );
1685     if( errId )
1686       *errId = err;
1687     if( errTxt ) {
1688       const char* _errTxt = gpgme_strerror( err );
1689       *errTxt = malloc( strlen( _errTxt ) + 1 );
1690       if( *errTxt )
1691         strcpy(*errTxt, _errTxt );
1692     }
1693   }
1694   
1695   gpgme_data_release( gCiphertext );
1696
1697   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
1698
1699   *cleartext = malloc( rCLen + 1 );
1700   if( *cleartext ) {
1701       if( rCLen ) {
1702           bOk = true;
1703           strncpy((char*)*cleartext, rCiph, rCLen );
1704       }
1705       ((char*)(*cleartext))[rCLen] = 0;
1706   }
1707
1708   free( rCiph );
1709   gpgme_release( ctx );
1710   return bOk;
1711 }
1712
1713 bool decryptAndCheckMessage( const char* ciphertext,
1714           const char** cleartext, const char* certificate,
1715           struct SignatureMetaData* sigmeta ){ return true; }
1716
1717
1718 const char* requestCertificateDialog(){ return 0; }
1719
1720
1721 /* The buffer generatedKey contains the LEN bytes you want.
1722    Caller is responsible for freeing. */
1723 bool requestDecentralCertificate( const char* certparms, 
1724                                   char** generatedKey, int* length )
1725 {
1726     GpgmeError err;
1727     GpgmeCtx ctx;
1728     GpgmeData pub;
1729     int len;
1730
1731     err = gpgme_data_new (&pub);
1732     fprintf( stderr,  "1: gpgme returned %d\n", err );
1733     if( err != GPGME_No_Error )
1734         return false;
1735
1736     err = gpgme_new (&ctx);
1737     fprintf( stderr,  "2: gpgme returned %d\n", err );
1738     if( err != GPGME_No_Error ) {
1739         gpgme_data_release( pub );
1740         return false;
1741     }
1742
1743     gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
1744     /* Don't ASCII-armor, the MUA will use base64 encoding */
1745     /*    gpgme_set_armor (ctx, 1); */
1746     err = gpgme_op_genkey (ctx, certparms, pub, NULL );
1747     fprintf( stderr,  "3: gpgme returned %d\n", err );
1748     if( err != GPGME_No_Error ) {
1749         gpgme_data_release( pub );
1750         gpgme_release( ctx );
1751         return false;
1752     }
1753
1754     gpgme_release (ctx);
1755     *generatedKey = gpgme_data_release_and_get_mem (pub, &len);
1756     *length = len;
1757
1758     return true;
1759 }
1760
1761 bool requestCentralCertificateAndPSE( const char* name,
1762           const char* email, const char* organization, const char* department,
1763           const char* ca_address ){ return true; }
1764
1765 bool createPSE(){ return true; }
1766
1767 bool registerCertificate( const char* certificate ){ return true; }
1768
1769 bool requestCertificateProlongation( const char* certificate,
1770                                      const char* ca_address ){ return true; }
1771
1772 const char* certificateChain(){ return 0; }
1773
1774 bool deleteCertificate( const char* certificate ){ return true; }
1775
1776 bool archiveCertificate( const char* certificate ){ return true; }
1777
1778
1779 const char* displayCRL(){ return 0; }
1780
1781 void updateCRL(){}
1782
1783
1784 char *
1785 trim_trailing_spaces( char *string )
1786 {
1787     char *p, *mark;
1788
1789     for( mark = NULL, p = string; *p; p++ ) {
1790         if( isspace( *p ) ) {
1791             if( !mark )
1792                 mark = p;
1793         }
1794         else
1795             mark = NULL;
1796     }
1797     if( mark )
1798         *mark = '\0' ;
1799
1800     return string ;
1801 }
1802
1803 /* Parse a DN and return an array-ized one.  This is not a validating
1804    parser and it does not support any old-stylish syntax; gpgme is
1805    expected to return only rfc2253 compatible strings. */
1806 static const unsigned char *
1807 parse_dn_part (struct DnPair *array, const unsigned char *string)
1808 {
1809   const unsigned char *s, *s1;
1810   size_t n;
1811   unsigned char *p;
1812
1813   /* parse attributeType */
1814   for (s = string+1; *s && *s != '='; s++)
1815     ;
1816   if (!*s)
1817     return NULL; /* error */
1818   n = s - string;
1819   if (!n)
1820     return NULL; /* empty key */
1821   array->key = p = xmalloc (n+1);
1822   
1823   
1824   memcpy (p, string, n);
1825   p[n] = 0;
1826   trim_trailing_spaces (p);
1827   if ( !strcmp (p, "1.2.840.113549.1.9.1") )
1828     strcpy (p, "EMail");
1829   string = s + 1;
1830
1831   if (*string == '#')
1832     { /* hexstring */
1833       string++;
1834       for (s=string; hexdigitp (s); s++)
1835         s++;
1836       n = s - string;
1837       if (!n || (n & 1))
1838         return NULL; /* empty or odd number of digits */
1839       n /= 2;
1840       array->value = p = xmalloc (n+1);
1841       
1842       
1843       for (s1=string; n; s1 += 2, n--)
1844         *p++ = xtoi_2 (s1);
1845       *p = 0;
1846    }
1847   else
1848     { /* regular v3 quoted string */
1849       for (n=0, s=string; *s; s++)
1850         {
1851           if (*s == '\\')
1852             { /* pair */
1853               s++;
1854               if (*s == ',' || *s == '=' || *s == '+'
1855                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
1856                   || *s == '\\' || *s == '\"' || *s == ' ')
1857                 n++;
1858               else if (hexdigitp (s) && hexdigitp (s+1))
1859                 {
1860                   s++;
1861                   n++;
1862                 }
1863               else
1864                 return NULL; /* invalid escape sequence */
1865             }
1866           else if (*s == '\"')
1867             return NULL; /* invalid encoding */
1868           else if (*s == ',' || *s == '=' || *s == '+'
1869                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
1870             break; 
1871           else
1872             n++;
1873         }
1874
1875       array->value = p = xmalloc (n+1);
1876       
1877       
1878       for (s=string; n; s++, n--)
1879         {
1880           if (*s == '\\')
1881             { 
1882               s++;
1883               if (hexdigitp (s))
1884                 {
1885                   *p++ = xtoi_2 (s);
1886                   s++;
1887                 }
1888               else
1889                 *p++ = *s;
1890             }
1891           else
1892             *p++ = *s;
1893         }
1894       *p = 0;
1895     }
1896   return s;
1897 }
1898
1899
1900 /* Parse a DN and return an array-ized one.  This is not a validating
1901    parser and it does not support any old-stylish syntax; gpgme is
1902    expected to return only rfc2253 compatible strings. */
1903 static struct DnPair *
1904 parse_dn (const unsigned char *string)
1905 {
1906   struct DnPair *array;
1907   size_t arrayidx, arraysize;
1908   int i;
1909
1910   if( !string )
1911     return NULL;
1912
1913   arraysize = 7; /* C,ST,L,O,OU,CN,email */
1914   arrayidx = 0;
1915   array = xmalloc ((arraysize+1) * sizeof *array);
1916   
1917   
1918   while (*string)
1919     {
1920       while (*string == ' ')
1921         string++;
1922       if (!*string)
1923         break; /* ready */
1924       if (arrayidx >= arraysize)
1925         { /* mutt lacks a real safe_realoc - so we need to copy */
1926           struct DnPair *a2;
1927
1928           arraysize += 5;
1929           a2 = xmalloc ((arraysize+1) * sizeof *array);
1930           for (i=0; i < arrayidx; i++)
1931             {
1932               a2[i].key = array[i].key;
1933               a2[i].value = array[i].value;
1934             }
1935           free (array);
1936           array = a2;
1937         }
1938       array[arrayidx].key = NULL;
1939       array[arrayidx].value = NULL;
1940       string = parse_dn_part (array+arrayidx, string);
1941       arrayidx++;
1942       if (!string)
1943         goto failure;
1944       while (*string == ' ')
1945         string++;
1946       if (*string && *string != ',' && *string != ';' && *string != '+')
1947         goto failure; /* invalid delimiter */
1948       if (*string)
1949         string++;
1950     }
1951   array[arrayidx].key = NULL;
1952   array[arrayidx].value = NULL;
1953   return array;
1954
1955  failure:
1956   for (i=0; i < arrayidx; i++)
1957     {
1958       free (array[i].key);
1959       free (array[i].value);
1960     }
1961   free (array);
1962   return NULL;
1963 }
1964
1965 static int 
1966 add_dn_part( char* result, struct DnPair* dn, const char* part )
1967 {
1968   int any = 0;
1969
1970   if( dn ) {
1971     for(; dn->key; ++dn ) {
1972       if( !strcmp( dn->key, part ) ) {
1973         if( any ) strcat( result, "+" );
1974         /* email hack */
1975         if( !strcmp( part, "1.2.840.113549.1.9.1" ) ) strcat( result, "EMail" );
1976         else strcat( result, part );
1977         strcat( result, "=" );
1978         strcat( result, dn->value );
1979         any = 1;
1980       }
1981     }
1982   }
1983   return any;
1984 }
1985
1986 static char* 
1987 reorder_dn( struct DnPair *dn )
1988 {
1989   /* note: The must parts are: CN, L, OU, O, C */
1990   const char* stdpart[] = {
1991     "CN", "S", "SN", "GN", "T", "UID",
1992           "MAIL", "EMAIL", "MOBILE", "TEL", "FAX", "STREET",
1993     "L",  "PC", "SP", "ST",
1994     "OU",
1995     "O",
1996     "C",
1997     NULL
1998   };
1999   int any=0, any2=0, len=0, i;
2000   char* result;
2001   if( dn ) {
2002     for( i = 0; dn[i].key; ++i ) {
2003       len += strlen( dn[i].key );
2004       len += strlen( dn[i].value );
2005       len += 4; /* ',' and '=', and possibly "(" and ")" */
2006     }
2007   }
2008   result = xmalloc( (len+1)*sizeof(char) );
2009   *result = 0;
2010
2011   /* add standard parts */
2012   for( i = 0; stdpart[i]; ++i ) {
2013     if( any ) {
2014       strcat( result, "," );
2015     }
2016     any = add_dn_part( result, dn, stdpart[i] );
2017   }
2018
2019   /* add remaining parts in no particular order */
2020   if( dn ) {
2021     for(; dn->key; ++dn ) {
2022       for( i = 0; stdpart[i]; ++i ) {
2023         if( !strcmp( dn->key, stdpart[i] ) ) {
2024           break;
2025         }
2026       }
2027       if( !stdpart[i] ) {
2028         if( any ) strcat( result, "," );
2029         if( !any2 ) strcat( result, "(");
2030         any = add_dn_part( result, dn, dn->key );
2031         any2 = 1;
2032       }
2033     }
2034   }
2035   if( any2 ) strcat( result, ")");
2036   return result;
2037 }
2038
2039 struct CertIterator {
2040   GpgmeCtx ctx;  
2041   struct CertificateInfo info;
2042 };
2043
2044 struct CertIterator* 
2045 startListCertificates( const char* pattern, int remote )
2046 {
2047     GpgmeError err;
2048     struct CertIterator* it;
2049     const char* patterns[] = { pattern, NULL };
2050     fprintf( stderr,  "startListCertificates( \"%s\", %d )\n", pattern, remote );
2051
2052     it = xmalloc( sizeof( struct CertIterator ) );
2053
2054     err = gpgme_new (&(it->ctx));
2055     /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2056     if( err != GPGME_No_Error ) {
2057       free( it );
2058       return NULL;
2059     }
2060
2061     gpgme_set_protocol (it->ctx, GPGME_PROTOCOL_CMS);
2062     if( remote ) gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_EXTERN ); 
2063     else gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_LOCAL );
2064     err =  gpgme_op_keylist_ext_start ( it->ctx, patterns, 0, 0);
2065     if( err != GPGME_No_Error ) {
2066       fprintf( stderr,  "gpgme_op_keylist_ext_start returned %d", err );
2067       endListCertificates( it );
2068       return NULL;
2069     }
2070     memset( &(it->info), 0, sizeof( struct CertificateInfo ) );
2071     return it;
2072 }
2073
2074 /* free() each string in a char*[] and the array itself */
2075 static void 
2076 freeStringArray( char** c )
2077 {
2078     char** _c = c;
2079
2080     while( c && *c ) {
2081       /*fprintf( stderr, "freeing \"%s\"\n", *c );*/
2082       free( *c );
2083       ++c;
2084     }
2085     free( _c );
2086 }
2087
2088 /* free all malloc'ed data in a struct CertificateInfo */
2089 static void 
2090 freeInfo( struct CertificateInfo* info )
2091 {
2092   struct DnPair* a = info->dnarray;
2093   assert( info );
2094   freeStringArray( info->userid );
2095   free( info->serial);
2096   free( info->fingerprint );
2097   free( info->issuer );
2098   free( info->chainid );
2099   free( info->caps );
2100   while( a && a->key && a->value ) {
2101     free (a->key);
2102     free (a->value);
2103     ++a;
2104   }
2105   free (info->dnarray);
2106   memset( info, 0, sizeof( *info ) );
2107 }
2108
2109 /* Format the fingerprint nicely. The caller should
2110    free the returned value using free() */
2111 static char* make_fingerprint( const char* fpr )
2112 {
2113   int len = strlen(fpr);
2114   int i = 0;
2115   char* result = xmalloc( (len + len/2 + 1)*sizeof(char) );
2116
2117   for(; *fpr; ++fpr, ++i ) {
2118     if( i%3 == 2) {
2119       result[i] = ':'; ++i;
2120     }
2121     result[i] = *fpr;
2122   }
2123   result[i] = 0;
2124   return result;
2125 }
2126
2127 int 
2128 nextCertificate( struct CertIterator* it, struct CertificateInfo** result )
2129 {
2130   GpgmeError err;
2131   GpgmeKey   key;
2132   int retval = GPGME_No_Error;
2133   assert( it );
2134   fprintf( stderr,  "nextCertificates( %p, %p )\n", it, result );
2135   err = gpgme_op_keylist_next ( it->ctx, &key);
2136   if( err != GPGME_EOF ) {   
2137     int idx;
2138     const char* s;
2139     unsigned long u;
2140     char* names[MAX_GPGME_IDX+1];
2141     struct DnPair *issuer_dn, *tmp_dn;
2142     retval = err;
2143     memset( names, 0, sizeof( names ) );
2144     freeInfo( &(it->info) );
2145
2146     for( idx = 0; (s = gpgme_key_get_string_attr (key, GPGME_ATTR_USERID, 0, idx)) && idx < MAX_GPGME_IDX; 
2147          ++idx ) {
2148       names[idx] = xstrdup( s );
2149     }
2150     
2151     it->info.userid = xmalloc( sizeof( char* ) * (idx+1) );
2152     memset( it->info.userid, 0, sizeof( char* ) * (idx+1) );
2153     it->info.dnarray = 0;
2154     for( idx = 0; names[idx] != 0; ++idx ) {
2155       struct DnPair* a = parse_dn( names[idx] ); 
2156       if( idx == 0 ) {
2157         it->info.userid[idx] = reorder_dn( a );
2158         it->info.dnarray = a;
2159         free (names[idx]);
2160         names[idx] = NULL;
2161       } else {
2162         it->info.userid[idx] = names[idx];
2163       }
2164     }
2165     it->info.userid[idx] = 0;
2166
2167     s = gpgme_key_get_string_attr (key, GPGME_ATTR_SERIAL, 0, 0); 
2168     it->info.serial = s? xstrdup(s) : NULL;
2169
2170     s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, 0, 0); 
2171     it->info.fingerprint = make_fingerprint( s );
2172
2173     s = gpgme_key_get_string_attr (key, GPGME_ATTR_ISSUER, 0, 0); 
2174     if( s ) {
2175       issuer_dn = tmp_dn = parse_dn( s );     
2176       /*it->info.issuer = xstrdup(s);*/
2177       it->info.issuer = reorder_dn( issuer_dn );
2178       while( tmp_dn->key ) {
2179         free( tmp_dn->key );
2180         free( tmp_dn->value );
2181         ++tmp_dn;
2182       }
2183       free( issuer_dn );
2184       issuer_dn = tmp_dn = NULL;
2185     } else {
2186       it->info.issuer = NULL;
2187     }
2188     s = gpgme_key_get_string_attr (key, GPGME_ATTR_CHAINID, 0, 0); 
2189     it->info.chainid = s? xstrdup(s): NULL;
2190
2191     s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEY_CAPS, 0, 0); 
2192     it->info.caps = s? xstrdup(s) : NULL;
2193
2194     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_CREATED, 0, 0); 
2195     it->info.created = u;
2196
2197     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_EXPIRE, 0, 0); 
2198     it->info.expire = u;
2199
2200     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_IS_SECRET, 0, 0); 
2201     it->info.secret = u;
2202
2203     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_UID_INVALID, 0, 0); 
2204     it->info.invalid = u;
2205
2206     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_EXPIRED, 0, 0); 
2207     it->info.expired = u;
2208
2209     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_DISABLED, 0, 0); 
2210     it->info.disabled = u;
2211
2212     gpgme_key_release (key);
2213     /*return &(it->info);*/
2214     *result =  &(it->info);
2215   } else {
2216     *result = NULL;
2217   }
2218   return retval;
2219 }
2220
2221 int
2222 endListCertificates( struct CertIterator* it )
2223 {
2224   char *s = gpgme_get_op_info (it->ctx, 0);
2225   int truncated = s && strstr (s, "<truncated/>");
2226   fprintf( stderr,  "endListCertificates( %p )\n", it );
2227   if( s ) free( s );
2228   assert(it);
2229   freeInfo( &(it->info) );
2230   gpgme_op_keylist_end(it->ctx);
2231   gpgme_release (it->ctx);
2232   free( it );
2233   return truncated;
2234 }
2235
2236 int
2237 importCertificateWithFPR( const char* fingerprint, char** additional_info )
2238 {
2239   GpgmeError err;
2240   GpgmeCtx  ctx;
2241   GpgmeData keydata;
2242   GpgmeRecipients recips;
2243   char* buf;
2244   const char* tmp1;
2245   char* tmp2;
2246
2247   err = gpgme_new( &ctx );
2248   /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2249   if( err != GPGME_No_Error ) {
2250     return err;
2251   }
2252   gpgme_set_protocol( ctx, GPGME_PROTOCOL_CMS );
2253   gpgme_set_keylist_mode( ctx, GPGME_KEYLIST_MODE_LOCAL );
2254
2255   err = gpgme_data_new( &keydata );
2256   if( err ) {
2257     fprintf( stderr,  "gpgme_data_new returned %d\n", err );
2258     gpgme_release( ctx );
2259     return err;
2260   }
2261
2262   err = gpgme_recipients_new( &recips );
2263   if( err ) {
2264     fprintf( stderr,  "gpgme_recipients_new returned %d\n", err );
2265     gpgme_data_release( keydata );
2266     gpgme_release( ctx );
2267     return err;
2268   }
2269   
2270   buf = malloc( sizeof(char)*( strlen( fingerprint ) + 1 ) );
2271   if( !buf ) {
2272     gpgme_recipients_release( recips );
2273     gpgme_data_release( keydata );    
2274     gpgme_release( ctx );
2275     return GPGME_Out_Of_Core;
2276   }
2277   tmp1 = fingerprint;
2278   tmp2 = buf;
2279   while( *tmp1 ) {
2280     if( *tmp1 != ':' ) *tmp2++ = *tmp1;
2281     tmp1++;
2282   }
2283   *tmp2 = 0;
2284   fprintf( stderr,  "calling gpgme_recipients_add_name( %s )\n", buf );  
2285   err = gpgme_recipients_add_name( recips, buf ); 
2286   if( err ) {
2287     fprintf( stderr,  "gpgme_recipients_add_name returned %d\n", err );
2288     free (buf);
2289     gpgme_recipients_release( recips );
2290     gpgme_data_release( keydata );    
2291     gpgme_release( ctx );
2292     return err;
2293   }
2294
2295   err = gpgme_op_export( ctx, recips, keydata );
2296   if( err ) {
2297     fprintf( stderr,  "gpgme_op_export returned %d\n", err );
2298     free (buf);
2299     *additional_info = gpgme_get_op_info( ctx, 0 );
2300     gpgme_recipients_release( recips );
2301     gpgme_data_release( keydata );    
2302     gpgme_release( ctx );
2303     return err;
2304   }
2305   free (buf);
2306   buf = NULL;
2307
2308   err = gpgme_op_import( ctx, keydata );
2309   *additional_info = gpgme_get_op_info( ctx, 0 );
2310   if( err ) {    
2311     fprintf( stderr,  "gpgme_op_import returned %d\n", err );
2312     gpgme_recipients_release( recips );
2313     gpgme_data_release( keydata );
2314     gpgme_release( ctx );
2315     return err;
2316   }
2317
2318   gpgme_recipients_release( recips );
2319   gpgme_data_release( keydata );    
2320   gpgme_release( ctx );
2321   return 0;
2322 }
2323 int
2324 importCertificateFromMem( const char* data, size_t length , char** additional_info )
2325 {
2326   GpgmeError err;
2327   GpgmeCtx  ctx;
2328   GpgmeData keydata;
2329
2330   err = gpgme_new( &ctx );
2331   /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2332   if( err != GPGME_No_Error ) {
2333     return err;
2334   }
2335   gpgme_set_protocol( ctx, GPGME_PROTOCOL_CMS );
2336   gpgme_set_keylist_mode( ctx, GPGME_KEYLIST_MODE_LOCAL );
2337
2338   err = gpgme_data_new_from_mem( &keydata, data, length, 0 );
2339   if( err ) {
2340     fprintf( stderr,  "gpgme_data_new returned %d\n", err );
2341     gpgme_release( ctx );
2342     return err;
2343   }
2344
2345   err = gpgme_op_import( ctx, keydata );
2346   *additional_info = gpgme_get_op_info( ctx, 0 );
2347   if( err ) {    
2348     fprintf( stderr,  "gpgme_op_import returned %d\n", err );
2349     gpgme_data_release( keydata );    
2350     gpgme_release( ctx );
2351     return err;
2352   }
2353
2354   gpgme_data_release( keydata );    
2355   gpgme_release( ctx );
2356   return 0;
2357 }
2358
2359 /*  == == == == == == == == == == == == == == == == == == == == == == == == ==
2360    ==                                                                      ==
2361   ==         Continuation of CryptPlug code                               ==
2362  ==                                                                      ==
2363 == == == == == == == == == == == == == == == == == == == == == == == == ==  */
2364
2365
2366 /*
2367   Find all certificate for a given addressee and return them in a
2368   '\1' separated list.
2369   NOTE: The certificate parameter must point to a not-yet allocated
2370         char*.  The function will allocate the memory needed and
2371         return the size in newSize.
2372   If secretOnly is true, only secret keys are returned.
2373 */
2374 bool findCertificates( const char* addressee,
2375                        char** certificates,
2376                        int* newSize,
2377                        bool secretOnly )
2378 {
2379 #define MAXCERTS 1024
2380   /* use const char declarations since all of them are needed twice */
2381   const char* delimiter = "\1";
2382   const char* openBracket = "    (";
2383   const char* closeBracket = ")";
2384
2385   GpgmeCtx ctx;
2386   GpgmeError err;
2387   GpgmeKey rKey;
2388   const char *s;
2389   const char *s2;
2390   char* dn;
2391   struct DnPair* a;
2392   int nFound = 0;
2393   int iFound = 0;
2394   int siz = 0;
2395   char* DNs[MAXCERTS];
2396   char* FPRs[MAXCERTS];
2397   
2398   if( ! certificates ){
2399     fprintf( stderr, "gpgme: findCertificates called with invalid *certificates pointer\n" );
2400     return false;
2401   }
2402
2403   if( ! newSize ){
2404     fprintf( stderr, "gpgme: findCertificates called with invalid newSize pointer\n" );
2405     return false;
2406   }
2407
2408   *certificates = 0;
2409   *newSize = 0;
2410   
2411   /* calculate length of buffer needed for certs plus fingerprints */
2412   gpgme_new (&ctx);
2413   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
2414   err = gpgme_op_keylist_start(ctx, addressee, secretOnly ? 1 : 0);
2415   while( GPGME_No_Error == err ) {
2416     err = gpgme_op_keylist_next(ctx, &rKey);
2417     if( GPGME_No_Error == err ) {
2418       s = gpgme_key_get_string_attr (rKey, GPGME_ATTR_USERID, NULL, 0);
2419       if( s ) {
2420         dn = xstrdup( s );
2421         s2 = gpgme_key_get_string_attr (rKey, GPGME_ATTR_FPR, NULL, 0);
2422         if( s2 ) {
2423           if( nFound )
2424             siz += strlen( delimiter );
2425           a = parse_dn( dn );
2426           free( dn );
2427           dn = reorder_dn( a );
2428           siz += strlen( dn );
2429           siz += strlen( openBracket );
2430           siz += strlen( s2 );
2431           siz += strlen( closeBracket );
2432           DNs[ nFound ] = dn;
2433           dn = NULL; /* prevent it from being free'ed below. */
2434           FPRs[nFound ] = xstrdup( s2 );
2435           ++nFound;
2436           if( nFound >= MAXCERTS ) {
2437             fprintf( stderr,
2438                      "gpgme: findCertificates found too many certificates (%d)\n",
2439                      MAXCERTS );
2440             break;
2441           }
2442         }
2443         free (dn); 
2444       }
2445     }
2446   }
2447   gpgme_op_keylist_end( ctx );
2448   gpgme_release (ctx);
2449   
2450   
2451   if( 0 < siz ) {
2452     /* add one for trailing ZERO char */
2453     ++siz;
2454     *newSize = siz;
2455     /* allocate the buffer */
2456     *certificates = xmalloc( sizeof(char) * siz );
2457     memset( *certificates, 0, sizeof(char) * siz );
2458     /* fill the buffer */
2459     for (iFound=0; iFound < nFound; iFound++) {
2460       if( !iFound )
2461         strcpy(*certificates, DNs[iFound] );
2462       else {
2463         strcat(*certificates, delimiter );
2464         strcat(*certificates, DNs[iFound] );
2465       }
2466       strcat(  *certificates, openBracket );
2467       strcat(  *certificates, FPRs[iFound] );
2468       strcat(  *certificates, closeBracket );
2469       free( DNs[ iFound ] );
2470       free( FPRs[iFound ] );
2471     }
2472   }
2473     
2474   return ( 0 < nFound );
2475 }
2476
2477
2478 static const char*
2479 sig_status_to_string( GpgmeSigStat status )
2480 {
2481   const char *result;
2482
2483   switch (status) {
2484     case GPGME_SIG_STAT_NONE:
2485       result = "Oops: Signature not verified";
2486       break;
2487     case GPGME_SIG_STAT_NOSIG:
2488       result = "No signature found";
2489       break;
2490     case GPGME_SIG_STAT_GOOD:
2491       result = "Good signature";
2492       break;
2493     case GPGME_SIG_STAT_BAD:
2494       result = "BAD signature";
2495       break;
2496     case GPGME_SIG_STAT_NOKEY:
2497       result = "No public key to verify the signature";
2498       break;
2499     case GPGME_SIG_STAT_ERROR:
2500       result = "Error verifying the signature";
2501       break;
2502     case GPGME_SIG_STAT_DIFF:
2503       result = "Different results for signatures";
2504       break;
2505     default:
2506       result = "Error: Unknown status";
2507       break;
2508   }
2509
2510   return result;
2511 }
2512
2513
2514 bool checkMessageSignature( char** cleartext,
2515                             const char* signaturetext,
2516                             bool signatureIsBinary,
2517                             int signatureLen,
2518                             struct SignatureMetaData* sigmeta )
2519 {
2520   GpgmeCtx ctx;
2521   GpgmeSigStat status;
2522   unsigned long sumGPGME;
2523   SigStatusFlags sumPlug;
2524   GpgmeData datapart, sigpart;
2525   char* rClear = 0;
2526   size_t clearLen;
2527   GpgmeError err;
2528   GpgmeKey key;
2529   time_t created;
2530   struct DnPair* a;
2531   int sig_idx=0;
2532   int UID_idx=0;
2533   const char* statusStr;
2534   const char* fpr;
2535   bool isOpaqueSigned;
2536   
2537   if( !cleartext ) {
2538     if( sigmeta )
2539       storeNewCharPtr( &sigmeta->status,
2540                         __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO );
2541
2542     return false;
2543   }
2544
2545   isOpaqueSigned = !*cleartext;
2546
2547   gpgme_new( &ctx );
2548   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
2549   gpgme_set_armor (ctx,    signatureIsBinary ? 0 : 1);
2550   /*  gpgme_set_textmode (ctx, signatureIsBinary ? 0 : 1); */
2551
2552   if( isOpaqueSigned )
2553     gpgme_data_new( &datapart );
2554   else
2555     gpgme_data_new_from_mem( &datapart, *cleartext,
2556                              strlen( *cleartext ), 1 );
2557
2558   gpgme_data_new_from_mem( &sigpart,
2559                            signaturetext,
2560                            signatureIsBinary
2561                            ? signatureLen
2562                            : strlen( signaturetext ),
2563                            1 );
2564
2565   gpgme_op_verify( ctx, sigpart, datapart, &status );
2566
2567   if( isOpaqueSigned ) {
2568     rClear = gpgme_data_release_and_get_mem( datapart, &clearLen );
2569     *cleartext = malloc( clearLen + 1 );
2570     if( *cleartext ) {
2571       if( clearLen )
2572         strncpy(*cleartext, rClear, clearLen );
2573       (*cleartext)[clearLen] = '\0';
2574     }
2575     free( rClear );
2576   }
2577   else
2578     gpgme_data_release( datapart );
2579
2580   gpgme_data_release( sigpart );
2581
2582   /* Provide information in the sigmeta struct */
2583   /* the status string */
2584   statusStr = sig_status_to_string( status );
2585   sigmeta->status = malloc( strlen( statusStr ) + 1 );
2586   if( sigmeta->status ) {
2587     strcpy( sigmeta->status, statusStr );
2588     sigmeta->status[strlen( statusStr )] = '\0';
2589   } else
2590     ; /* nothing to do, is already 0 */
2591
2592   /* Extended information for any number of signatures. */
2593   fpr = gpgme_get_sig_status( ctx, sig_idx, &status, &created );
2594   sigmeta->extended_info = 0;
2595   while( fpr != NULL ) {
2596     struct tm* ctime_val;
2597     const char* sig_status;
2598
2599     void* alloc_return = realloc( sigmeta->extended_info,
2600                                   sizeof( struct SignatureMetaDataExtendedInfo )
2601                                   * ( sig_idx + 1 ) );
2602     if( alloc_return ) {
2603       sigmeta->extended_info = alloc_return;
2604
2605       /* clear the data area */
2606       memset( &sigmeta->extended_info[sig_idx], 
2607               0,
2608               sizeof (struct SignatureMetaDataExtendedInfo) );
2609
2610       /* the creation time */
2611       sigmeta->extended_info[sig_idx].creation_time = malloc( sizeof( struct tm ) );
2612       if( sigmeta->extended_info[sig_idx].creation_time ) {
2613         ctime_val = localtime( &created );
2614         memcpy( sigmeta->extended_info[sig_idx].creation_time,
2615                 ctime_val, sizeof( struct tm ) );
2616       }
2617
2618       /* the extended signature verification status */
2619       sumGPGME = gpgme_get_sig_ulong_attr( ctx,
2620                                            sig_idx,
2621                                            GPGME_ATTR_SIG_SUMMARY,
2622                                            0 );
2623       fprintf( stderr, "gpgmeplug checkMessageSignature status flags: %lX\n", sumGPGME );
2624       /* translate GPGME status flags to common CryptPlug status flags */
2625       sumPlug = 0;
2626       if( sumGPGME & GPGME_SIGSUM_VALID       ) sumPlug |= SigStat_VALID      ;
2627       if( sumGPGME & GPGME_SIGSUM_GREEN       ) sumPlug |= SigStat_GREEN      ;
2628       if( sumGPGME & GPGME_SIGSUM_RED         ) sumPlug |= SigStat_RED        ;
2629       if( sumGPGME & GPGME_SIGSUM_KEY_REVOKED ) sumPlug |= SigStat_KEY_REVOKED;
2630       if( sumGPGME & GPGME_SIGSUM_KEY_EXPIRED ) sumPlug |= SigStat_KEY_EXPIRED;
2631       if( sumGPGME & GPGME_SIGSUM_SIG_EXPIRED ) sumPlug |= SigStat_SIG_EXPIRED;
2632       if( sumGPGME & GPGME_SIGSUM_KEY_MISSING ) sumPlug |= SigStat_KEY_MISSING;
2633       if( sumGPGME & GPGME_SIGSUM_CRL_MISSING ) sumPlug |= SigStat_CRL_MISSING;
2634       if( sumGPGME & GPGME_SIGSUM_CRL_TOO_OLD ) sumPlug |= SigStat_CRL_TOO_OLD;
2635       if( sumGPGME & GPGME_SIGSUM_BAD_POLICY  ) sumPlug |= SigStat_BAD_POLICY ;
2636       if( sumGPGME & GPGME_SIGSUM_SYS_ERROR   ) sumPlug |= SigStat_SYS_ERROR  ;
2637       if( !sumPlug )
2638         sumPlug = SigStat_NUMERICAL_CODE | sumGPGME;
2639       sigmeta->extended_info[sig_idx].sigStatusFlags = sumPlug;
2640
2641       sigmeta->extended_info[sig_idx].validity = GPGME_VALIDITY_UNKNOWN;
2642
2643       err = gpgme_get_sig_key (ctx, sig_idx, &key);
2644
2645       if ( err == GPGME_No_Error) {
2646         const char* attr_string;
2647         unsigned long attr_ulong;
2648
2649         /* extract key identidy */
2650         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_KEYID, 0, 0);
2651         if (attr_string != 0)
2652             storeNewCharPtr( &sigmeta->extended_info[sig_idx].keyid, attr_string );
2653
2654         /* extract finger print */
2655         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_FPR, 0, 0);
2656         if (attr_string != 0)
2657             storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint,
2658                             attr_string );
2659
2660         /* algorithms useable with this key */
2661         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_ALGO, 0, 0);
2662         if (attr_string != 0)
2663             storeNewCharPtr( &sigmeta->extended_info[sig_idx].algo,
2664                             attr_string );
2665         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_ALGO, 0, 0);
2666         sigmeta->extended_info[sig_idx].algo_num = attr_ulong;
2667
2668         /* extract key validity */
2669         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_VALIDITY, 0, 0);
2670         sigmeta->extended_info[sig_idx].validity = attr_ulong;
2671
2672         /* extract user id, according to the documentation it's representable
2673         * as a number, but it seems that it also has a string representation
2674         */
2675         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_USERID, 0, 0);
2676         if (attr_string != 0) {
2677             a = parse_dn( attr_string );
2678             sigmeta->extended_info[sig_idx].userid = reorder_dn( a );
2679         }
2680         
2681         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_USERID, 0, 0);
2682         sigmeta->extended_info[sig_idx].userid_num = attr_ulong;
2683
2684         /* extract the length */
2685           sigmeta->extended_info[sig_idx].keylen = attr_ulong;
2686
2687         /* extract the creation time of the key */
2688         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_CREATED, 0, 0);
2689         sigmeta->extended_info[sig_idx].key_created = attr_ulong;
2690
2691         /* extract the expiration time of the key */
2692         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_EXPIRE, 0, 0);
2693         sigmeta->extended_info[sig_idx].key_expires = attr_ulong;
2694
2695         /* extract user name */
2696         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_NAME, 0, 0);
2697         if (attr_string != 0) {
2698             a = parse_dn( attr_string );
2699             sigmeta->extended_info[sig_idx].name = reorder_dn( a );
2700         }
2701
2702         /* extract email(s) */
2703         sigmeta->extended_info[sig_idx].emailCount = 0;
2704         sigmeta->extended_info[sig_idx].emailList = 0;
2705         for( UID_idx=0; 
2706              (attr_string = gpgme_key_get_string_attr(key,
2707                               GPGME_ATTR_EMAIL, 0, UID_idx)); 
2708              ++UID_idx ){
2709           if (*attr_string) {
2710             fprintf( stderr, "gpgmeplug checkMessageSignature found email: %s\n", attr_string );
2711             if( !sigmeta->extended_info[sig_idx].emailCount )
2712                 alloc_return = 
2713                     malloc( sizeof( char*) );
2714             else
2715                 alloc_return = 
2716                     realloc( sigmeta->extended_info[sig_idx].emailList,
2717                              sizeof( char*)
2718                              * (sigmeta->extended_info[sig_idx].emailCount + 1) );
2719             if( alloc_return ) {
2720               sigmeta->extended_info[sig_idx].emailList = alloc_return;
2721               storeNewCharPtr( 
2722                   &( sigmeta->extended_info[sig_idx].emailList[
2723                           sigmeta->extended_info[sig_idx].emailCount ] ),
2724                   attr_string );
2725               ++sigmeta->extended_info[sig_idx].emailCount;
2726             }
2727           }
2728         }
2729         if( !sigmeta->extended_info[sig_idx].emailCount )
2730           fprintf( stderr, "gpgmeplug checkMessageSignature found NO EMAIL\n" );
2731
2732         /* extract the comment */
2733         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_COMMENT, 0, 0);
2734         if (attr_string != 0)
2735             storeNewCharPtr( &sigmeta->extended_info[sig_idx].comment,
2736                             attr_string );
2737       }
2738       else
2739         storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint, fpr );
2740
2741       sig_status = sig_status_to_string( status );
2742       storeNewCharPtr( &sigmeta->extended_info[sig_idx].status_text,
2743                        sig_status );
2744
2745     } else
2746       break; /* if allocation fails once, it isn't likely to
2747                 succeed the next time either */
2748
2749     fpr = gpgme_get_sig_status (ctx, ++sig_idx, &status, &created);
2750   }
2751   sigmeta->extended_info_count = sig_idx;
2752   sigmeta->nota_xml = gpgme_get_notation( ctx );
2753   sigmeta->status_code = status;
2754
2755   gpgme_release( ctx );
2756   return ( status == GPGME_SIG_STAT_GOOD );
2757 }
2758