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