Made debugging configurable.
[gpgol.git] / src / engine.c
1 /* engine.c - Crypto engine dispatcher
2  *      Copyright (C) 2007, 2008 g10 Code GmbH
3  *
4  * This file is part of GpgOL.
5  *
6  * GpgOL is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1 
9  * of the License, or (at your option) any later version.
10  *  
11  * GpgOL is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <errno.h>
27 #include <assert.h>
28 #define WIN32_LEAN_AND_MEAN 
29 #include <windows.h>
30
31 #include "common.h"
32 #include "engine.h"
33 #include "engine-gpgme.h"
34 #include "engine-assuan.h"
35
36
37 #define FILTER_BUFFER_SIZE 128  /* FIXME: Increase it after testing  */
38
39
40 #define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
41                                        SRCNAME, __func__, __LINE__); \
42                         } while (0)
43
44 #define debug_filter        (opt.enable_debug & DBG_FILTER)
45 #define debug_filter_extra  (opt.enable_debug & DBG_FILTER_EXTRA)
46
47 /* This variable indicates whether the assuan engine is used.  */
48 static int use_assuan;
49
50
51 /* Definition of the key object.  */
52 struct engine_keyinfo_s
53 {
54   struct {
55     gpgme_key_t key;
56   } gpgme;
57
58 };
59
60
61 /* Definition of the filter object.  This object shall only be
62    accessed by one thread. */
63 struct engine_filter_s
64 {
65   int use_assuan;          /* The same as the global USE_ASSUAN.  */
66
67   struct {
68     CRITICAL_SECTION lock; /* The lock for the this object. */
69     HANDLE condvar;        /* Manual reset event signaled if LENGTH > 0.  */
70     int nonblock;          /* Put gpgme data cb in non blocking mode.  */
71     size_t length;         /* Number of bytes in BUFFER waiting to be
72                               send down the pipe.  */
73     char buffer[FILTER_BUFFER_SIZE];
74     int got_eof;         /* End of file has been indicated.  */
75     /* These objects are only in this structure because we
76        use this structure's lock to protect them.  */
77     int ready;           /* Set to true if the gpgme process has finished.  */
78     HANDLE ready_event;  /* And the corresponding event.  */
79     gpg_error_t status;  /* Status of the gpgme process.  */
80   } in;
81
82   struct {
83     CRITICAL_SECTION lock; /* The lock for the this object. */
84     HANDLE condvar;        /* Manual reset event signaled if LENGTH == 0.  */
85     int nonblock;          /* Put gpgme data cb in non blocking mode.  */
86     size_t length;         /* Number of bytes in BUFFER waiting to be
87                               send back to the caller.  */
88     char buffer[FILTER_BUFFER_SIZE];
89   } out;
90
91   /* The data sink as set by engine_create_filter.  */
92   int (*outfnc) (void *, const void *, size_t);
93   void *outfncdata;
94
95   /* Objects to be released by engine_wait/cancel.  */
96   struct gpgme_data_cbs cb_inbound;  /* Callback structure for gpgme.  */
97   struct gpgme_data_cbs cb_outbound; /* Ditto.  */
98   gpgme_data_t indata;               /* Input data.  */
99   gpgme_data_t outdata;              /* Output data.  */
100   void *cancel_data;                 /* Used by engine_cancel.  */
101 };
102
103
104 static void
105 take_in_lock (engine_filter_t filter, const char *func)
106 {
107   EnterCriticalSection (&filter->in.lock);
108   if (debug_filter_extra)
109     log_debug ("%s:%s: in.lock taken\n", SRCNAME, func);
110 }
111
112 static void
113 release_in_lock (engine_filter_t filter, const char *func)
114 {
115   LeaveCriticalSection (&filter->in.lock);
116   if (debug_filter_extra)
117     log_debug ("%s:%s: in.lock released\n", SRCNAME, func);
118 }
119
120 static void
121 take_out_lock (engine_filter_t filter, const char *func)
122 {
123   EnterCriticalSection (&filter->out.lock);
124   if (debug_filter_extra)
125     log_debug ("%s:%s: out.lock taken\n", SRCNAME, func);
126 }
127
128 static void
129 release_out_lock (engine_filter_t filter, const char *func)
130 {
131   LeaveCriticalSection (&filter->out.lock);
132   if (debug_filter_extra)
133     log_debug ("%s:%s: out.lock released\n", SRCNAME, func);
134 }
135
136
137
138
139 \f
140 /* Create a new filter object. */
141 static engine_filter_t 
142 create_filter (void)
143 {
144   engine_filter_t filter;
145
146   filter = xcalloc (1, sizeof *filter);
147
148   InitializeCriticalSection (&filter->in.lock);
149   filter->in.condvar = CreateEvent (NULL, TRUE, 0, NULL);
150   if (!filter->in.condvar)
151     log_error_w32 (-1, "%s:%s: create in.condvar failed", SRCNAME, __func__);
152
153   InitializeCriticalSection (&filter->out.lock);
154   filter->out.condvar = CreateEvent (NULL, TRUE, 0, NULL);
155   if (!filter->out.condvar)
156     log_error_w32 (-1, "%s:%s: create out.condvar failed", SRCNAME, __func__);
157
158   /* Create an automatic event (it only used one time so the type is
159      actually not important).  */
160   filter->in.ready_event = CreateEvent (NULL, 0, 0, NULL);
161   if (!filter->in.ready_event)
162     log_error_w32 (-1, "%s:%s: CreateEvent failed", SRCNAME, __func__);
163
164   /* If we are using the assuan engine we need to make the gpgme read
165      callback non blocking.  */
166   if (use_assuan)
167     {
168       filter->use_assuan = 1;
169       filter->in.nonblock = 1;
170     }
171
172   return filter;
173 }
174
175
176 static void
177 release_filter (engine_filter_t filter)
178 {
179   if (filter)
180     {
181       if (filter->in.condvar)
182         CloseHandle (filter->in.condvar);
183       if (filter->out.condvar)
184         CloseHandle (filter->out.condvar);
185       if (filter->in.ready_event)
186         CloseHandle (filter->in.ready_event);
187       gpgme_data_release (filter->indata);
188       gpgme_data_release (filter->outdata);
189       xfree (filter);
190     }
191 }
192
193
194
195
196 /* This read callback is used by GPGME to read data from a filter
197    object.  The function should return the number of bytes read, 0 on
198    EOF, and -1 on error.  If an error occurs, ERRNO should be set to
199    describe the type of the error.  */
200 static ssize_t
201 filter_gpgme_read_cb (void *handle, void *buffer, size_t size)
202 {
203   engine_filter_t filter = handle;
204   int nbytes;
205
206   if (!filter || !buffer || !size)
207     {
208       errno = EINVAL;
209       return (ssize_t)(-1);
210     }
211
212   if (debug_filter)
213     log_debug ("%s:%s: enter\n",  SRCNAME, __func__);
214   take_in_lock (filter, __func__);
215   while (!filter->in.length)
216     {
217       if (filter->in.got_eof || filter->in.ready)
218         {
219           release_in_lock (filter, __func__);
220          if (debug_filter)
221             log_debug ("%s:%s: returning EOF\n", SRCNAME, __func__);
222           return 0; /* Return EOF. */
223         }
224       release_in_lock (filter, __func__);
225       if (filter->in.nonblock)
226         {
227           errno = EAGAIN;
228           if (debug_filter_extra)
229             log_debug ("%s:%s: leave; result=EAGAIN\n", SRCNAME, __func__);
230           SwitchToThread ();
231           return -1;
232         }
233       if (debug_filter)
234         log_debug ("%s:%s: waiting for in.condvar\n", SRCNAME, __func__);
235       WaitForSingleObject (filter->in.condvar, 500);
236       take_in_lock (filter, __func__);
237       if (debug_filter)
238         log_debug ("%s:%s: continuing\n", SRCNAME, __func__);
239     }
240      
241   if (debug_filter)
242     log_debug ("%s:%s: requested read size=%d (filter.in.length=%d)\n",
243                SRCNAME, __func__, (int)size, (int)filter->in.length);
244   nbytes = size < filter->in.length ? size : filter->in.length;
245   memcpy (buffer, filter->in.buffer, nbytes);
246   if (filter->in.length > nbytes)
247     memmove (filter->in.buffer, filter->in.buffer + nbytes, 
248              filter->in.length - nbytes);
249   filter->in.length -= nbytes;
250   release_in_lock (filter, __func__);
251
252   if (debug_filter)
253     log_debug ("%s:%s: leave; result=%d\n",
254                SRCNAME, __func__, (int)nbytes);
255   
256   return nbytes;
257 }
258
259
260 /* This write callback is used by GPGME to write data to the filter
261    object.  The function should return the number of bytes written,
262    and -1 on error.  If an error occurs, ERRNO should be set to
263    describe the type of the error.  */
264 static ssize_t
265 filter_gpgme_write_cb (void *handle, const void *buffer, size_t size)
266 {
267   engine_filter_t filter = handle;
268   int nbytes;
269
270   if (!filter || !buffer || !size)
271     {
272       errno = EINVAL;
273       return (ssize_t)(-1);
274     }
275
276   if (debug_filter)
277     log_debug ("%s:%s: enter\n",  SRCNAME, __func__);
278   take_out_lock (filter, __func__);
279   while (filter->out.length)
280     {
281       release_out_lock (filter, __func__);
282       if (filter->out.nonblock)
283         {
284           errno = EAGAIN;
285           if (debug_filter_extra)
286             log_debug ("%s:%s: leave; result=EAGAIN\n", SRCNAME, __func__);
287           return -1;
288         }
289       if (debug_filter)
290         log_debug ("%s:%s: waiting for out.condvar\n", SRCNAME, __func__);
291       WaitForSingleObject (filter->out.condvar, 500);
292       take_out_lock (filter, __func__);
293       if (debug_filter)
294         log_debug ("%s:%s: continuing\n", SRCNAME, __func__);
295     }
296
297   if (debug_filter)
298     log_debug ("%s:%s: requested write size=%d\n",
299                SRCNAME, __func__, (int)size);
300   nbytes = size < FILTER_BUFFER_SIZE ? size : FILTER_BUFFER_SIZE;
301   memcpy (filter->out.buffer, buffer, nbytes);
302   filter->out.length = nbytes;
303   release_out_lock (filter, __func__);
304
305   if (debug_filter)
306     log_debug ("%s:%s: leave; result=%d\n", SRCNAME, __func__, (int)nbytes);
307   return nbytes;
308 }
309
310
311 /* Store a cancel parameter into FILTER.  Only use by the engine backends. */
312 void
313 engine_private_set_cancel (engine_filter_t filter, void *cancel_data)
314 {
315   filter->cancel_data = cancel_data;
316 }
317
318
319 /* This function is called by the gpgme backend to notify a filter
320    object about the final status of an operation.  It may only be
321    called by the engine-gpgme.c module. */
322 void
323 engine_private_finished (engine_filter_t filter, gpg_error_t status)
324 {
325   if (!filter)
326     {
327       log_debug ("%s:%s: called without argument\n", SRCNAME, __func__);
328       return;
329     }
330   if (debug_filter)
331     log_debug ("%s:%s: filter %p: process terminated: %s <%s>\n", 
332                SRCNAME, __func__, filter, 
333                gpg_strerror (status), gpg_strsource (status));
334   
335   take_in_lock (filter, __func__);
336   filter->in.ready = 1;
337   filter->in.status = status;
338   filter->cancel_data = NULL;
339   if (!SetEvent (filter->in.ready_event))
340     log_error_w32 (-1, "%s:%s: SetEvent failed", SRCNAME, __func__);
341   release_in_lock (filter, __func__);
342   if (debug_filter)
343     log_debug ("%s:%s: leaving\n", SRCNAME, __func__);
344 }
345
346
347
348
349 \f
350 /* Initialize the engine dispatcher.  */
351 int
352 engine_init (void)
353 {
354   gpg_error_t err;
355
356   err = op_gpgme_basic_init ();
357   if (err)
358     return err;
359
360   err = op_assuan_init ();
361   if (err)
362     {
363       use_assuan = 0;
364       MessageBox (NULL,
365                   _("The user interface server is not available or does "
366                     "not work.  Using an internal user interface.\n\n"
367                     "This is limited to the PGP/MIME protocol and "
368                     "thus S/MIME protected message are not readable."),
369                   _("GpgOL"), MB_ICONWARNING|MB_OK);
370       err = op_gpgme_init ();
371     }
372   else
373     use_assuan = 1;
374
375   return err;
376 }
377
378
379 /* Shutdown the engine dispatcher.  */
380 void
381 engine_deinit (void)
382 {
383   op_assuan_deinit ();
384   op_gpgme_deinit ();
385 }
386
387
388 \f
389 /* Filter the INDATA of length INDATA and write the output using
390    OUTFNC.  OUTFNCDATA is passed as first argument to OUTFNC, followed
391    by the data to be written and its length.  FILTER is an object
392    returned for example by engine_encrypt_start.  The function returns
393    0 on success or an error code on error.
394
395    Passing INDATA as NULL and INDATALEN as 0, the filter will be
396    flushed, that is all remaining stuff will be written to OUTFNC.
397    This indicates EOF and the filter won't accept anymore input.  */
398 int
399 engine_filter (engine_filter_t filter, const void *indata, size_t indatalen)
400 {
401   gpg_error_t err;
402   int nbytes;
403
404   if (debug_filter)
405     log_debug ("%s:%s: enter; filter=%p\n", SRCNAME, __func__, filter); 
406   /* Our implementation is for now straightforward without any
407      additional buffer filling etc.  */
408   if (!filter || !filter->outfnc)
409     return gpg_error (GPG_ERR_INV_VALUE);
410   if (filter->in.length > FILTER_BUFFER_SIZE
411       || filter->out.length > FILTER_BUFFER_SIZE)
412     return gpg_error (GPG_ERR_BUG);
413   if (filter->in.got_eof)
414     return gpg_error (GPG_ERR_CONFLICT); /* EOF has already been indicated.  */
415
416   if (debug_filter)
417     log_debug ("%s:%s: indata=%p indatalen=%d outfnc=%p\n",
418                SRCNAME, __func__, indata, (int)indatalen, filter->outfnc); 
419   for (;;)
420     {
421       /* If there is something to write out, do this now to make space
422          for more data.  */
423       take_out_lock (filter, __func__);
424       while (filter->out.length)
425         {
426           if (debug_filter)
427             log_debug ("%s:%s: pushing %d bytes to the outfnc\n",
428                        SRCNAME, __func__, filter->out.length); 
429           nbytes = filter->outfnc (filter->outfncdata, 
430                                    filter->out.buffer, filter->out.length);
431           if (nbytes == -1)
432             {
433               if (debug_filter)
434                 log_debug ("%s:%s: error writing data\n", SRCNAME, __func__);
435               release_out_lock (filter, __func__);
436               return gpg_error (GPG_ERR_EIO);
437             }
438           assert (nbytes <= filter->out.length && nbytes >= 0);
439           if (nbytes < filter->out.length)
440             memmove (filter->out.buffer, filter->out.buffer + nbytes,
441                      filter->out.length - nbytes); 
442           filter->out.length -= nbytes;
443         }
444       if (!PulseEvent (filter->out.condvar))
445         log_error_w32 (-1, "%s:%s: PulseEvent(out) failed", SRCNAME, __func__);
446       release_out_lock (filter, __func__);
447       
448       take_in_lock (filter, __func__);
449
450       if (!indata && !indatalen)
451         {
452           filter->in.got_eof = 1;
453           /* Flush requested.  Tell the output function to also flush.  */
454           nbytes = filter->outfnc (filter->outfncdata, NULL, 0);
455           if (nbytes == -1)
456             {
457               log_debug ("%s:%s: error flushing data\n", SRCNAME, __func__);
458               err = gpg_error (GPG_ERR_EIO);
459             }
460           else
461             err = 0;
462           release_in_lock (filter, __func__);
463           return err; 
464         }
465
466       /* Fill the input buffer, relinquish control to the callback
467          processor and loop until all input data has been
468          processed.  */
469       if (!filter->in.length && indatalen)
470         {
471           filter->in.length = (indatalen > FILTER_BUFFER_SIZE
472                                ? FILTER_BUFFER_SIZE : indatalen);
473           memcpy (filter->in.buffer, indata, filter->in.length);
474           indata    += filter->in.length;
475           indatalen -= filter->in.length;
476         }
477       if (!filter->in.length || (filter->in.ready && !filter->out.length))
478         {
479           release_in_lock (filter, __func__);
480           err = 0;
481           break;  /* the loop.  */
482         }
483       if (!PulseEvent (filter->in.condvar))
484         log_error_w32 (-1, "%s:%s: PulseEvent(in) failed", SRCNAME, __func__);
485       release_in_lock (filter, __func__);
486       Sleep (50);
487     }
488
489   if (debug_filter)
490     log_debug ("%s:%s: leave; err=%d\n", SRCNAME, __func__, err); 
491   return err;
492 }
493
494
495 /* Dummy data sink used if caller does not need an output
496    function.  */
497 static int
498 dummy_outfnc (void *opaque, const void *data, size_t datalen)
499 {
500   (void)opaque;
501   (void)data;
502   return (int)datalen;
503 }
504
505
506 /* Create a new filter object which uses OUTFNC as its data sink.  If
507    OUTFNC is called with NULL/0 for the data to be written, the
508    function should do a flush.  OUTFNC is expected to return the
509    number of bytes actually written or -1 on error.  It may return 0
510    to indicate that no data has been written and the caller shall try
511    again.  OUTFNC and OUTFNCDATA are internally used by the engine
512    even after the call to this function.  There lifetime only ends
513    after an engine_wait or engine_cancel. */
514 int
515 engine_create_filter (engine_filter_t *r_filter,
516                       int (*outfnc) (void *, const void *, size_t),
517                       void *outfncdata)
518 {
519   gpg_error_t err;
520   engine_filter_t filter;
521
522   filter = create_filter ();
523   filter->cb_inbound.read = filter_gpgme_read_cb;
524   filter->cb_outbound.write = filter_gpgme_write_cb;
525   filter->outfnc = outfnc? outfnc : dummy_outfnc;
526   filter->outfncdata = outfncdata;
527
528   err = gpgme_data_new_from_cbs (&filter->indata, 
529                                  &filter->cb_inbound, filter);
530   if (err)
531     goto failure;
532
533   err = gpgme_data_new_from_cbs (&filter->outdata,
534                                  &filter->cb_outbound, filter);
535   if (err)
536     goto failure;
537
538   *r_filter = filter;
539   return 0;
540
541  failure:
542   release_filter (filter);
543   return err;
544 }
545
546
547
548 /* Wait for FILTER to finish.  Returns 0 on success.  FILTER is not
549    valid after the function has returned success.  */
550 int
551 engine_wait (engine_filter_t filter)
552 {
553   gpg_error_t err;
554   int more;
555
556   if (!filter || !filter->outfnc)
557     return gpg_error (GPG_ERR_INV_VALUE);
558
559   /* If we are here, engine_filter is not anymore called but there is
560      likely stuff in the output buffer which needs to be written
561      out.  */
562   /* Argh, Busy waiting.  As soon as we change fromCritical Sections
563      to a kernel based objects we should use WaitOnMultipleObjects to
564      wait for the out.lock as well as for the ready_event.  */
565   do 
566     {
567       more = 0;
568       take_out_lock (filter, __func__);
569       if (filter->out.length)
570         {
571           int nbytes; 
572
573           nbytes = filter->outfnc (filter->outfncdata, 
574                                    filter->out.buffer, filter->out.length);
575           if (nbytes < 0)
576             {
577               log_error ("%s:%s: error writing data\n", SRCNAME, __func__);
578               release_out_lock (filter, __func__);
579               return gpg_error (GPG_ERR_EIO);
580             }
581          
582           assert (nbytes <= filter->out.length && nbytes >= 0);
583           if (nbytes < filter->out.length)
584             memmove (filter->out.buffer, filter->out.buffer + nbytes,
585                      filter->out.length - nbytes); 
586           filter->out.length -= nbytes;
587           if (filter->out.length)
588             {
589               if (debug_filter_extra)
590                 log_debug ("%s:%s: still %d pending bytes for outfnc\n",
591                            SRCNAME, __func__, filter->out.length);
592               more = 1;
593             }
594         }
595       if (!PulseEvent (filter->out.condvar))
596         log_error_w32 (-1, "%s:%s: PulseEvent(out) failed", SRCNAME, __func__);
597       release_out_lock (filter, __func__);
598       take_in_lock (filter, __func__);
599       if (!filter->in.ready)
600         more = 1;
601       release_in_lock (filter, __func__);
602       if (more)
603         Sleep (50);
604     }
605   while (more);
606
607   if (WaitForSingleObject (filter->in.ready_event, INFINITE) != WAIT_OBJECT_0)
608     {
609       log_error_w32 (-1, "%s:%s: WFSO failed", SRCNAME, __func__);
610       return gpg_error (GPG_ERR_GENERAL);
611     }
612   err = filter->in.status;
613   log_debug ("%s:%s: filter %p ready: %s", SRCNAME, __func__, 
614              filter, gpg_strerror (err));
615
616   if (!err)
617     release_filter (filter);
618   return err;
619 }
620
621
622 /* Cancel FILTER. */
623 void
624 engine_cancel (engine_filter_t filter)
625 {
626   void *cancel_data;
627
628   if (!filter)
629     return;
630   
631   take_in_lock (filter, __func__);
632   cancel_data = filter->cancel_data;
633   filter->cancel_data = NULL;
634   filter->in.ready = 1;
635   release_in_lock (filter, __func__);
636   if (cancel_data)
637     {
638       log_debug ("%s:%s: filter %p: sending cancel command to backend",
639                  SRCNAME, __func__, filter);
640       if (filter->use_assuan)
641         engine_assuan_cancel (cancel_data);
642       else
643         engine_gpgme_cancel (cancel_data);
644       if (WaitForSingleObject (filter->in.ready_event, INFINITE)
645           != WAIT_OBJECT_0)
646         log_error_w32 (-1, "%s:%s: WFSO failed", SRCNAME, __func__);
647       else
648         log_debug ("%s:%s: filter %p: backend has been canceled", 
649                    SRCNAME, __func__,  filter);
650     }
651   log_debug ("%s:%s: filter %p: canceled", SRCNAME, __func__, filter);
652   release_filter (filter);
653 }
654
655
656
657 /* Start an encryption operation to all RECIPEINTS using PROTOCOL
658    RECIPIENTS is a NULL terminated array of rfc2822 addresses.  FILTER
659    is an object created by engine_create_filter.  The caller needs to
660    call engine_wait to finish the operation.  A filter object may not
661    be reused after having been used through this function.  However,
662    the lifetime of the filter object lasts until the final engine_wait
663    or engine_cancel.  On return the protocol to be used is stored at
664    R_PROTOCOL. */
665 int
666 engine_encrypt_start (engine_filter_t filter, HWND hwnd,
667                       protocol_t req_protocol, char **recipients,
668                       protocol_t *r_protocol)
669 {
670   gpg_error_t err;
671   protocol_t used_protocol;
672
673   *r_protocol = req_protocol;
674   if (filter->use_assuan)
675     {
676       err = op_assuan_encrypt (req_protocol, filter->indata, filter->outdata,
677                                filter, hwnd, recipients, &used_protocol);
678       if (!err)
679         *r_protocol = used_protocol;
680     }
681   else
682     err = op_gpgme_encrypt (req_protocol, filter->indata, filter->outdata,
683                             filter, hwnd, recipients);
684       
685   return err;
686 }
687
688
689 /* Start an detached signing operation.  FILTER is an object created
690    by engine_create_filter.  The caller needs to call engine_wait to
691    finish the operation.  A filter object may not be reused after
692    having been used through this function.  However, the lifetime of
693    the filter object lasts until the final engine_wait or
694    engine_cancel.  */
695 int
696 engine_sign_start (engine_filter_t filter, HWND hwnd, protocol_t protocol)
697 {
698   gpg_error_t err;
699
700   if (filter->use_assuan)
701     err = op_assuan_sign (protocol, filter->indata, filter->outdata,
702                          filter, hwnd);
703   else
704     err = op_gpgme_sign (protocol, filter->indata, filter->outdata,
705                          filter, hwnd);
706   return err;
707 }
708
709
710 /* Start an decrypt operation.  FILTER is an object created by
711    engine_create_filter.  The caller needs to call engine_wait to
712    finish the operation.  A filter object may not be reused after
713    having been used through this function.  However, the lifetime of
714    the filter object lasts until the final engine_wait or
715    engine_cancel.  */
716 int
717 engine_decrypt_start (engine_filter_t filter, HWND hwnd, protocol_t protocol,
718                       int with_verify)
719 {
720   gpg_error_t err;
721
722   if (filter->use_assuan)
723     err = op_assuan_decrypt (protocol, filter->indata, filter->outdata,
724                             filter, hwnd, with_verify);
725   else
726     err = op_gpgme_decrypt (protocol, filter->indata, filter->outdata,
727                             filter, hwnd, with_verify);
728   return err;
729 }
730
731
732 /* Start a verify operation.  FILTER is an object created by
733    engine_create_filter; an output function is not required. SIGNATURE
734    is the detached signature or NULL if FILTER delivers an opaque
735    signature.  The caller needs to call engine_wait to finish the
736    operation.  A filter object may not be reused after having been
737    used through this function.  However, the lifetime of the filter
738    object lasts until the final engine_wait or engine_cancel.  */
739 int
740 engine_verify_start (engine_filter_t filter, HWND hwnd, const char *signature,
741                      protocol_t protocol)
742 {
743   gpg_error_t err;
744
745   if (!signature)
746     {
747       log_error ("%s:%s: opaque signature are not yet supported\n",
748                  SRCNAME, __func__);
749       return gpg_error (GPG_ERR_NOT_SUPPORTED);
750     }
751
752   if (filter->use_assuan)
753     err = op_assuan_verify (protocol, filter->indata, signature, filter, hwnd);
754   else
755     err = op_gpgme_verify (protocol, filter->indata, signature, filter, hwnd);
756   return err;
757 }
758
759
760 /* Fire up the key manager.  Returns 0 on success.  */
761 int
762 engine_start_keymanager (HWND hwnd)
763 {
764   if (use_assuan)
765     return op_assuan_start_keymanager (hwnd);
766   else
767     return gpg_error (GPG_ERR_NOT_SUPPORTED);
768 }