cpp, qt: Include config.h
[gpgme.git] / lang / cpp / src / eventloopinteractor.cpp
1 /*
2   eventloopinteractor.cpp
3   Copyright (C) 2003,2004 Klarälvdalens Datakonsult AB
4
5   This file is part of GPGME++.
6
7   GPGME++ is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Library General Public
9   License as published by the Free Software Foundation; either
10   version 2 of the License, or (at your option) any later version.
11
12   GPGME++ is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU Library General Public License for more details.
16
17   You should have received a copy of the GNU Library General Public License
18   along with GPGME++; see the file COPYING.LIB.  If not, write to the
19   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20   Boston, MA 02110-1301, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24  #include "config.h"
25 #endif
26
27 #include <eventloopinteractor.h>
28
29 #include <context.h>
30 #include "context_p.h"
31 #include <key.h>
32 #include <trustitem.h>
33
34 #include <gpgme.h>
35
36 #include <vector>
37 using std::vector;
38 #ifndef NDEBUG
39 # include <iostream>
40 #endif
41 #include <cassert>
42
43 namespace GpgME
44 {
45
46 //
47 // EventLoopInteractor::Private Declaration
48 //
49
50 class EventLoopInteractor::Private
51 {
52 public:
53     struct OneFD {
54         OneFD(int aFd, int aDir, gpgme_io_cb_t aFnc,
55               void *aFncData, void *aExternalTag)
56             : fd(aFd), dir(aDir), fnc(aFnc),
57               fncData(aFncData), externalTag(aExternalTag) {}
58         int fd;
59         int dir;
60         gpgme_io_cb_t fnc;
61         void *fncData;
62         void *externalTag;
63     };
64
65     vector<OneFD *> mCallbacks;
66
67     static void removeIOCb(void *tag);
68     static gpgme_error_t registerIOCb(void *data, int fd, int dir,
69                                       gpgme_io_cb_t fnc, void *fnc_data,
70                                       void **r_tag);
71     static void eventIOCb(void *, gpgme_event_io_t type, void *type_data);
72
73     static const gpgme_io_cbs iocbs;
74 };
75
76 const gpgme_io_cbs EventLoopInteractor::Private::iocbs = {
77     &EventLoopInteractor::Private::registerIOCb,
78     0,
79     &EventLoopInteractor::Private::removeIOCb,
80     &EventLoopInteractor::Private::eventIOCb,
81     0
82 };
83
84 //
85 // EventLoopInteractor::Private IO Callback Implementations
86 //
87
88 gpgme_error_t EventLoopInteractor::Private::registerIOCb(void *, int fd, int dir,
89         gpgme_io_cb_t fnc, void *fnc_data,
90         void **r_tag)
91 {
92     assert(instance()); assert(instance()->d);
93     bool ok = false;
94     void *etag = instance()->registerWatcher(fd, dir ? Read : Write, ok);
95     if (!ok) {
96         return gpgme_error(GPG_ERR_GENERAL);
97     }
98     instance()->d->mCallbacks.push_back(new OneFD(fd, dir, fnc, fnc_data, etag));
99     if (r_tag) {
100         *r_tag = instance()->d->mCallbacks.back();
101     }
102     return GPG_ERR_NO_ERROR;
103 }
104
105 void EventLoopInteractor::Private::removeIOCb(void *tag)
106 {
107
108     if (!instance() || !instance()->d) {
109         return;
110     }
111     for (vector<OneFD *>::iterator it = instance()->d->mCallbacks.begin();
112             it != instance()->d->mCallbacks.end() ; ++it) {
113         if (*it == tag) {
114             instance()->unregisterWatcher((*it)->externalTag);
115             delete *it; *it = 0;
116             instance()->d->mCallbacks.erase(it);
117             return;
118         }
119     }
120 }
121
122 void EventLoopInteractor::Private::eventIOCb(void *data, gpgme_event_io_t type, void *type_data)
123 {
124     assert(instance());
125     Context *ctx = static_cast<Context *>(data);
126     switch (type) {
127     case GPGME_EVENT_START: {
128         instance()->operationStartEvent(ctx);
129         // TODO: what's in type_data?
130     }
131     break;
132     case GPGME_EVENT_DONE: {
133         gpgme_error_t e = *static_cast<gpgme_error_t *>(type_data);
134         if (ctx && ctx->impl()) {
135             ctx->impl()->lasterr = e;
136         }
137         instance()->operationDoneEvent(ctx, Error(e));
138     }
139     break;
140     case GPGME_EVENT_NEXT_KEY: {
141         gpgme_key_t key = static_cast<gpgme_key_t>(type_data);
142         instance()->nextKeyEvent(ctx, Key(key, false));
143     }
144     break;
145     case GPGME_EVENT_NEXT_TRUSTITEM: {
146         gpgme_trust_item_t item = static_cast<gpgme_trust_item_t>(type_data);
147         instance()->nextTrustItemEvent(ctx, TrustItem(item));
148         gpgme_trust_item_unref(item);
149     }
150     break;
151     default: // warn
152         ;
153     }
154 }
155
156 //
157 // EventLoopInteractor Implementation
158 //
159
160 EventLoopInteractor *EventLoopInteractor::mSelf = 0;
161
162 EventLoopInteractor::EventLoopInteractor() : d(new Private)
163 {
164     assert(!mSelf);
165     mSelf = this;
166 }
167
168 EventLoopInteractor::~EventLoopInteractor()
169 {
170     // warn if there are still callbacks registered
171     mSelf = 0;
172     delete d;
173 }
174
175 void EventLoopInteractor::manage(Context *context)
176 {
177     if (!context || context->managedByEventLoopInteractor()) {
178         return;
179     }
180     gpgme_io_cbs *iocbs = new gpgme_io_cbs(Private::iocbs);
181     iocbs->event_priv = context;
182     context->installIOCallbacks(iocbs);
183 }
184
185 void EventLoopInteractor::unmanage(Context *context)
186 {
187     if (context) {
188         context->uninstallIOCallbacks();
189     }
190 }
191
192 void EventLoopInteractor::actOn(int fd, Direction dir)
193 {
194     for (vector<Private::OneFD *>::const_iterator it = d->mCallbacks.begin();
195             it != d->mCallbacks.end() ; ++it) {
196         if ((*it)->fd == fd && ((*it)->dir ? Read : Write) == dir) {
197             (*((*it)->fnc))((*it)->fncData, fd);
198             break;
199         }
200     }
201 }
202
203 } // namespace GpgME