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