9d7681d09d33201a6204cf4a42e1c7c72cb0f023
[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, gpgme_event_io_t type,
46                               void *type_data)
47 {
48   switch (type)
49     {
50     case GPGME_EVENT_START:
51       /* Nothing to do here, as the wait routine is called after the
52          initialization is finished.  */
53       break;
54
55     case GPGME_EVENT_DONE:
56       break;
57
58     case GPGME_EVENT_NEXT_KEY:
59       _gpgme_op_keylist_event_cb (data, type, type_data);
60       break;
61
62     case GPGME_EVENT_NEXT_TRUSTITEM:
63       _gpgme_op_trustlist_event_cb (data, type, type_data);
64       break;
65     }
66 }
67
68 \f
69 /* If COND is a null pointer, wait until the blocking operation in CTX
70    finished and return its error value.  Otherwise, wait until COND is
71    satisfied or the operation finished.  */
72 gpgme_error_t
73 _gpgme_wait_on_condition (gpgme_ctx_t ctx, volatile int *cond)
74 {
75   gpgme_error_t err = 0;
76   int hang = 1;
77
78   do
79     {
80       int nr = _gpgme_io_select (ctx->fdt.fds, ctx->fdt.size, 0);
81       int i;
82
83       if (nr < 0)
84         {
85           /* An error occured.  Close all fds in this context, and
86              signal it.  */
87           int idx;
88
89           err = GPGME_File_Error;
90           for (idx = 0; idx < ctx->fdt.size; idx++)
91             if (ctx->fdt.fds[idx].fd != -1)
92               _gpgme_io_close (ctx->fdt.fds[idx].fd);
93           _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
94
95           return err;
96         }
97       
98       for (i = 0; i < ctx->fdt.size && nr; i++)
99         {
100           if (ctx->fdt.fds[i].fd != -1 && ctx->fdt.fds[i].signaled)
101             {
102               struct wait_item_s *item;
103               
104               ctx->fdt.fds[i].signaled = 0;
105               assert (nr);
106               nr--;
107               
108               item = (struct wait_item_s *) ctx->fdt.fds[i].opaque;
109
110               err = item->handler (item->handler_value, ctx->fdt.fds[i].fd);
111               if (err)
112                 {
113                   /* An error occured.  Close all fds in this context,
114                      and signal it.  */
115                   int idx;
116                   
117                   for (idx = 0; idx < ctx->fdt.size; idx++)
118                     if (ctx->fdt.fds[idx].fd != -1)
119                       _gpgme_io_close (ctx->fdt.fds[idx].fd);
120                   _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
121                   return err;
122                 }
123             }
124         }
125
126       for (i = 0; i < ctx->fdt.size; i++)
127         if (ctx->fdt.fds[i].fd != -1)
128           break;
129       if (i == ctx->fdt.size)
130         {
131           _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_DONE, &err);
132           hang = 0;
133         }
134       if (cond && *cond)
135         hang = 0;
136     }
137   while (hang);
138
139   return 0;
140 }
141
142
143 /* Wait until the blocking operation in context CTX has finished and
144    return the error value.  */
145 gpgme_error_t
146 _gpgme_wait_one (gpgme_ctx_t ctx)
147 {
148   return _gpgme_wait_on_condition (ctx, NULL);
149 }