Line data Source code
1 : /*
2 : editinteractor.cpp - Interface for edit interactors
3 : Copyright (C) 2007 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 "editinteractor.h"
24 : #include "callbacks.h"
25 : #include "error.h"
26 :
27 : #include <gpgme.h>
28 :
29 : #ifdef _WIN32
30 : # include <io.h>
31 : #include <windows.h>
32 : #else
33 : # include <unistd.h>
34 : #endif
35 :
36 : #include <cerrno>
37 : #include <cstring>
38 :
39 : #ifndef GPG_ERR_ALREADY_SIGNED
40 : # define GPG_ERR_ALREADY_SIGNED GPG_ERR_USER_1
41 : #endif
42 :
43 : using namespace GpgME;
44 :
45 : static const char *status_to_string(unsigned int status);
46 : static Error status_to_error(unsigned int status);
47 :
48 : class EditInteractor::Private
49 : {
50 : friend class ::GpgME::EditInteractor;
51 : friend class ::GpgME::CallbackHelper;
52 : EditInteractor *const q;
53 : public:
54 : explicit Private(EditInteractor *qq);
55 : ~Private();
56 :
57 : private:
58 : unsigned int state;
59 : Error error;
60 : std::FILE *debug;
61 : };
62 :
63 : class GpgME::CallbackHelper
64 : {
65 : private:
66 14 : static int writeAll(int fd, const void *buf, size_t count)
67 : {
68 14 : size_t toWrite = count;
69 42 : while (toWrite > 0) {
70 14 : const int n = gpgme_io_write(fd, buf, toWrite);
71 14 : if (n < 0) {
72 0 : return n;
73 : }
74 14 : toWrite -= n;
75 : }
76 14 : return count;
77 : }
78 :
79 : public:
80 28 : static int edit_interactor_callback_impl(void *opaque, gpgme_status_code_t status, const char *args, int fd)
81 : {
82 28 : EditInteractor::Private *ei = (EditInteractor::Private *)opaque;
83 :
84 28 : Error err = status_to_error(status);
85 :
86 28 : if (!err) {
87 :
88 : // advance to next state based on input:
89 28 : const unsigned int oldState = ei->state;
90 28 : ei->state = ei->q->nextState(status, args, err);
91 28 : if (ei->debug) {
92 : std::fprintf(ei->debug, "EditInteractor: %u -> nextState( %s, %s ) -> %u\n",
93 0 : oldState, status_to_string(status), args ? args : "<null>", ei->state);
94 : }
95 28 : if (err) {
96 0 : ei->state = oldState;
97 0 : goto error;
98 : }
99 :
100 35 : if (ei->state != oldState &&
101 : // if there was an error from before, we stop here (### this looks weird, can this happen at all?)
102 7 : ei->error.code() == GPG_ERR_NO_ERROR) {
103 :
104 : // successful state change -> call action
105 7 : if (const char *const result = ei->q->action(err)) {
106 7 : if (err) {
107 0 : goto error;
108 : }
109 7 : if (ei->debug) {
110 0 : std::fprintf(ei->debug, "EditInteractor: action result \"%s\"\n", result);
111 : }
112 : // if there's a result, write it:
113 7 : if (*result) {
114 7 : gpgme_err_set_errno(0);
115 7 : const ssize_t len = std::strlen(result);
116 7 : if (writeAll(fd, result, len) != len) {
117 0 : err = Error::fromSystemError();
118 0 : if (ei->debug) {
119 0 : std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asString());
120 : }
121 0 : goto error;
122 : }
123 : }
124 7 : gpgme_err_set_errno(0);
125 7 : if (writeAll(fd, "\n", 1) != 1) {
126 0 : err = Error::fromSystemError();
127 0 : if (ei->debug) {
128 0 : std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asString());
129 : }
130 0 : goto error;
131 : }
132 : } else {
133 0 : if (err) {
134 0 : goto error;
135 : }
136 0 : if (ei->debug) {
137 0 : std::fprintf(ei->debug, "EditInteractor: no action result\n");
138 : }
139 : }
140 : } else {
141 21 : if (ei->debug) {
142 0 : std::fprintf(ei->debug, "EditInteractor: no action executed\n");
143 : }
144 : }
145 : }
146 :
147 : error:
148 28 : if (err) {
149 0 : ei->error = err;
150 0 : ei->state = EditInteractor::ErrorState;
151 : }
152 :
153 28 : if (ei->debug) {
154 : std::fprintf(ei->debug, "EditInteractor: error now %u (%s)\n",
155 0 : ei->error.encodedError(), gpgme_strerror(ei->error.encodedError()));
156 : }
157 :
158 28 : return ei->error.encodedError();
159 : }
160 : };
161 :
162 28 : static gpgme_error_t edit_interactor_callback(void *opaque, gpgme_status_code_t status, const char *args, int fd)
163 : {
164 28 : return CallbackHelper::edit_interactor_callback_impl(opaque, status, args, fd);
165 : }
166 :
167 : const gpgme_edit_cb_t GpgME::edit_interactor_callback = ::edit_interactor_callback;
168 :
169 2 : EditInteractor::Private::Private(EditInteractor *qq)
170 : : q(qq),
171 : state(StartState),
172 : error(),
173 2 : debug(0)
174 : {
175 :
176 2 : }
177 :
178 2 : EditInteractor::Private::~Private() {}
179 :
180 2 : EditInteractor::EditInteractor()
181 2 : : d(new Private(this))
182 : {
183 :
184 2 : }
185 :
186 2 : EditInteractor::~EditInteractor()
187 : {
188 2 : delete d;
189 2 : }
190 :
191 35 : unsigned int EditInteractor::state() const
192 : {
193 35 : return d->state;
194 : }
195 :
196 0 : Error EditInteractor::lastError() const
197 : {
198 0 : return d->error;
199 : }
200 :
201 28 : bool EditInteractor::needsNoResponse(unsigned int status) const
202 : {
203 28 : switch (status) {
204 : case GPGME_STATUS_ALREADY_SIGNED:
205 : case GPGME_STATUS_ERROR:
206 : case GPGME_STATUS_GET_BOOL:
207 : case GPGME_STATUS_GET_LINE:
208 : case GPGME_STATUS_KEY_CREATED:
209 : case GPGME_STATUS_NEED_PASSPHRASE_SYM:
210 : case GPGME_STATUS_SC_OP_FAILURE:
211 7 : return false;
212 : default:
213 21 : return true;
214 : }
215 : }
216 :
217 : // static
218 28 : Error status_to_error(unsigned int status)
219 : {
220 28 : switch (status) {
221 : case GPGME_STATUS_MISSING_PASSPHRASE:
222 0 : return Error::fromCode(GPG_ERR_NO_PASSPHRASE);
223 : case GPGME_STATUS_ALREADY_SIGNED:
224 0 : return Error::fromCode(GPG_ERR_ALREADY_SIGNED);
225 : case GPGME_STATUS_SIGEXPIRED:
226 0 : return Error::fromCode(GPG_ERR_SIG_EXPIRED);
227 : }
228 28 : return Error();
229 : }
230 :
231 0 : void EditInteractor::setDebugChannel(std::FILE *debug)
232 : {
233 0 : d->debug = debug;
234 0 : }
235 :
236 : static const char *const status_strings[] = {
237 : "EOF",
238 : /* mkstatus processing starts here */
239 : "ENTER",
240 : "LEAVE",
241 : "ABORT",
242 :
243 : "GOODSIG",
244 : "BADSIG",
245 : "ERRSIG",
246 :
247 : "BADARMOR",
248 :
249 : "RSA_OR_IDEA",
250 : "KEYEXPIRED",
251 : "KEYREVOKED",
252 :
253 : "TRUST_UNDEFINED",
254 : "TRUST_NEVER",
255 : "TRUST_MARGINAL",
256 : "TRUST_FULLY",
257 : "TRUST_ULTIMATE",
258 :
259 : "SHM_INFO",
260 : "SHM_GET",
261 : "SHM_GET_BOOL",
262 : "SHM_GET_HIDDEN",
263 :
264 : "NEED_PASSPHRASE",
265 : "VALIDSIG",
266 : "SIG_ID",
267 : "ENC_TO",
268 : "NODATA",
269 : "BAD_PASSPHRASE",
270 : "NO_PUBKEY",
271 : "NO_SECKEY",
272 : "NEED_PASSPHRASE_SYM",
273 : "DECRYPTION_FAILED",
274 : "DECRYPTION_OKAY",
275 : "MISSING_PASSPHRASE",
276 : "GOOD_PASSPHRASE",
277 : "GOODMDC",
278 : "BADMDC",
279 : "ERRMDC",
280 : "IMPORTED",
281 : "IMPORT_OK",
282 : "IMPORT_PROBLEM",
283 : "IMPORT_RES",
284 : "FILE_START",
285 : "FILE_DONE",
286 : "FILE_ERROR",
287 :
288 : "BEGIN_DECRYPTION",
289 : "END_DECRYPTION",
290 : "BEGIN_ENCRYPTION",
291 : "END_ENCRYPTION",
292 :
293 : "DELETE_PROBLEM",
294 : "GET_BOOL",
295 : "GET_LINE",
296 : "GET_HIDDEN",
297 : "GOT_IT",
298 : "PROGRESS",
299 : "SIG_CREATED",
300 : "SESSION_KEY",
301 : "NOTATION_NAME",
302 : "NOTATION_DATA",
303 : "POLICY_URL",
304 : "BEGIN_STREAM",
305 : "END_STREAM",
306 : "KEY_CREATED",
307 : "USERID_HINT",
308 : "UNEXPECTED",
309 : "INV_RECP",
310 : "NO_RECP",
311 : "ALREADY_SIGNED",
312 : "SIGEXPIRED",
313 : "EXPSIG",
314 : "EXPKEYSIG",
315 : "TRUNCATED",
316 : "ERROR",
317 : "NEWSIG",
318 : "REVKEYSIG",
319 : "SIG_SUBPACKET",
320 : "NEED_PASSPHRASE_PIN",
321 : "SC_OP_FAILURE",
322 : "SC_OP_SUCCESS",
323 : "CARDCTRL",
324 : "BACKUP_KEY_CREATED",
325 : "PKA_TRUST_BAD",
326 : "PKA_TRUST_GOOD",
327 :
328 : "PLAINTEXT",
329 : };
330 : static const unsigned int num_status_strings = sizeof status_strings / sizeof * status_strings ;
331 :
332 0 : const char *status_to_string(unsigned int idx)
333 : {
334 0 : if (idx < num_status_strings) {
335 0 : return status_strings[idx];
336 : } else {
337 0 : return "(unknown)";
338 : }
339 : }
|