2004-04-22 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 #include <errno.h>
26
27 #include "gpgme.h"
28 #include "context.h"
29 #include "wait.h"
30 #include "ops.h"
31 #include "io.h"
32 #include "util.h"
33
34 \f
35 /* The private event loops are used for all blocking operations, and
36    for the key and trust item listing operations.  They are completely
37    separated from each other.  */
38
39 \f
40 /* Internal I/O callback functions.  */
41
42 /* The add_io_cb and remove_io_cb handlers are shared with the global
43    event loops.  */
44
45 void
46 _gpgme_wait_private_event_cb (void *data, gpgme_event_io_t type,
47                               void *type_data)
48 {
49   switch (type)
50     {
51     case GPGME_EVENT_START:
52       /* Nothing to do here, as the wait routine is called after the
53          initialization is finished.  */
54       break;
55
56     case GPGME_EVENT_DONE:
57       break;
58
59     case GPGME_EVENT_NEXT_KEY:
60       _gpgme_op_keylist_event_cb (data, type, type_data);
61       break;
62
63     case GPGME_EVENT_NEXT_TRUSTITEM:
64       _gpgme_op_trustlist_event_cb (data, type, type_data);
65       break;
66     }
67 }
68
69 \f
70 /* If COND is a null pointer, wait until the blocking operation in CTX
71    finished and return its error value.  Otherwise, wait until COND is
72    satisfied or the operation finished.  */
73 gpgme_error_t
74 _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond)
75 {
76   gpgme_error_t err = 0;
77   int hang = 1;
78
79   do
80     {
81       int nr = _gpgme_io_select (ctx->fdt.fds, ctx->fdt.size, 0);
82       unsigned int i;
83
84       if (nr < 0)
85         {
86           /* An error occured.  Close all fds in this context, and
87              signal it.  */
88           unsigned int idx;
89
90           err = gpg_error_from_errno (errno);
91           for (idx = 0; idx < ctx->fdt.size; idx++)
92             if (ctx->fdt.fds[idx].fd != -1)
93               _gpgme_io_close (ctx->fdt.fds[idx].fd);
94           _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
95
96           return err;
97         }
98       
99       for (i = 0; i < ctx->fdt.size && nr; i++)
100         {
101           if (ctx->fdt.fds[i].fd != -1 && ctx->fdt.fds[i].signaled)
102             {
103               struct wait_item_s *item;
104               
105               ctx->fdt.fds[i].signaled = 0;
106               assert (nr);
107               nr--;
108               
109               item = (struct wait_item_s *) ctx->fdt.fds[i].opaque;
110
111               err = item->handler (item->handler_value, ctx->fdt.fds[i].fd);
112               if (err)
113                 {
114                   /* An error occured.  Close all fds in this context,
115                      and signal it.  */
116                   unsigned int idx;
117                   
118                   for (idx = 0; idx < ctx->fdt.size; idx++)
119                     if (ctx->fdt.fds[idx].fd != -1)
120                       _gpgme_io_close (ctx->fdt.fds[idx].fd);
121                   _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
122                   return err;
123                 }
124             }
125         }
126
127       for (i = 0; i < ctx->fdt.size; i++)
128         if (ctx->fdt.fds[i].fd != -1)
129           break;
130       if (i == ctx->fdt.size)
131         {
132           _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
133           hang = 0;
134         }
135       if (cond && *cond)
136         hang = 0;
137     }
138   while (hang);
139
140   return 0;
141 }
142
143
144 /* Wait until the blocking operation in context CTX has finished and
145    return the error value.  */
146 gpgme_error_t
147 _gpgme_wait_one (gpgme_ctx_t ctx)
148 {
149   return _gpgme_wait_on_condition (ctx, NULL);
150 }