Fix sign+encr problem.
[gpgol.git] / src / engine-assuan.c
1 /* engine-assuan.c - Crypto engine using an Assuan server
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 #define WINVER 0x0500  /* Required for AllowSetForegroundWindow.  */
30 #include <windows.h>
31
32 #include <assuan.h>
33 #include "common.h"
34 #include "engine.h"
35 #include "engine-assuan.h"
36
37
38 #define TRACEPOINT() do { log_debug ("%s:%s:%d: tracepoint\n", \
39                                        SRCNAME, __func__, __LINE__); \
40                         } while (0)
41
42 /* Debug macros.  */
43 #define debug_ioworker        (opt.enable_debug & DBG_IOWORKER)
44 #define debug_ioworker_extra  (opt.enable_debug & DBG_IOWORKER_EXTRA)
45
46
47 /* How many times we will try to connect to a server after we have
48    started him.  */
49 #define FIREUP_RETRIES 10
50
51
52 /* This is the buffer object used for the asynchronous reading of the
53    status channel.  */
54 struct status_buffer_s
55 {
56   int eof;
57   int linelen;  /* Used length of LINE. */
58   char line[ASSUAN_LINELENGTH];
59 };
60 typedef struct status_buffer_s *status_buffer_t;
61
62
63 /* We operate in an asynchronous mode and thus need to run code for
64    final cleanup.  Thus all functions need to implement a closure
65    function and setup an closure_data_t object.  */ 
66 struct closure_data_s;
67 typedef struct closure_data_s *closure_data_t;
68 struct closure_data_s
69 {
70   void (*closure)(closure_data_t);
71   gpg_error_t final_err;         /* Final error code.  */
72   engine_filter_t filter;
73   assuan_context_t assctx;
74   ULONG cmdid;
75   assuan_fd_t status_read_fd;
76   struct gpgme_data_cbs status_cbs;
77   gpgme_data_t status_data;
78   status_buffer_t status_buffer; /* Allocated on demand.  */
79   int status_ready;
80   gpgme_data_t sigdata;   /* Used by verify_closure.  */
81   gpg_error_t last_err;
82 };
83
84
85 /* The object used by our I/O worker thread.  */
86 struct work_item_s;
87 typedef struct work_item_s *work_item_t;
88 struct work_item_s
89 {
90   work_item_t next;
91   int used;          /* If not set this object may be reused.  */
92   int waiting;       /* Helper for async_worker_thread.  */
93
94   const char *name;  /* Description used for debugging.  */
95   ULONG cmdid;       /* Used to group work items of one command.  */
96   closure_data_t cld;/* NULL or the closure.  */
97   int wait_on_success; /* This work item needs to be ready before
98                           invoking a closure for this command.  */
99   gpgme_data_t data; /* The data object we write to or read from.  */
100   int writing;       /* If true we are going to write to HD.  */
101   HANDLE hd;         /* The handle we read from or write to.  */
102   int inactive;      /* If set, the handle is not yet active.  */
103   int io_pending;    /* I/O is still pending.  The value is the number
104                         of bytes to be written or the size of the
105                         buffer given to ReadFile. */
106   int got_ready;     /* Operation finished.  */
107   int delayed_ready; /* Ready but delayed due to a missing prerequesite.  */
108   int got_error;     /* An error as been encountered.  */
109   int aborting;      /* Set to true after a CancelIO has been issued.  */
110   void (*finalize)(work_item_t); /* Function called immediately before
111                                     the item is removed from the
112                                     queue.  */
113   OVERLAPPED ov;     /* The overlapped info structure.  */
114   char buffer[1024]; /* The buffer used by ReadFile or WriteFile.  */
115
116   ULONG switch_counter; /* Used by switch_threads.  */
117 };
118
119
120 /* A helper context used to convey information from op_assuan_encrypt
121    to op_assuan_encrypt_bottom.  */
122 struct engine_assuan_encstate_s
123 {
124   engine_filter_t filter;
125   const char *protocol_name;
126   HANDLE inpipe[2];
127   HANDLE outpipe[2];
128   closure_data_t cld;
129   assuan_context_t ctx;
130   ULONG cmdid;
131 };
132
133
134 /* The queue of all outstandig I/O operations.  Protected by the
135    work_queue_lock.  */
136 static work_item_t work_queue;
137
138 /* The big lock used to protect the work queue.  */
139 static CRITICAL_SECTION work_queue_lock;
140
141 /* An auto-reset event which will be signaled to get the
142    async_worker_thread out of its WFMO and to inspect the work
143    queue.  */
144 static HANDLE work_queue_event;
145
146
147 /*-- prototypes --*/
148 static DWORD WINAPI async_worker_thread (void *dummy);
149
150
151
152 \f
153 /* Return the next command id.  Command Ids are used to group
154    resources of one command. */
155 static ULONG
156 create_command_id (void)
157 {
158   static ULONG command_id;
159   ULONG cmdid;
160
161   while (!(cmdid = InterlockedIncrement (&command_id)))
162     ;
163   return cmdid;
164 }
165
166
167 static void
168 close_pipe (HANDLE apipe[2])
169 {
170   int i;
171
172   for (i=0; i < 2; i++)
173     if (apipe[i] != INVALID_HANDLE_VALUE)
174       {
175         CloseHandle (apipe[i]);
176         apipe[i] = INVALID_HANDLE_VALUE;
177       }
178 }
179
180
181 /* Duplicate HANDLE into the server's process and close HANDLE.  Note
182    that HANDLE is closed even if the function fails.  Returns the
183    duplicated handle on success or INVALID_HANDLE_VALUE on error.  */
184 static HANDLE
185 dup_to_server (HANDLE handle, pid_t serverpid)
186 {
187   HANDLE prochandle, newhandle;
188
189   prochandle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, serverpid);
190   if (!prochandle)
191     {
192       log_error_w32 (-1, "%s:%s: OpenProcess(%lu) failed", 
193                      SRCNAME, __func__, (unsigned long)serverpid);
194       CloseHandle (handle);
195       return INVALID_HANDLE_VALUE;
196     }
197
198   if (!DuplicateHandle (GetCurrentProcess(), handle,
199                         prochandle, &newhandle, 0,
200                         TRUE, DUPLICATE_SAME_ACCESS ))
201     {
202       log_error_w32 (-1, "%s:%s: DuplicateHandle to pid %lu failed", 
203                      SRCNAME, __func__, (unsigned long)serverpid);
204       CloseHandle (prochandle);
205       CloseHandle (handle);
206       return INVALID_HANDLE_VALUE;
207     }
208   CloseHandle (prochandle);
209   CloseHandle (handle);
210   return newhandle;
211 }
212
213
214 /* Create pipe with one end being inheritable and prepared for
215    overlapped I/O.
216
217      FILEDES[0] := read handle. 
218      FILEDES[1] := write handle. 
219
220    SERVERPID is the PID of the server.  FOR_WRITE is seen out of our
221    perspective; if it is set, the read handle is created in the server
222    process and the write handle is overlapped.  If it is not set the
223    write handle is created in the server process and the read handle
224    is overlapped.
225 */
226 static gpg_error_t
227 create_io_pipe (HANDLE filedes[2], pid_t serverpid, int for_write)
228 {
229   static ULONG pipenumber;
230   ULONG pipeno;
231   char pipename[100];
232   HANDLE r, w;
233   SECURITY_ATTRIBUTES sec_attr;
234
235   memset (&sec_attr, 0, sizeof sec_attr );
236   sec_attr.nLength = sizeof sec_attr;
237
238   /* CreatePipe is in reality implemented using a Named Pipe.  We do
239      it the same but use a name which is in our name space.  We allow
240      only one instance, use the standard timeout of 120 seconds and
241      buffers of 4k. */
242   pipeno = InterlockedIncrement (&pipenumber);
243   snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\GpgOL_anon.%08lx.%08lx",
244             (unsigned long)GetCurrentProcessId(), pipeno);
245   sec_attr.bInheritHandle = /*for_write? TRUE :*/FALSE;
246   r = CreateNamedPipe (pipename, (PIPE_ACCESS_INBOUND
247                                   | (for_write? 0:FILE_FLAG_OVERLAPPED)),
248                        PIPE_TYPE_BYTE | PIPE_WAIT,
249                        1, 4096, 4096, 120000, &sec_attr);
250   if (r == INVALID_HANDLE_VALUE)
251     {
252       log_error_w32 (-1, "%s:%s: CreateNamedPipe failed for `%s'",
253                      SRCNAME, __func__, pipename);
254       return gpg_error (GPG_ERR_GENERAL);
255     }
256   if (for_write)
257     {
258       r = dup_to_server (r, serverpid);
259       if (r == INVALID_HANDLE_VALUE)
260         {
261           log_error_w32 (-1, "%s:%s: dup_for_server(r) failed for `%s'",
262                          SRCNAME, __func__, pipename);
263           return gpg_error (GPG_ERR_GENERAL);
264         }
265     }
266
267   /* Now open the other side of the named pipe.  Because we have not
268      called ConnectNamedPipe another process should not be able to
269      open the pipe in the meantime.  This is an educated guess by
270      looking at REACTOS and WINE - they implement an anonymous pipe
271      this way.  */
272   sec_attr.bInheritHandle = /*for_write?*/ FALSE /*: TRUE*/;
273   w = CreateFile (pipename, GENERIC_WRITE, 0, &sec_attr,
274                   OPEN_EXISTING, (FILE_ATTRIBUTE_NORMAL
275                                   | (for_write? FILE_FLAG_OVERLAPPED:0)),
276                   NULL);
277   if (w == INVALID_HANDLE_VALUE)
278     {
279       log_error_w32 (-1, "%s:%s: CreateFile failed for `%s'",
280                      SRCNAME, __func__, pipename);
281       CloseHandle (r);
282       return gpg_error (GPG_ERR_GENERAL);
283     }
284   if (!for_write)
285     {
286       w = dup_to_server (w, serverpid);
287       if (w == INVALID_HANDLE_VALUE)
288         {
289           log_error_w32 (-1, "%s:%s: dup_for_server(w) failed for `%s'",
290                          SRCNAME, __func__, pipename);
291           CloseHandle (r);
292           return gpg_error (GPG_ERR_GENERAL);
293         }
294     }
295
296   filedes[0] = r;
297   filedes[1] = w;
298   if (debug_ioworker)
299     log_debug ("%s:%s: new pipe created: r=%p%s w=%p%s",  SRCNAME, __func__,
300                r, for_write? " (server)":"",
301                w, !for_write?" (server)":"");
302   return 0;
303 }
304
305
306 /* Return the socket name of the UI Server.  */
307 static const char *
308 get_socket_name (void)
309 {
310   static char *name;
311
312   if (!name)
313     {
314       const char *dir = default_homedir ();
315       name = xmalloc (strlen (dir) + 11 + 1);
316       strcpy (stpcpy (name, dir), "\\S.uiserver");
317     }
318
319   return name;
320 }
321
322
323 /* Return the name of the default UI server.  This name is used to
324    auto start an UI server if an initial connect failed.  */
325 static char *
326 get_uiserver_name (void)
327 {
328   char *name = NULL;
329   char *dir, *uiserver, *p;
330   int extra_arglen = 0;
331
332   dir = read_w32_registry_string ("HKEY_LOCAL_MACHINE", GNUPG_REGKEY,
333                                   "Install Directory");
334   if (dir)
335     {
336       uiserver = read_w32_registry_string (NULL, GNUPG_REGKEY, 
337                                            "UI Server");
338       if (!uiserver)
339         {
340           uiserver = xstrdup ("kleopatra.exe");
341           extra_arglen = 9; /* Space required for " --daemon".  */
342         }
343
344       name = xmalloc (strlen (dir) + strlen (uiserver) + extra_arglen + 2);
345       strcpy (stpcpy (stpcpy (name, dir), "\\"), uiserver);
346       for (p = name; *p; p++)
347         if (*p == '/')
348           *p = '\\';
349       xfree (uiserver);
350       if (extra_arglen && access (name, F_OK))
351         {
352           /* Kleopatra iis not nstalled: Try GPA instead but if it is
353              also not available still return the Kleopatra
354              filename.  */
355           const char gpaserver[] = "gpa.exe";
356           char *name2;
357           
358           name2 = xmalloc (strlen (dir) + strlen (gpaserver) + extra_arglen+2);
359           strcpy (stpcpy (stpcpy (name2, dir), "\\"), gpaserver);
360           for (p = name2; *p; p++)
361             if (*p == '/')
362               *p = '\\';
363           if (access (name2, F_OK ))
364             xfree (name2);
365           else
366             {
367               xfree (name);
368               name = name2;
369             }
370         }
371       xfree (dir);
372
373       /* Append the arg for Kleopatra.  */
374       if (name && extra_arglen)
375         strcat (name, " --daemon");
376     }
377   
378   return name;
379 }
380
381
382
383 static gpg_error_t
384 send_one_option (assuan_context_t ctx, const char *name, const char *value)
385 {
386   gpg_error_t err;
387   char buffer[1024];
388
389   if (!value || !*value)
390     err = 0;  /* Avoid sending empty strings.  */
391   else 
392     {
393       snprintf (buffer, sizeof buffer, "OPTION %s=%s", name, value);
394       err = assuan_transact (ctx, buffer, NULL, NULL, NULL, NULL, NULL, NULL);
395     }
396
397   return err;
398 }
399
400
401 static int
402 getinfo_pid_cb (void *opaque, const void *buffer, size_t length)
403 {
404   pid_t *pid = opaque;
405   char pidbuf[50];
406
407   /* There is only the pid in the server's response.  */
408   if (length >= sizeof pidbuf)
409     length = sizeof pidbuf -1;
410   if (length)
411     {
412       strncpy (pidbuf, buffer, length);
413       pidbuf[length] = 0;
414       *pid = (pid_t)strtoul (pidbuf, NULL, 10);
415     }
416   return 0;
417 }
418
419
420 /* Send options to the UI server and return the server's PID.  */
421 static gpg_error_t
422 send_options (assuan_context_t ctx, void *hwnd, pid_t *r_pid)
423 {
424   gpg_error_t err = 0;
425   char numbuf[50];
426
427   *r_pid = (pid_t)(-1);
428   err = assuan_transact (ctx, "GETINFO pid", getinfo_pid_cb, r_pid,
429                          NULL, NULL, NULL, NULL);
430   if (!err && *r_pid == (pid_t)(-1))
431     {
432       log_debug ("%s:%s: server did not return a PID", SRCNAME, __func__);
433       err = gpg_error (GPG_ERR_ASSUAN_SERVER_FAULT);
434     }
435
436   if (*r_pid != (pid_t)(-1) && !AllowSetForegroundWindow (*r_pid))
437     log_error_w32 (-1, "AllowSetForegroundWindow(%u) failed", *r_pid);
438
439   if (!err && hwnd)
440     {
441       snprintf (numbuf, sizeof numbuf, "%lx", (unsigned long)hwnd);
442       err = send_one_option (ctx, "window-id", numbuf);
443     }
444
445   return err;
446 }
447
448
449 /* Connect to the UI server and setup the connection.  */
450 static gpg_error_t
451 connect_uiserver (assuan_context_t *r_ctx, pid_t *r_pid, ULONG *r_cmdid,
452                   void *hwnd)
453 {
454   static ULONG retry_counter;
455   ULONG retry_count;
456   gpg_error_t err;
457   assuan_context_t ctx;
458
459   *r_ctx = NULL;
460   *r_pid = (pid_t)(-1);
461   *r_cmdid = 0;
462  retry:
463   err = assuan_socket_connect (&ctx, get_socket_name (), -1);
464   if (err)
465     {
466       /* Let only one thread start an UI server but all allow threads
467          to check for a connection.  Note that this is not really
468          correct as the maximum waiting time decreases with the number
469          of threads.  However, it is unlikely that we have more than 2
470          or 3 threads here - if at all more than one.  */
471       retry_count = InterlockedExchangeAdd (&retry_counter, 1);
472       if (retry_count < FIREUP_RETRIES)
473         {
474           if (!retry_count)
475             {
476               char *uiserver = get_uiserver_name ();
477               if (!uiserver)
478                 {
479                   log_error ("%s:%s: UI server not installed",
480                              SRCNAME, __func__);
481                   InterlockedExchange (&retry_counter, FIREUP_RETRIES);
482                   retry_count = FIREUP_RETRIES;
483                 }
484               else
485                 {
486                   log_debug ("%s:%s: UI server not running, starting `%s'",
487                              SRCNAME, __func__, uiserver);
488                   if (gpgol_spawn_detached (uiserver))
489                     {
490                       /* Error; try again to connect in case the
491                          server has been started in the meantime.
492                          Make sure that we don't get here a second
493                          time.  */
494                       InterlockedExchange (&retry_counter, FIREUP_RETRIES);
495                     }
496                   xfree (uiserver);
497                 }
498             }
499           if (retry_count < FIREUP_RETRIES)
500             {
501               log_debug ("%s:%s: waiting for UI server to come up",
502                          SRCNAME, __func__);
503               Sleep (1000);
504               goto retry;
505             }
506         }
507       else
508         {
509           /* Avoid a retry counter overflow by limiting to the limit.  */
510           InterlockedExchange (&retry_counter, FIREUP_RETRIES);
511         }
512
513       log_error ("%s:%s: error connecting `%s': %s\n", SRCNAME, __func__,
514                  get_socket_name (), gpg_strerror (err));
515     }
516   else if ((err = send_options (ctx, hwnd, r_pid)))
517     {
518       assuan_disconnect (ctx);
519     }
520   else
521     {
522       *r_cmdid = create_command_id ();
523       *r_ctx = ctx;
524     }
525   return err;
526 }
527
528
529
530 \f
531 \f
532 static void
533 cleanup (void)
534 {
535   /* Fixme: We should stop the worker thread.  */
536 }
537
538
539 /* Cleanup static resources. */
540 void
541 op_assuan_deinit (void)
542 {
543   cleanup ();
544 }
545
546
547 /* Initialize this system. */
548 int
549 op_assuan_init (void)
550 {
551   static int init_done;
552   gpgme_error_t err;
553   assuan_context_t ctx;
554   pid_t pid;
555   ULONG cmdid;
556
557   if (init_done)
558     return 0;
559   
560   /* Run a test connection to see whether the UI server is available.  */
561   err = connect_uiserver (&ctx, &pid, &cmdid, NULL);
562   if (!err)
563     {
564       err = assuan_transact (ctx, "NOP", NULL, NULL, NULL, NULL, NULL, NULL);
565       assuan_disconnect (ctx);
566     }
567   if (err)
568     return err;
569   
570   /* Fire up the pipe worker thread. */
571   {
572     HANDLE th;
573     DWORD  mytid, tid;
574
575     InitializeCriticalSection (&work_queue_lock);
576     work_queue_event = CreateEvent (NULL, FALSE, FALSE, NULL);
577     if (!work_queue_event)
578       {
579         log_error_w32 (-1, "%s:%s: CreateEvent failed", SRCNAME, __func__);
580         return gpg_error (GPG_ERR_GENERAL);
581       }
582     mytid = GetCurrentThreadId ();
583     th = CreateThread (NULL, 256*1024, async_worker_thread, (void*)mytid,
584                        0, &tid);
585     if (th == INVALID_HANDLE_VALUE)
586       log_error ("failed to launch the async_worker_thread");
587     else
588       CloseHandle (th);
589   }
590
591   init_done = 1; 
592   return 0;
593 }
594
595 #if 0 /* Not used. */
596 /* Dummy window procedure.  */
597 static LRESULT CALLBACK 
598 attach_thread_input_wndw_proc (HWND hwnd, UINT msg, 
599                                WPARAM wparam, LPARAM lparam)
600 {               
601   return DefWindowProc (hwnd, msg, wparam, lparam);
602 }
603
604
605 /* Our helper thread needs to attach its input events to the main
606    message queue.  To do this we need to create a the message queue
607    first by creating an hidden window within this thread.  */
608 static void
609 attach_thread_input (DWORD other_tid)
610 {
611   WNDCLASS wndwclass = {0, attach_thread_input_wndw_proc, 0, 0, glob_hinst,
612                         0, 0, 0, 0, "gpgol-assuan-engine"};
613   HWND hwnd;
614
615   /* First create a window to make sure that a message queue exists
616      for this thread.  */
617   if (!RegisterClass (&wndwclass))
618     {
619       log_error_w32 (-1, "%s:%s: error registering window class",
620                      SRCNAME, __func__);
621       return;
622     }
623   hwnd = CreateWindow ("gpgol-assuan-engine", "gpgol-assuan-engine",
624                        0, 0, 0, 0, 0, NULL, NULL, glob_hinst, NULL);
625   if (!hwnd)
626     {
627       log_error_w32 (-1, "%s:%s: error creating main window",
628                      SRCNAME, __func__);
629       return;
630     }
631
632   /* Now attach it to the main thread.  */
633   if (!AttachThreadInput (GetCurrentThreadId (), other_tid,  TRUE))
634     log_error_w32 (-1, "%s:%s: AttachThreadInput failed",
635                    SRCNAME, __func__);
636   log_debug ("%s:%s: attached thread %lu to %lu", SRCNAME, __func__,
637              GetCurrentThreadId (), other_tid);
638 }
639 #endif /* not used.  */
640
641
642 /* This is a wraper around SwitchToThread, a syscall we unfortunately
643    need due to the lack of an sophisticated event system.  The wrapper
644    calls SwitchToThread but after a couple of immediate folliwing
645    switches, it introduces a short delays.  */
646 static void
647 switch_threads (work_item_t item)
648 {
649   ULONG count;
650
651   count = InterlockedExchangeAdd (&item->switch_counter, 1);
652   if (count > 5)
653     {
654       /* Tried too often without success.  Use Sleep until
655          clear_switch_threads has been called.  */
656       InterlockedExchange (&item->switch_counter, 5);
657       SleepEx (60, TRUE); 
658     }
659   else if (!SwitchToThread ())
660     {
661       /* No runable other thread: Fall asleep. */
662       SleepEx (8, TRUE);
663     }
664 }
665
666 /* Call this fucntion if some action has been done.  */
667 static void
668 clear_switch_threads (work_item_t item)
669 {
670   InterlockedExchange (&item->switch_counter, 0);
671 }
672
673
674
675 \f
676 /* Helper to write to the callback.  */
677 static void
678 write_to_callback (work_item_t item, DWORD nbytes)
679 {
680   int nwritten;
681
682   if (!nbytes)
683     {
684       /* (With overlapped, EOF is not indicated by NBYTES==0.)  */
685       log_error ("%s:%s: [%s:%p] short read (0 bytes)",
686                  SRCNAME, __func__, item->name, item->hd);
687     }
688   else
689     {
690       assert (nbytes > 0);
691       nwritten = gpgme_data_write (item->data, item->buffer, nbytes);
692       if (nwritten < 0)
693         {
694           log_error ("%s:%s: [%s:%p] error writing to callback: %s",
695                      SRCNAME, __func__, item->name, item->hd,strerror (errno));
696           item->got_error = 1;
697         }
698       else if (nwritten < nbytes)
699         {
700           log_error ("%s:%s: [%s:%p] short write to callback (%d of %lu)",
701                      SRCNAME, __func__, item->name, item->hd, nwritten,nbytes);
702           item->got_error = 1;
703         }
704       else
705         {
706           if (debug_ioworker)
707             log_debug ("%s:%s: [%s:%p] wrote %d bytes to callback",
708                        SRCNAME, __func__, item->name, item->hd, nwritten);
709         }
710     }
711 }
712
713 /* Helper for async_worker_thread.  Returns true if the item's handle
714    needs to be put on the wait list.  This is called with the worker
715    mutex hold. */
716 static int
717 worker_start_read (work_item_t item)
718 {
719   DWORD nbytes;
720   int retval = 0;
721
722   /* Read from the handle and write to the callback.  The gpgme
723      callback is expected to never block.  */
724   if (ReadFile (item->hd, item->buffer, sizeof item->buffer,
725                 &nbytes, &item->ov) )
726     {
727       write_to_callback (item, nbytes);
728       retval = 1;
729     }
730   else 
731     {
732       int syserr = GetLastError ();
733
734       if (syserr == ERROR_IO_PENDING)
735         {
736           if (debug_ioworker)
737             log_debug ("%s:%s: [%s:%p] io(read) pending",
738                        SRCNAME, __func__, item->name, item->hd);
739           item->io_pending = sizeof item->buffer;
740           retval = 1;
741         }
742       else if (syserr == ERROR_HANDLE_EOF || syserr == ERROR_BROKEN_PIPE)
743         {
744           if (debug_ioworker)
745             log_debug ("%s:%s: [%s:%p] EOF%s seen",
746                        SRCNAME, __func__, item->name, item->hd,
747                        syserr == ERROR_BROKEN_PIPE? " (broken pipe)":"");
748           item->got_ready = 1;
749         }
750       else
751         {
752           log_error_w32 (syserr, "%s:%s: [%s:%p] read error",
753                          SRCNAME, __func__, item->name, item->hd);
754           item->got_error = 1;
755         }
756     }
757
758   return retval;
759 }
760
761 /* Result checking helper for async_worker_thread.  This is called with
762    the worker mutex hold.  */
763 static void
764 worker_check_read (work_item_t item, DWORD nbytes)
765 {
766   write_to_callback (item, nbytes);
767 }
768
769
770
771 /* Helper for async_worker_thread.  Returns true if the item's handle
772    needs to be put on the wait list.  This is called with the worker
773    mutex hold.  */
774 static int
775 worker_start_write (work_item_t item)
776 {
777   int nread;
778   DWORD nbytes;
779   int retval = 0;
780
781   assert (!item->io_pending);
782
783   /* Read from the callback and the write to the handle.  The gpgme
784      callback is expected to never block.  */
785   nread = gpgme_data_read (item->data, item->buffer, sizeof item->buffer);
786   if (nread < 0)
787     {
788       if (errno == EAGAIN)
789         {
790           /* EAGAIN from the callback.  That means that data is
791              currently not available.  */
792           if (debug_ioworker_extra)
793             log_debug ("%s:%s: [%s:%p] EAGAIN received from callback",
794                        SRCNAME, __func__, item->name, item->hd);
795           switch_threads (item);
796           retval = 1;
797         }
798       else
799         {
800           clear_switch_threads (item);
801           log_error ("%s:%s: [%s:%p] error reading from callback: %s",
802                      SRCNAME, __func__, item->name, item->hd,strerror (errno));
803           item->got_error = 1;
804         }
805     }
806   else if (!nread)
807     {
808       clear_switch_threads (item);
809       if (debug_ioworker)
810         log_debug ("%s:%s: [%s:%p] EOF received from callback",
811                    SRCNAME, __func__, item->name, item->hd);
812       item->got_ready = 1;
813     }
814   else 
815     {                  
816       clear_switch_threads (item);
817       if (WriteFile (item->hd, item->buffer, nread, &nbytes, &item->ov))
818         {
819           if (nbytes < nread)
820             {
821               log_error ("%s:%s: [%s:%p] short write (%lu of %d)", 
822                          SRCNAME, __func__, item->name,item->hd,nbytes, nread);
823               item->got_error = 1;
824             }
825           else
826             {
827               if (debug_ioworker)
828                 log_debug ("%s:%s: [%s:%p] wrote %lu bytes", 
829                            SRCNAME, __func__, item->name, item->hd, nbytes);
830             }
831           retval = 1; /* Keep on waiting for space in the pipe.  */
832         }
833       else 
834         {
835           int syserr = GetLastError ();
836
837           if (syserr == ERROR_IO_PENDING)
838             {
839               /* This is the common case.  Start the async I/O.  */
840               if (debug_ioworker)
841                 log_debug ("%s:%s: [%s:%p] io(write) pending (%d bytes)",
842                            SRCNAME, __func__, item->name, item->hd, nread);
843               item->io_pending = nread;
844               retval = 1; /* Need to wait for the I/O to complete.  */
845             }
846           else
847             {
848               log_error_w32 (syserr, "%s:%s: [%s:%p] write error",
849                              SRCNAME, __func__, item->name, item->hd);
850               item->got_error = 1;
851             }
852         }
853     }
854
855   return retval;
856 }
857
858
859 /* Result checking helper for async_worker_thread.  This is called with
860    the worker mutex hold.  */
861 static void
862 worker_check_write (work_item_t item, DWORD nbytes)
863 {
864   if (nbytes < item->io_pending)
865     {
866       log_error ("%s:%s: [%s:%p] short write (%lu of %d)",
867                  SRCNAME,__func__, item->name, item->hd, nbytes,
868                  item->io_pending);
869       item->got_error = 1;
870     }
871   else
872     {
873       if (debug_ioworker)
874         log_debug ("%s:%s: [%s:%p] write finished (%lu bytes)", 
875                    SRCNAME, __func__, item->name, item->hd, nbytes);
876     }
877 }
878
879
880
881 /* The worker thread which feeds the pipes.  */
882 static DWORD WINAPI
883 async_worker_thread (void *dummy)
884 {
885   work_item_t item;
886   int n;
887   DWORD nbytes;
888   HANDLE hdarray[MAXIMUM_WAIT_OBJECTS];
889   int count, addit, any_ready, hdarraylen;
890   
891 /*   attach_thread_input ( (DWORD)dummy ); */
892   (void)dummy;
893
894   for (;;)
895     {
896       /* 
897          Step 1: Walk our queue and fire up async I/O requests.  
898        */
899       if (debug_ioworker_extra)
900         log_debug ("%s:%s: step 1 - scanning work queue", SRCNAME, __func__);
901       EnterCriticalSection (&work_queue_lock);
902       
903       /* We always need to wait on the the work queue event.  */
904       hdarraylen = 0;
905       hdarray[hdarraylen++] = work_queue_event;
906
907       count = 0;
908       any_ready = 0;
909       for (item = work_queue; item; item = item->next)
910         {
911           item->waiting = 0;
912           if (!item->used)
913             continue;
914           assert (item->hd != INVALID_HANDLE_VALUE);
915           count++;
916           if (item->got_error)
917             {
918               if (!item->delayed_ready)
919                 any_ready = 1;
920               continue; 
921             }
922           assert (item->data);
923           if (hdarraylen == DIM (hdarray))
924             {
925               if (debug_ioworker)
926                 log_debug ("%s:%s: [%s:%p] wait array full - ignored for now",
927                            SRCNAME, __func__, item->name, item->hd);
928               continue;
929             }
930
931           /* Decide whether we need to wait for this item.  This is
932              the case if the previous WriteFile or ReadFile indicated
933              that I/O is pending or if the worker_start_foo function
934              indicated that we should wait.  Put handles we want to
935              wait upon into HDARRAY. */ 
936           if (item->inactive)
937             addit = 0;
938           else if (item->io_pending)
939             addit = 1;
940           else if (item->writing)
941             addit = worker_start_write (item);
942           else 
943             addit = worker_start_read (item);
944
945           if (addit)
946             {
947               hdarray[hdarraylen++] = item->hd;
948               item->waiting = 1; /* Only required for debugging.  */
949             }
950
951           /* Set a flag if this work item is ready or got an error.  */
952           if (!item->delayed_ready && (item->got_error || item->got_ready))
953             any_ready = 1;
954         }
955       LeaveCriticalSection (&work_queue_lock);
956
957       /*
958          Step 2: Wait for events or handle activitity.
959        */
960       if (any_ready)
961         {
962           /* There is at least one work item which is ready or got an
963              error.  Skip the wait step so that we process it
964              immediately.  */
965           if (debug_ioworker_extra)
966             log_debug ("%s:%s: step 2 - %d items in queue; skipping wait", 
967                        SRCNAME, __func__, count);
968         }
969       else
970         {
971           if (debug_ioworker_extra)
972             {
973               log_debug ("%s:%s: step 2 - "
974                          "%d items in queue; waiting for %d items:",
975                          SRCNAME, __func__, count, hdarraylen-1);
976               for (item = work_queue; item; item = item->next)
977                 {
978                   if (item->waiting)
979                     log_debug ("%s:%s: [%s:%p]",
980                                SRCNAME, __func__, item->name, item->hd);
981                 }
982             }
983           /* [Currently not used]
984              First process any window messages of this thread.  Do
985              this before wating so that the message queue is cleared
986              before waiting and we don't get stucked due to messages
987              not removed.  We need to process the message queue also
988              after the wait because we will only get to here if there
989              is actual ui-server work to be done but some messages
990              might still be in the queue.  */
991 /*           { */
992 /*             MSG msg; */
993
994 /*             while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) */
995 /*               { */
996 /*                 TranslateMessage (&msg); */
997 /*                 DispatchMessage (&msg); */
998 /*               } */
999 /*           } */
1000
1001           n = WaitForMultipleObjects (hdarraylen, hdarray, FALSE, INFINITE);
1002 /*           n = MsgWaitForMultipleObjects (hdarraylen, hdarray, FALSE, */
1003 /*                                          INFINITE, QS_ALLEVENTS); */
1004           if (n == WAIT_FAILED)
1005             {
1006               /* The WFMO failed.  This is an error; to help debugging
1007                  we now print information about all the handles we
1008                  wanted to wait upon.  */
1009               int i;
1010               DWORD hdinfo;
1011                   
1012               log_error_w32 (-1, "%s:%s: WFMO failed", SRCNAME, __func__);
1013               for (i=0; i < hdarraylen; i++)
1014                 {
1015                   hdinfo = 0;
1016                   if (!GetHandleInformation (hdarray[i], &hdinfo))
1017                     log_debug_w32 (-1, "%s:%s: WFMO GetHandleInfo(%p) failed", 
1018                                    SRCNAME, __func__, hdarray[i]);
1019                   else
1020                     log_debug ("%s:%s: WFMO GetHandleInfo(%p)=0x%lu", 
1021                                SRCNAME, __func__, hdarray[i],
1022                                (unsigned long)hdinfo);
1023                 }
1024               Sleep (1000);
1025             }
1026           else if (n >= 0 && n < hdarraylen)
1027             {
1028               if (debug_ioworker_extra)
1029                 log_debug ("%s:%s: WFMO succeeded (res=%d, hd=%p)",
1030                            SRCNAME, __func__, n, hdarray[n]);
1031             }
1032           else if (n == hdarraylen)
1033             {
1034               if (debug_ioworker_extra)
1035                 log_debug ("%s:%s: WFMO succeeded (res=%d, msgevent)",
1036                            SRCNAME, __func__, n);
1037             }
1038           else
1039             {
1040               log_error ("%s:%s: WFMO returned: %d", SRCNAME, __func__, n);
1041               Sleep (1000);
1042             }
1043
1044           /* [Currently not used] 
1045              Try to process the message queue.  */
1046 /*           { */
1047 /*             MSG msg; */
1048             
1049 /*             while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) */
1050 /*               { */
1051 /*                 TranslateMessage (&msg); */
1052 /*                 DispatchMessage (&msg); */
1053 /*               } */
1054 /*           } */
1055         }
1056
1057       /*
1058          Step 3: Handle I/O completion status.
1059        */
1060       EnterCriticalSection (&work_queue_lock);
1061       if (debug_ioworker_extra)
1062         log_debug ("%s:%s: step 3 - checking completion states", 
1063                    SRCNAME, __func__);
1064       for (item = work_queue; item; item = item->next)
1065         {
1066           if (!item->io_pending || item->inactive)
1067             {
1068               /* No I/O is pending for that item, thus there is no
1069                  need to check a completion status.  */
1070             }
1071           else if (GetOverlappedResult (item->hd, &item->ov, &nbytes, FALSE))
1072             {
1073               /* An overlapped I/O result is available.  Check that
1074                  the returned number of bytes are plausible and clear
1075                  the I/O pending flag of this work item.  For a a read
1076                  item worker_check_read forwards the received data to
1077                  the caller.  */
1078               if (item->writing)
1079                 worker_check_write (item, nbytes);
1080               else
1081                 worker_check_read (item, nbytes);
1082               item->io_pending = 0;
1083             }
1084           else 
1085             {
1086               /* Some kind of error occured: Set appropriate
1087                  flags.  */
1088               int syserr = GetLastError ();
1089               if (syserr == ERROR_IO_INCOMPLETE)
1090                 {
1091                   /* This is a common case, the I/O has not yet
1092                      completed for this work item.  No need for any
1093                      action. */
1094                 }
1095               else if (!item->writing && (syserr == ERROR_HANDLE_EOF
1096                                           || syserr == ERROR_BROKEN_PIPE) )
1097                 {
1098                   /* Got EOF.  */
1099                   if (debug_ioworker)
1100                     log_debug ("%s:%s: [%s:%p] EOF%s received",
1101                                SRCNAME, __func__, item->name, item->hd,
1102                                syserr==ERROR_BROKEN_PIPE?" (broken pipe)":"");
1103                   item->io_pending = 0;
1104                   item->got_ready = 1;
1105                 }
1106               else
1107                 {
1108                   /* Something went wrong.  We better cancel the I/O. */
1109                   log_error_w32 (syserr,
1110                                  "%s:%s: [%s:%p] GetOverlappedResult failed",
1111                                  SRCNAME, __func__, item->name, item->hd);
1112                   item->io_pending = 0;
1113                   item->got_error = 1;
1114                   if (!item->aborting)
1115                     {
1116                       item->aborting = 1;
1117                       if (!CancelIo (item->hd))
1118                         log_error_w32 (-1, "%s:%s: [%s:%p] CancelIo failed",
1119                                        SRCNAME,__func__, item->name, item->hd);
1120                     }
1121                   else 
1122                     item->got_ready = 1;
1123                 }
1124             }
1125         }
1126       LeaveCriticalSection (&work_queue_lock);
1127
1128       /* 
1129          Step 4: Act on the flags set in step 3.
1130        */
1131
1132       /* Give the system a chance to process cancel I/O etc. */
1133       SwitchToThread ();
1134
1135       EnterCriticalSection (&work_queue_lock);
1136       if (debug_ioworker_extra)
1137         log_debug ("%s:%s: step 4 - cleaning up work queue",
1138                    SRCNAME, __func__); 
1139       for (item = work_queue; item; item = item->next)
1140         {
1141           if (item->used && (item->got_ready || item->got_error))
1142             {
1143               /* This is a work item either flagged as ready or as in
1144                  error state. */
1145               
1146               if (item->cld)
1147                 {
1148                   /* Perform the closure.  */
1149                   work_item_t itm2;
1150
1151                   /* If the Assuan state did not return an ERR but the
1152                      I/O machinery set this work item int the error
1153                      state, we set the final error to reflect this.  */
1154                   if (!item->cld->final_err && item->got_error)
1155                     item->cld->final_err = gpg_error (GPG_ERR_EIO);
1156
1157                   /* Check whether there are other work items in this
1158                      group we need to wait for before invoking the
1159                      closure. */
1160                   for (itm2=work_queue; itm2; itm2 = itm2->next)
1161                     if (itm2->used && itm2 != item 
1162                         && itm2->cmdid == item->cmdid
1163                         && itm2->wait_on_success
1164                         && !(itm2->got_ready || itm2->got_error))
1165                       break;
1166                   if (itm2)
1167                     {
1168                       /* We need to delay the closure until all work
1169                          items we depend on are ready.  */
1170                       if (debug_ioworker)
1171                         log_debug ("%s:%s: [%s:%p] delaying closure "
1172                                    "due to [%s:%p]", SRCNAME, __func__,
1173                                    item->name, item->hd, 
1174                                    itm2->name, itm2->hd);
1175                       item->delayed_ready = 1;
1176                       if (item->cld->final_err)
1177                         {
1178                           /* However, if we received an error we better
1179                              do not assume that the server has properly
1180                              closed all I/O channels.  Send a cancel
1181                              to the work item we are waiting for. */
1182                           if (!itm2->aborting)
1183                             {
1184                               if (debug_ioworker)
1185                                 log_debug ("%s:%s: [%s:%p] calling CancelIO",
1186                                            SRCNAME, __func__,
1187                                            itm2->name, itm2->hd);
1188                               itm2->aborting = 1;
1189                               if (!CancelIo (itm2->hd))
1190                                 log_error_w32 (-1, "%s:%s: [%s:%p] "
1191                                                "CancelIo failed",
1192                                                SRCNAME,__func__, 
1193                                                itm2->name, itm2->hd);
1194                             }
1195                           else
1196                             {
1197                               /* Ooops second time here: Clear the
1198                                  wait flag so that we won't get to
1199                                  here anymore.  */
1200                               if (debug_ioworker)
1201                                 log_debug ("%s:%s: [%s:%p] clearing "
1202                                            "wait on success flag",
1203                                            SRCNAME, __func__,
1204                                            itm2->name, itm2->hd);
1205                               itm2->wait_on_success = 0;
1206                             }
1207                         }
1208                       goto step4_cont;
1209                     }
1210                   
1211                   item->delayed_ready = 0;
1212                   if (debug_ioworker)
1213                     log_debug ("%s:%s: [%s:%p] invoking closure",
1214                                SRCNAME,__func__, item->name, item->hd);
1215                   
1216                   item->cld->closure (item->cld);
1217                   xfree (item->cld);
1218                   item->cld = NULL;
1219                 } /* End closure processing.  */
1220
1221               item->got_ready = 0;
1222               item->finalize (item);
1223               item->used = 0;
1224             step4_cont:
1225               ;
1226             }
1227         }
1228
1229       LeaveCriticalSection (&work_queue_lock);
1230     }
1231 }
1232
1233
1234 void
1235 engine_assuan_cancel (void *cancel_data)
1236 {
1237   /* FIXME */
1238 }
1239
1240
1241
1242
1243 /* Standard finalize handler.  Called right before the item is removed
1244    from the queue.  Called while the work_queue_lock is hold.  */
1245 static void
1246 finalize_handler (work_item_t item)
1247 {
1248   if (debug_ioworker)
1249     log_debug ("%s:%s: [%s:%p] closing handle", 
1250                SRCNAME, __func__, item->name, item->hd);
1251   CloseHandle (item->hd);
1252   item->hd = INVALID_HANDLE_VALUE;
1253 }
1254
1255 /* A finalize handler which does not close the handle.  */
1256 static void
1257 noclose_finalize_handler (work_item_t item)
1258 {
1259   if (debug_ioworker)
1260     log_debug ("%s:%s: [%s:%p] called",
1261                SRCNAME, __func__, item->name, item->hd);
1262   item->hd = INVALID_HANDLE_VALUE;
1263 }
1264
1265
1266 /* Add a data callback and a handle to the work queue.  This should
1267    only be called once per handle.  Caller gives up ownership of
1268    CLD. */
1269 static void
1270 enqueue_callback (const char *name, assuan_context_t ctx, 
1271                   gpgme_data_t data, HANDLE hd,
1272                   int for_write, void (*fin_handler)(work_item_t),
1273                   ULONG cmdid, closure_data_t cld, 
1274                   int wait_on_success, int inactive)
1275 {
1276   work_item_t item;
1277   int created = 0;
1278
1279   EnterCriticalSection (&work_queue_lock);
1280   for (item = work_queue; item; item = item->next)
1281     if (!item->used)
1282       break;
1283   if (!item)
1284     {
1285       item = xmalloc (sizeof *item);
1286       item->next = work_queue;
1287       work_queue = item;
1288       created = 1;
1289     }
1290   item->used = 1;
1291   item->name = name;
1292   item->cmdid = cmdid;
1293   item->cld = cld;
1294   item->wait_on_success = wait_on_success;
1295   item->data = data;
1296   item->writing = for_write;
1297   item->hd = hd;
1298   item->inactive = inactive;
1299   item->io_pending = 0;
1300   item->got_ready = 0;
1301   item->delayed_ready = 0;
1302   item->got_error = 0;
1303   item->aborting = 0;
1304   item->finalize = fin_handler;
1305   memset (&item->ov, 0, sizeof item->ov);
1306   if (debug_ioworker)
1307     log_debug ("%s:%s: [%s:%p] created%s",
1308                SRCNAME, __func__, item->name, item->hd,
1309                created?"":" (reusing)");
1310   LeaveCriticalSection (&work_queue_lock);
1311 }
1312
1313
1314 /* Set all items of CMDID into the active state.  */
1315 static void
1316 set_items_active (ULONG cmdid)
1317 {
1318   work_item_t item;
1319
1320   EnterCriticalSection (&work_queue_lock);
1321   for (item = work_queue; item; item = item->next)
1322     if (item->used && item->cmdid == cmdid)
1323       item->inactive = 0;
1324   LeaveCriticalSection (&work_queue_lock);
1325 }
1326
1327
1328 static void
1329 destroy_command (ULONG cmdid, int force)
1330 {
1331   work_item_t item;
1332
1333   EnterCriticalSection (&work_queue_lock);
1334   for (item = work_queue; item; item = item->next)
1335     if (item->used && item->cmdid == cmdid 
1336         && (!item->wait_on_success || force))
1337       {
1338         if (debug_ioworker)
1339           log_debug ("%s:%s: [%s:%p] cmdid=%lu registered for destroy",
1340                      SRCNAME, __func__, item->name, item->hd, item->cmdid);
1341         /* First send an I/O cancel in case the last
1342            GetOverlappedResult returned only a partial result.  This
1343            works because we are always running within the
1344            async_worker_thread.  */
1345 /*         if (!CancelIo (item->hd)) */
1346 /*           log_error_w32 (-1, "%s:%s: [%s:%p] CancelIo failed", */
1347 /*                          SRCNAME, __func__, item->name, item->hd); */
1348         item->got_ready = 1;
1349       }
1350   LeaveCriticalSection (&work_queue_lock);
1351 }
1352
1353
1354 /* Process a status line.  */
1355 static int
1356 status_handler (closure_data_t cld, const char *line)
1357 {
1358   gpg_error_t err;
1359   int retval = 0;
1360
1361   if (debug_ioworker)
1362     log_debug ("%s:%s: cld %p, line `%s'", SRCNAME, __func__, cld, line);
1363
1364   if (*line == '#' || !*line)
1365     ;
1366   else if (line[0] == 'D' && line[1] == ' ')
1367     {
1368       line += 2;
1369     }
1370   else if (line[0] == 'S' && (!line[1] || line[1] == ' '))
1371     {
1372       for (line += 1; *line == ' '; line++)
1373         ;
1374     }  
1375   else if (line[0] == 'O' && line[1] == 'K' && (!line[2] || line[2] == ' '))
1376     {
1377       for (line += 2; *line == ' '; line++)
1378         ;
1379       cld->final_err = 0;
1380       retval = 1;
1381     }
1382   else if (!strncmp (line, "ERR", 3) && (!line[3] || line[3] == ' '))
1383     {
1384       for (line += 3; *line == ' '; line++)
1385         ;
1386       err = strtoul (line, NULL, 10);
1387       if (!err)
1388         err = gpg_error (GPG_ERR_ASS_INV_RESPONSE);
1389       cld->final_err = err;
1390       retval = 1;
1391     }  
1392   else if (!strncmp (line, "INQUIRE", 7) && (!line[7] || line[7] == ' '))
1393     {
1394       for (line += 7; *line == ' '; line++)
1395         ;
1396       /* We have no inquire handler thus get out of it immediately.  */
1397       err = assuan_write_line (cld->assctx, "END");
1398       if (err)
1399         cld->last_err = err;
1400     }
1401   else if (!strncmp (line, "END", 3) && (!line[3] || line[3] == ' '))
1402     {
1403       for (line += 3; *line == ' '; line++)
1404         ;
1405     }
1406   else
1407     retval = -1; /* Invalid response.  */
1408
1409   return retval;
1410 }
1411
1412
1413 /* This write callback is used by GPGME to push data to our status
1414    line handler.  The function should return the number of bytes
1415    written, and -1 on error.  If an error occurs, ERRNO should be set
1416    to describe the type of the error.  */
1417 static ssize_t
1418 status_in_cb (void *opaque, const void *buffer, size_t size)
1419 {
1420   size_t orig_size = size;
1421   closure_data_t cld = opaque;
1422   status_buffer_t sb;
1423   size_t nleft, nbytes;
1424   char *p;
1425
1426   assert (cld);
1427   if (!size)
1428     return 0;
1429
1430   if (!(sb=cld->status_buffer))
1431     {
1432       cld->status_buffer = sb = xmalloc (sizeof *cld->status_buffer);
1433       sb->eof = 0;
1434       sb->linelen = 0;
1435     }
1436
1437   do
1438     {
1439       assert (sb->linelen < ASSUAN_LINELENGTH);
1440       nleft = ASSUAN_LINELENGTH - sb->linelen;
1441       nbytes = size < nleft? size : nleft;
1442       memcpy (sb->line+sb->linelen, buffer, nbytes);
1443       sb->linelen += nbytes;
1444       size -= nbytes;
1445       while ((p = memchr (sb->line, '\n', sb->linelen)) && !cld->status_ready)
1446         {
1447           *p = 0;
1448           if (p > sb->line && p[-1] == '\r')
1449             p[-1] = 0;
1450           switch (status_handler (cld, sb->line))
1451             {
1452             case 0: 
1453               break;
1454             case 1: /* Ready. */
1455               cld->status_ready = 1;
1456               destroy_command (cld->cmdid, 0);
1457               break;
1458             default:
1459               log_error ("%s:%s: invalid line from server", SRCNAME, __func__);
1460               errno = EINVAL;
1461               return -1;
1462             }
1463           sb->linelen -= (p+1 - sb->line);
1464           memmove (sb->line, p+1, sb->linelen);
1465         }
1466       if (sb->linelen >= ASSUAN_LINELENGTH)
1467         {
1468           log_error ("%s:%s: line from server too long", SRCNAME, __func__);
1469           errno = ERANGE;
1470           return -1;
1471         }
1472     }
1473   while (size);
1474   
1475   return orig_size;
1476 }
1477
1478
1479
1480 /* Start an asynchronous command.  Caller gives up ownership of
1481    CLD.  */
1482 static gpg_error_t
1483 start_command (assuan_context_t ctx, closure_data_t cld,
1484                ULONG cmdid, const char *line)
1485 {
1486   gpg_error_t err;
1487   assuan_fd_t fds[5];
1488   int nfds;
1489
1490   if (debug_ioworker)
1491     log_debug ("%s:%s: sending `%s'", SRCNAME, __func__, line);
1492
1493   /* Get the fd used by assuan for status channel reads.  This is the
1494      first fd returned by assuan_get_active_fds for read fds.  */
1495   nfds = assuan_get_active_fds (ctx, 0, fds, DIM (fds));
1496   if (nfds < 1)
1497     return gpg_error (GPG_ERR_GENERAL); /* Ooops.  */
1498
1499   cld->cmdid = cmdid;
1500   cld->status_cbs.write = status_in_cb;
1501   cld->assctx = ctx;
1502   /* Fixme: We might want to have reference counting for CLD to cope
1503      with thye problem that the gpgme data object uses CLD which might
1504      get invalidated at any time.  */
1505   err = gpgme_data_new_from_cbs (&cld->status_data, &cld->status_cbs, cld);
1506   if (err)
1507     {
1508       xfree (cld);
1509       return err;
1510     }
1511
1512   set_items_active (cmdid);
1513   enqueue_callback ("status", ctx, cld->status_data, fds[0], 0,
1514                     noclose_finalize_handler, cmdid, cld, 0, 0);
1515   cld = NULL; /* Now belongs to the status work item.  */
1516
1517   /* Process the work queue.  */
1518   if (!SetEvent (work_queue_event))
1519     log_error_w32 (-1, "%s:%s: SetEvent failed", SRCNAME, __func__);
1520   /* Send the command. */
1521   return assuan_write_line (ctx, line);
1522 }
1523
1524
1525 static const char *
1526 get_protocol_name (protocol_t protocol)
1527 {
1528   switch (protocol)
1529     {
1530     case PROTOCOL_OPENPGP: return "OpenPGP"; break;
1531     case PROTOCOL_SMIME:   return "CMS"; break;
1532     default: return NULL;
1533     }
1534 }
1535
1536
1537 /* Callback used to get the protocool status line form a PREP_ENCRYPT
1538    or SENDER command.  */
1539 static assuan_error_t
1540 prep_foo_status_cb (void *opaque, const char *line)
1541 {
1542   protocol_t *protocol = opaque;
1543
1544   if (!strncmp (line, "PROTOCOL", 8) && (line[8]==' ' || !line[8]))
1545     {
1546       for (line += 8; *line == ' '; line++)
1547         ;
1548       if (!strncmp (line, "OpenPGP", 7) && (line[7]==' '||!line[7]))
1549         *protocol = PROTOCOL_OPENPGP;
1550       else if (!strncmp (line, "CMS", 3) && (line[3]==' '||!line[3]))
1551         *protocol = PROTOCOL_SMIME;
1552     }
1553   return 0;
1554 }
1555
1556
1557
1558 \f
1559 /* Note that this closure is called in the context of the
1560    async_worker_thread.  */
1561 static void
1562 encrypt_closure (closure_data_t cld)
1563 {
1564   engine_private_finished (cld->filter, cld->final_err);
1565 }
1566
1567
1568 /* Encrypt the data from INDATA to the OUTDATA object for all
1569    recpients given in the NULL terminated array RECIPIENTS.  This
1570    function terminates with success and then expects the caller to
1571    wait for the result of the encryption using engine_wait.  FILTER is
1572    used for asynchronous commnication with the engine module.  HWND is
1573    the window handle of the current window and used to maintain the
1574    correct relationship between a popups and the active window.  If
1575    this function returns success, the data objects may only be
1576    destroyed after an engine_wait or engine_cancel.  On success the
1577    function returns a poiunter to the encryption state and thus
1578    requires that op_assuan_encrypt_bottom will be run later. */
1579 int
1580 op_assuan_encrypt (protocol_t protocol, 
1581                    gpgme_data_t indata, gpgme_data_t outdata,
1582                    engine_filter_t filter, void *hwnd,
1583                    char **recipients, protocol_t *r_used_protocol,
1584                    struct engine_assuan_encstate_s **r_encstate)
1585 {
1586   gpg_error_t err;
1587   closure_data_t cld;
1588   assuan_context_t ctx;
1589   char line[1024];
1590   HANDLE inpipe[2], outpipe[2];
1591   ULONG cmdid;
1592   pid_t pid;
1593   int i;
1594   char *p;
1595   int detect_protocol;
1596   const char *protocol_name;
1597   struct engine_assuan_encstate_s *encstate;
1598
1599   *r_encstate = NULL;
1600
1601   detect_protocol = !(protocol_name = get_protocol_name (protocol));
1602
1603   err = connect_uiserver (&ctx, &pid, &cmdid, hwnd);
1604   if (err)
1605     return err;
1606
1607   if ((err = create_io_pipe (inpipe, pid, 1)))
1608     return err;
1609   if ((err = create_io_pipe (outpipe, pid, 0)))
1610     {
1611       close_pipe (inpipe);
1612       return err;
1613     }
1614
1615   cld = xcalloc (1, sizeof *cld);
1616   cld->closure = encrypt_closure;
1617   cld->filter = filter;
1618
1619   err = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
1620   if (err)
1621     goto leave;
1622   for (i=0; recipients && recipients[i]; i++)
1623     {
1624       snprintf (line, sizeof line, "RECIPIENT %s", recipients[i]);
1625       for (p=line; *p; p++)
1626         if (*p == '\n' || *p =='\r' )
1627           *p = ' ';
1628       err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1629       if (err)
1630         goto leave;
1631     }
1632
1633   /* If the protocol has not been given, let the UI server tell us the
1634      protocol to use. */
1635   if (detect_protocol)
1636     {
1637       protocol = PROTOCOL_UNKNOWN;
1638       err = assuan_transact (ctx, "PREP_ENCRYPT", NULL, NULL, NULL, NULL,
1639                              prep_foo_status_cb, &protocol);
1640       if (err)
1641         {
1642           if (gpg_err_code (err) == GPG_ERR_ASS_UNKNOWN_CMD)
1643             err = gpg_error (GPG_ERR_INV_VALUE);
1644           goto leave;
1645         }
1646       if ( !(protocol_name = get_protocol_name (protocol)) )
1647         {
1648           err = gpg_error (GPG_ERR_INV_VALUE);
1649           goto leave;
1650         }
1651     }
1652
1653   *r_used_protocol = protocol;
1654
1655   /* Note: We don't use real descriptor passing but a hack: We
1656      duplicate the handle into the server process and the server then
1657      uses this handle.  Eventually we should put this code into
1658      assuan_sendfd.  */
1659   snprintf (line, sizeof line, "INPUT FD=%ld", (unsigned long int)inpipe[0]);
1660   err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1661   if (err)
1662     goto leave;
1663   snprintf (line, sizeof line, "OUTPUT FD=%ld", (unsigned long int)outpipe[1]);
1664   err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1665   if (err)
1666     goto leave;
1667
1668   /* The work items are created as inactive, so that the worker thread
1669      ignores them.  They are set to active by with the start_command
1670      function called by op_assuan_encrypt_bottom.  */
1671   enqueue_callback (" input", ctx, indata, inpipe[1], 1, finalize_handler,
1672                     cmdid, NULL, 0, 1); 
1673   enqueue_callback ("output", ctx, outdata, outpipe[0], 0, finalize_handler, 
1674                     cmdid, NULL, 1 /* Wait on success */, 1); 
1675
1676   encstate = xcalloc (1, sizeof *encstate);
1677   encstate->filter = filter;
1678   encstate->protocol_name = protocol_name;
1679   encstate->inpipe[0] = inpipe[0];
1680   encstate->inpipe[1] = inpipe[1];
1681   encstate->outpipe[0] = outpipe[0];
1682   encstate->outpipe[1] = outpipe[1];
1683   encstate->cld = cld;
1684   encstate->ctx = ctx;
1685   encstate->cmdid = cmdid;
1686   *r_encstate = encstate;
1687   return 0;
1688
1689  leave:
1690   if (err)
1691     {
1692       /* Fixme: Cancel stuff in the work_queue. */
1693       close_pipe (inpipe);
1694       close_pipe (outpipe);
1695       xfree (cld);
1696       assuan_disconnect (ctx);
1697     }
1698   else
1699     engine_private_set_cancel (filter, ctx);
1700   return err;
1701 }
1702
1703 /* Continue and actually start the encryption or cancel it with CANCEL
1704    set to TRUE.  The fucntion takes ownvership of ENCSTATE.  */
1705 int
1706 op_assuan_encrypt_bottom (struct engine_assuan_encstate_s *encstate,
1707                           int cancel)
1708 {
1709   char line[1024];
1710   gpg_error_t err;
1711
1712   if (!encstate)
1713     return 0;
1714   if (cancel)
1715     err = gpg_error (GPG_ERR_CANCELED);
1716   else
1717     {
1718       snprintf (line, sizeof line, "ENCRYPT --protocol=%s",
1719                 encstate->protocol_name);
1720       err = start_command (encstate->ctx, encstate->cld, 
1721                            encstate->cmdid, line);
1722       encstate->cld = NULL; /* Now owned by start_command.  */
1723     }
1724
1725   if (err)
1726     {
1727       xfree (encstate->cld);
1728       encstate->cld = NULL;
1729       engine_private_set_cancel (encstate->filter, NULL);
1730       close_pipe (encstate->inpipe);
1731       close_pipe (encstate->outpipe);
1732       if (cancel)
1733         destroy_command (encstate->cmdid, 1);
1734       assuan_disconnect (encstate->ctx);
1735       encstate->ctx = NULL;
1736     }
1737   else
1738     engine_private_set_cancel (encstate->filter, encstate->ctx);
1739   xfree (encstate);
1740   return err;
1741 }
1742
1743
1744
1745 \f
1746 /* Note that this closure is called in the context of the
1747    async_worker_thread.  */
1748 static void
1749 sign_closure (closure_data_t cld)
1750 {
1751   engine_private_finished (cld->filter, cld->final_err);
1752 }
1753
1754
1755 /* Created a detached signature for INDATA and write it to OUTDATA.
1756    On termination of the signing command engine_private_finished() is
1757    called with FILTER as the first argument.  SENDER is the sender's
1758    mail address (a mailbox).  The used protocol wioll be stored at
1759    R_PROTOCOL. */
1760 int 
1761 op_assuan_sign (protocol_t protocol, 
1762                 gpgme_data_t indata, gpgme_data_t outdata,
1763                 engine_filter_t filter, void *hwnd,
1764                 const char *sender, protocol_t *r_used_protocol)
1765 {
1766   gpg_error_t err;
1767   closure_data_t cld;
1768   assuan_context_t ctx;
1769   char line[1024];
1770   HANDLE inpipe[2], outpipe[2];
1771   ULONG cmdid;
1772   pid_t pid;
1773   int detect_protocol;
1774   const char *protocol_name;
1775   protocol_t suggested_protocol;
1776
1777   detect_protocol = !(protocol_name = get_protocol_name (protocol));
1778
1779   err = connect_uiserver (&ctx, &pid, &cmdid, hwnd);
1780   if (err)
1781     return err;
1782
1783   if ((err = create_io_pipe (inpipe, pid, 1)))
1784     return err;
1785   if ((err = create_io_pipe (outpipe, pid, 0)))
1786     {
1787       close_pipe (inpipe);
1788       return err;
1789     }
1790
1791   cld = xcalloc (1, sizeof *cld);
1792   cld->closure = sign_closure;
1793   cld->filter = filter;
1794
1795   err = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
1796   if (err)
1797     goto leave;
1798
1799   /* We always send the SENDER command becuase it allows us to figure
1800      out the protocol to use.  In case the UI server faisl to send the
1801      protocol we fall back to OpenPGP.  */
1802   suggested_protocol = PROTOCOL_UNKNOWN;
1803   if (!sender)
1804     sender = "<kleopatra-does-not-allow-an-empty-arg@example.net>";
1805   snprintf (line, sizeof line, "SENDER%s%s", sender? " ":"", sender?sender:"");
1806   err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL,
1807                          prep_foo_status_cb, &suggested_protocol);
1808   if (err)
1809     {
1810       if (gpg_err_code (err) == GPG_ERR_ASS_UNKNOWN_CMD)
1811         err = gpg_error (GPG_ERR_INV_VALUE);
1812       goto leave;
1813     }
1814   if (detect_protocol)
1815     {
1816       log_debug ("%s:%s: suggested protocol is %d", 
1817                  SRCNAME, __func__, suggested_protocol);
1818       protocol = (suggested_protocol == PROTOCOL_UNKNOWN?
1819                   PROTOCOL_OPENPGP : suggested_protocol);
1820       if ( !(protocol_name = get_protocol_name (protocol)) )
1821         {
1822           err = gpg_error (GPG_ERR_INV_VALUE);
1823           goto leave;
1824         }
1825     }
1826   *r_used_protocol = protocol;
1827   log_debug ("%s:%s: using protocol %s", SRCNAME, __func__, protocol_name);
1828
1829   snprintf (line, sizeof line, "INPUT FD=%ld", (unsigned long int)inpipe[0]);
1830   err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1831   if (err)
1832     goto leave;
1833   snprintf (line, sizeof line, "OUTPUT FD=%ld", (unsigned long int)outpipe[1]);
1834   err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1835   if (err)
1836     goto leave;
1837
1838   enqueue_callback (" input", ctx, indata, inpipe[1], 1, finalize_handler,
1839                     cmdid, NULL, 0, 0); 
1840   enqueue_callback ("output", ctx, outdata, outpipe[0], 0, finalize_handler, 
1841                     cmdid, NULL, 1 /* Wait on success */, 0); 
1842
1843   snprintf (line, sizeof line, "SIGN --protocol=%s --detached",
1844             protocol_name);
1845   err = start_command (ctx, cld, cmdid, line);
1846   cld = NULL; /* Now owned by start_command.  */
1847   if (err)
1848     goto leave;
1849
1850
1851  leave:
1852   if (err)
1853     {
1854       /* Fixme: Cancel stuff in the work_queue. */
1855       close_pipe (inpipe);
1856       close_pipe (outpipe);
1857       xfree (cld);
1858       assuan_disconnect (ctx);
1859     }
1860   else
1861     engine_private_set_cancel (filter, ctx);
1862   return err;
1863 }
1864
1865
1866
1867 \f
1868 /* Note that this closure is called in the context of the
1869    async_worker_thread.  */
1870 static void
1871 decrypt_closure (closure_data_t cld)
1872 {
1873   engine_private_finished (cld->filter, cld->final_err);
1874 }
1875
1876
1877 /* Decrypt data from INDATA to OUTDATE.  If WITH_VERIFY is set, the
1878    signature of a PGP/MIME combined message is also verified the same
1879    way as with op_assuan_verify.  */
1880 int 
1881 op_assuan_decrypt (protocol_t protocol,
1882                    gpgme_data_t indata, gpgme_data_t outdata, 
1883                    engine_filter_t filter, void *hwnd,
1884                    int with_verify)
1885 {
1886   gpg_error_t err;
1887   closure_data_t cld;
1888   assuan_context_t ctx;
1889   char line[1024];
1890   HANDLE inpipe[2], outpipe[2];
1891   ULONG cmdid;
1892   pid_t pid;
1893   const char *protocol_name;
1894
1895   if (!(protocol_name = get_protocol_name (protocol)))
1896     return gpg_error(GPG_ERR_INV_VALUE);
1897
1898   err = connect_uiserver (&ctx, &pid, &cmdid, hwnd);
1899   if (err)
1900     return err;
1901
1902   if ((err = create_io_pipe (inpipe, pid, 1)))
1903     return err;
1904   if ((err = create_io_pipe (outpipe, pid, 0)))
1905     {
1906       close_pipe (inpipe);
1907       return err;
1908     }
1909
1910   cld = xcalloc (1, sizeof *cld);
1911   cld->closure = decrypt_closure;
1912   cld->filter = filter;
1913
1914   err = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
1915   if (err)
1916     goto leave;
1917
1918   snprintf (line, sizeof line, "INPUT FD=%ld", (unsigned long int)inpipe[0]);
1919   err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1920   if (err)
1921     goto leave;
1922   snprintf (line, sizeof line, "OUTPUT FD=%ld", (unsigned long int)outpipe[1]);
1923   err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
1924   if (err)
1925     goto leave;
1926
1927   enqueue_callback (" input", ctx, indata, inpipe[1], 1, finalize_handler,
1928                     cmdid, NULL, 0, 0); 
1929   enqueue_callback ("output", ctx, outdata, outpipe[0], 0, finalize_handler, 
1930                     cmdid, NULL, 1 /* Wait on success */, 0); 
1931
1932   snprintf (line, sizeof line, "DECRYPT --protocol=%s%s",
1933             protocol_name, with_verify? "":" --no-verify");
1934   err = start_command (ctx, cld, cmdid, line);
1935   cld = NULL; /* Now owned by start_command.  */
1936   if (err)
1937     goto leave;
1938
1939
1940  leave:
1941   if (err)
1942     {
1943       /* Fixme: Cancel stuff in the work_queue. */
1944       close_pipe (inpipe);
1945       close_pipe (outpipe);
1946       xfree (cld);
1947       assuan_disconnect (ctx);
1948     }
1949   else
1950     engine_private_set_cancel (filter, ctx);
1951   return err;
1952 }
1953
1954
1955 \f
1956 /* Note that this closure is called in the context of the
1957    async_worker_thread.  */
1958 static void
1959 verify_closure (closure_data_t cld)
1960 {
1961   gpgme_data_release (cld->sigdata);
1962   cld->sigdata = NULL;
1963   engine_private_finished (cld->filter, cld->final_err);
1964 }
1965
1966
1967 /* With MSGDATA, SIGNATURE and SIGLEN given: 
1968
1969       Verify a detached message where the data is in the gpgme object
1970       MSGDATA and the signature given as the string SIGNATURE. 
1971
1972    With MSGDATA and OUTDATA given:
1973
1974       Verify an opaque signature from MSGDATA and write the decoded
1975       plaintext to OUTDATA.
1976
1977 */
1978 int 
1979 op_assuan_verify (gpgme_protocol_t protocol, 
1980                   gpgme_data_t msgdata, const char *signature, size_t sig_len,
1981                   gpgme_data_t outdata,
1982                   engine_filter_t filter, void *hwnd)
1983 {
1984   gpg_error_t err;
1985   closure_data_t cld = NULL;
1986   assuan_context_t ctx;
1987   char line[1024];
1988   HANDLE msgpipe[2], sigpipe[2], outpipe[2];
1989   ULONG cmdid;
1990   pid_t pid;
1991   gpgme_data_t sigdata = NULL;
1992   const char *protocol_name;
1993   int opaque_mode;
1994
1995   msgpipe[0] = INVALID_HANDLE_VALUE;
1996   msgpipe[1] = INVALID_HANDLE_VALUE;
1997   sigpipe[0] = INVALID_HANDLE_VALUE;
1998   sigpipe[1] = INVALID_HANDLE_VALUE;
1999   outpipe[0] = INVALID_HANDLE_VALUE;
2000   outpipe[1] = INVALID_HANDLE_VALUE;
2001
2002   if (!(protocol_name = get_protocol_name (protocol)))
2003     return gpg_error(GPG_ERR_INV_VALUE);
2004
2005   if (signature && sig_len && !outdata)
2006     opaque_mode = 0;
2007   else if (!signature && !sig_len && outdata)
2008     opaque_mode = 1;
2009   else
2010     return gpg_error(GPG_ERR_INV_VALUE);
2011
2012   if (!opaque_mode)
2013     {
2014       err = gpgme_data_new_from_mem (&sigdata, signature, sig_len, 0);
2015       if (err)
2016         goto leave;
2017     }
2018
2019   err = connect_uiserver (&ctx, &pid, &cmdid, hwnd);
2020   if (err)
2021     goto leave;
2022
2023   if (!opaque_mode)
2024     {
2025       if ((err = create_io_pipe (msgpipe, pid, 1)))
2026         goto leave;
2027       if ((err = create_io_pipe (sigpipe, pid, 1)))
2028         goto leave;
2029     }
2030   else
2031     {
2032       if ((err = create_io_pipe (msgpipe, pid, 1)))
2033         goto leave;
2034       if ((err = create_io_pipe (outpipe, pid, 0)))
2035         goto leave;
2036     }
2037
2038   cld = xcalloc (1, sizeof *cld);
2039   cld->closure = verify_closure;
2040   cld->filter = filter;
2041   cld->sigdata = sigdata;
2042
2043   err = assuan_transact (ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
2044   if (err)
2045     goto leave;
2046
2047   if (!opaque_mode)
2048     {
2049       snprintf (line, sizeof line, "MESSAGE FD=%ld",
2050                 (unsigned long int)msgpipe[0]);
2051       err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
2052       if (err)
2053         goto leave;
2054       snprintf (line, sizeof line, "INPUT FD=%ld",
2055                 (unsigned long int)sigpipe[0]);
2056       err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
2057       if (err)
2058         goto leave;
2059       enqueue_callback ("   msg", ctx, msgdata, msgpipe[1], 1,
2060                         finalize_handler, cmdid, NULL, 0, 0); 
2061       enqueue_callback ("   sig", ctx, sigdata, sigpipe[1], 1, 
2062                         finalize_handler, cmdid, NULL, 0, 0); 
2063     }
2064   else 
2065     {
2066       snprintf (line, sizeof line, "INPUT FD=%ld",
2067                 (unsigned long int)msgpipe[0]);
2068       err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
2069       if (err)
2070         goto leave;
2071       snprintf (line, sizeof line, "OUTPUT FD=%ld",
2072                 (unsigned long int)outpipe[1]);
2073       err = assuan_transact (ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
2074       if (err)
2075         goto leave;
2076       enqueue_callback ("   msg", ctx, msgdata, msgpipe[1], 1,
2077                         finalize_handler, cmdid, NULL, 0, 0); 
2078       enqueue_callback ("   out", ctx, outdata, outpipe[0], 0,
2079                         finalize_handler, cmdid, NULL, 1, 0); 
2080     }
2081
2082   snprintf (line, sizeof line, "VERIFY --protocol=%s",  protocol_name);
2083   err = start_command (ctx, cld, cmdid, line);
2084   cld = NULL;     /* Now owned by start_command.  */
2085   sigdata = NULL; /* Ditto.  */
2086   if (err)
2087     goto leave;
2088
2089
2090  leave:
2091   if (err)
2092     {
2093       /* Fixme: Cancel stuff in the work_queue. */
2094       close_pipe (msgpipe);
2095       close_pipe (sigpipe);
2096       close_pipe (outpipe);
2097       gpgme_data_release (sigdata);
2098       xfree (cld);
2099       assuan_disconnect (ctx);
2100     }
2101   else
2102     engine_private_set_cancel (filter, ctx);
2103   return err;
2104 }
2105
2106
2107 \f
2108 /* Ask the server to fire up the key manager.  */
2109 int 
2110 op_assuan_start_keymanager (void *hwnd)
2111 {
2112   gpg_error_t err;
2113   assuan_context_t ctx;
2114   ULONG cmdid;
2115   pid_t pid;
2116
2117   err = connect_uiserver (&ctx, &pid, &cmdid, hwnd);
2118   if (!err)
2119     {
2120       err = assuan_transact (ctx, "START_KEYMANAGER",
2121                              NULL, NULL, NULL, NULL, NULL, NULL);
2122       assuan_disconnect (ctx);
2123     }
2124   return err;
2125 }