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#include <gpgme++/config-gpgme++.h>
24
25#include <gpgme++/eventloopinteractor.h>
26
27#include <gpgme++/context.h>
28#include "context_p.h"
29#include <gpgme++/key.h>
30#include <gpgme++/trustitem.h>
31
32#include <gpgme.h>
33
34#include <vector>
35using std::vector;
36#ifndef NDEBUG
37# include <iostream>
38#endif
39#include <cassert>
40
41namespace GpgME {
42
43 //
44 // EventLoopInteractor::Private Declaration
45 //
46
47 class EventLoopInteractor::Private {
48 public:
49 struct OneFD {
50 OneFD( int aFd, int aDir, gpgme_io_cb_t aFnc,
51 void * aFncData, void * aExternalTag )
52 : fd( aFd ), dir( aDir ), fnc( aFnc ),
53 fncData( aFncData ), externalTag( aExternalTag ) {}
54 int fd;
55 int dir;
56 gpgme_io_cb_t fnc;
57 void * fncData;
58 void * externalTag;
59 };
60
61 vector<OneFD*> mCallbacks;
62
63 static void removeIOCb( void * tag );
64 static gpgme_error_t registerIOCb( void * data, int fd, int dir,
65 gpgme_io_cb_t fnc, void * fnc_data,
66 void ** r_tag );
67 static void eventIOCb( void *, gpgme_event_io_t type, void * type_data );
68
69 static gpgme_io_cbs iocbs;
70 };
71
72 gpgme_io_cbs EventLoopInteractor::Private::iocbs = {
73 &EventLoopInteractor::Private::registerIOCb,
74 0,
75 &EventLoopInteractor::Private::removeIOCb,
76 &EventLoopInteractor::Private::eventIOCb,
77 0
78 };
79
80
81 //
82 // EventLoopInteractor::Private IO Callback Implementations
83 //
84
85 gpgme_error_t EventLoopInteractor::Private::registerIOCb( void *, int fd, int dir,
86 gpgme_io_cb_t fnc, void * fnc_data,
87 void ** r_tag )
88 {
89 assert( instance() ); assert( instance()->d );
90 bool ok = false;
91 void * etag = instance()->registerWatcher( fd, dir ? Read : Write, ok );
92 if ( !ok ) {
93 return gpgme_error( GPG_ERR_GENERAL );
94 }
95 instance()->d->mCallbacks.push_back( new OneFD( fd, dir, fnc, fnc_data, etag ) );
96 if ( r_tag ) {
97 *r_tag = instance()->d->mCallbacks.back();
98 }
99 return GPG_ERR_NO_ERROR;
100 }
101
102 void EventLoopInteractor::Private::removeIOCb( void * tag ) {
103
104 if ( !instance() || !instance()->d ) {
105 return;
106 }
107 for ( vector<OneFD*>::iterator it = instance()->d->mCallbacks.begin();
108 it != instance()->d->mCallbacks.end() ; ++it ) {
109 if ( *it == tag ) {
110 instance()->unregisterWatcher( ( *it )->externalTag );
111 delete *it; *it = 0;
112 instance()->d->mCallbacks.erase( it );
113 return;
114 }
115 }
116 }
117
118 void EventLoopInteractor::Private::eventIOCb( void * data, gpgme_event_io_t type, void * type_data ) {
119 assert( instance() );
120 Context * ctx = static_cast<Context*>( data );
121 switch( type ) {
122 case GPGME_EVENT_START:
123 {
124 instance()->operationStartEvent( ctx );
125 // TODO: what's in type_data?
126 }
127 break;
128 case GPGME_EVENT_DONE:
129 {
130 gpgme_error_t e = *static_cast<gpgme_error_t*>( type_data );
131 if ( ctx && ctx->impl() ) {
132 ctx->impl()->lasterr = e;
133 }
134 instance()->operationDoneEvent( ctx, Error( e ) );
135 }
136 break;
137 case GPGME_EVENT_NEXT_KEY:
138 {
139 gpgme_key_t key = static_cast<gpgme_key_t>( type_data );
140 instance()->nextKeyEvent( ctx, Key( key, false ) );
141 }
142 break;
143 case GPGME_EVENT_NEXT_TRUSTITEM:
144 {
145 gpgme_trust_item_t item = static_cast<gpgme_trust_item_t>( type_data );
146 instance()->nextTrustItemEvent( ctx, TrustItem( item ) );
147 gpgme_trust_item_unref( item );
148 }
149 break;
150 default: // warn
151 ;
152 }
153 }
154
155 //
156 // EventLoopInteractor Implementation
157 //
158
159 EventLoopInteractor * EventLoopInteractor::mSelf = 0;
160
161 EventLoopInteractor::EventLoopInteractor() : d( new Private ) {
162 assert( !mSelf );
163 mSelf = this;
164 }
165
166 EventLoopInteractor::~EventLoopInteractor() {
167 // warn if there are still callbacks registered
168 mSelf = 0;
169 delete d;
170 }
171
172 void EventLoopInteractor::manage( Context * context ) {
173 if ( !context || context->managedByEventLoopInteractor() ) {
174 return;
175 }
176 gpgme_io_cbs * iocbs = new gpgme_io_cbs( Private::iocbs );
177 iocbs->event_priv = context;
178 context->installIOCallbacks( iocbs );
179 }
180
181 void EventLoopInteractor::unmanage( Context * context ) {
182 if ( context ) {
183 context->uninstallIOCallbacks();
184 }
185 }
186
187 void EventLoopInteractor::actOn( int fd, Direction dir ) {
188 for ( vector<Private::OneFD*>::const_iterator it = d->mCallbacks.begin();
189 it != d->mCallbacks.end() ; ++it ) {
190 if ( ( *it )->fd == fd && ( ( *it )->dir ? Read : Write ) == dir ) {
191 ( *( ( *it )->fnc ) )( ( *it )->fncData, fd );
192 break;
193 }
194 }
195 }
196
197} // namespace GpgME
198