2003-04-28 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / wait-private.c
1 /* wait-private.c 
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 g10 Code GmbH
4  
5    This file is part of GPGME.
6  
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11  
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <assert.h>
25
26 #include "gpgme.h"
27 #include "context.h"
28 #include "wait.h"
29 #include "ops.h"
30 #include "io.h"
31 #include "util.h"
32
33 \f
34 /* The private event loops are used for all blocking operations, and
35    for the key and trust item listing operations.  They are completely
36    separated from each other.  */
37
38 \f
39 /* Internal I/O callback functions.  */
40
41 /* The add_io_cb and remove_io_cb handlers are shared with the global
42    event loops.  */
43
44 void
45 _gpgme_wait_private_event_cb (void *data, GpgmeEventIO type, void *type_data)
46 {
47   switch (type)
48     {
49     case GPGME_EVENT_START:
50       /* Nothing to do here, as the wait routine is called after the
51          initialization is finished.  */
52       break;
53
54     case GPGME_EVENT_DONE:
55       break;
56
57     case GPGME_EVENT_NEXT_KEY:
58       _gpgme_op_keylist_event_cb (data, type, type_data);
59       break;
60
61     case GPGME_EVENT_NEXT_TRUSTITEM:
62       _gpgme_op_trustlist_event_cb (data, type, type_data);
63       break;
64     }
65 }
66
67 \f
68 /* If COND is a null pointer, wait until the blocking operation in CTX
69    finished and return its error value.  Otherwise, wait until COND is
70    satisfied or the operation finished.  */
71 GpgmeError
72 _gpgme_wait_on_condition (GpgmeCtx ctx, volatile int *cond)
73 {
74   GpgmeError err = 0;
75   int hang = 1;
76
77   do
78     {
79       int nr = _gpgme_io_select (ctx->fdt.fds, ctx->fdt.size, 0);
80       int i;
81
82       if (nr < 0)
83         {
84           /* An error occured.  Close all fds in this context, and
85              signal it.  */
86           int idx;
87
88           err = GPGME_File_Error;
89           for (idx = 0; idx < ctx->fdt.size; idx++)
90             if (ctx->fdt.fds[idx].fd != -1)
91               _gpgme_io_close (ctx->fdt.fds[idx].fd);
92           _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
93
94           return err;
95         }
96       
97       for (i = 0; i < ctx->fdt.size && nr; i++)
98         {
99           if (ctx->fdt.fds[i].fd != -1 && ctx->fdt.fds[i].signaled)
100             {
101               struct wait_item_s *item;
102               
103               ctx->fdt.fds[i].signaled = 0;
104               assert (nr);
105               nr--;
106               
107               item = (struct wait_item_s *) ctx->fdt.fds[i].opaque;
108
109               err = item->handler (item->handler_value, ctx->fdt.fds[i].fd);
110               if (err)
111                 {
112                   /* An error occured.  Close all fds in this context,
113                      and signal it.  */
114                   int idx;
115                   
116                   for (idx = 0; idx < ctx->fdt.size; idx++)
117                     if (ctx->fdt.fds[idx].fd != -1)
118                       _gpgme_io_close (ctx->fdt.fds[idx].fd);
119                   _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
120                   return err;
121                 }
122             }
123         }
124
125       for (i = 0; i < ctx->fdt.size; i++)
126         if (ctx->fdt.fds[i].fd != -1)
127           break;
128       if (i == ctx->fdt.size)
129         {
130           _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
131           hang = 0;
132         }
133       if (cond && *cond)
134         hang = 0;
135     }
136   while (hang);
137
138   return 0;
139 }
140
141
142 /* Wait until the blocking operation in context CTX has finished and
143    return the error value.  */
144 GpgmeError
145 _gpgme_wait_one (GpgmeCtx ctx)
146 {
147   return _gpgme_wait_on_condition (ctx, NULL);
148 }