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