4b4dd80605da8056a20880f254f4845c1315d6f3
[gpgme.git] / lang / cpp / src / callbacks.cpp
1 /*
2   callbacks.cpp - callback targets for internal use:
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 "callbacks.h"
24 #include "util.h"
25
26 #include <interfaces/progressprovider.h>
27 #include <interfaces/passphraseprovider.h>
28 #include <interfaces/dataprovider.h>
29 #include <error.h>
30
31 #include <gpgme.h>
32 #include <gpg-error.h>
33
34 #include <cassert>
35 #include <cerrno>
36 #include <cstring>
37 #include <unistd.h>
38 #include <stdlib.h>
39
40 static inline gpgme_error_t make_err_from_syserror()
41 {
42     return gpgme_error_from_syserror();
43 }
44
45 using GpgME::ProgressProvider;
46 using GpgME::PassphraseProvider;
47 using GpgME::DataProvider;
48
49 void progress_callback(void *opaque, const char *what,
50                        int type, int current, int total)
51 {
52     ProgressProvider *provider = static_cast<ProgressProvider *>(opaque);
53     if (provider) {
54         provider->showProgress(what, type, current, total);
55     }
56 }
57
58 /* To avoid that a compiler optimizes certain memset calls away, these
59    macros may be used instead. */
60 #define wipememory2(_ptr,_set,_len) do { \
61         volatile char *_vptr=(volatile char *)(_ptr); \
62         size_t _vlen=(_len); \
63         while(_vlen) { *_vptr=(_set); _vptr++; _vlen--; } \
64     } while(0)
65 #define wipememory(_ptr,_len) wipememory2(_ptr,0,_len)
66
67 gpgme_error_t passphrase_callback(void *opaque, const char *uid_hint, const char *desc,
68                                   int prev_was_bad, int fd)
69 {
70     PassphraseProvider *provider = static_cast<PassphraseProvider *>(opaque);
71     bool canceled = false;
72     gpgme_error_t err = GPG_ERR_NO_ERROR;
73     char *passphrase = provider ? provider->getPassphrase(uid_hint, desc, prev_was_bad, canceled) : 0 ;
74     if (canceled) {
75         err = make_error(GPG_ERR_CANCELED);
76     } else {
77         if (passphrase && *passphrase) {
78             size_t passphrase_length = std::strlen(passphrase);
79             size_t written = 0;
80             do {
81                 ssize_t now_written = gpgme_io_write(fd, passphrase + written, passphrase_length - written);
82                 if (now_written < 0) {
83                     err = make_err_from_syserror();
84                     break;
85                 }
86                 written += now_written;
87             } while (written < passphrase_length);
88         }
89     }
90
91     if (passphrase && *passphrase) {
92         wipememory(passphrase, std::strlen(passphrase));
93     }
94     free(passphrase);
95     gpgme_io_write(fd, "\n", 1);
96     return err;
97 }
98
99 static gpgme_ssize_t
100 data_read_callback(void *opaque, void *buf, size_t buflen)
101 {
102     DataProvider *provider = static_cast<DataProvider *>(opaque);
103     if (!provider) {
104         gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
105         return -1;
106     }
107     return (gpgme_ssize_t)provider->read(buf, buflen);
108 }
109
110 static gpgme_ssize_t
111 data_write_callback(void *opaque, const void *buf, size_t buflen)
112 {
113     DataProvider *provider = static_cast<DataProvider *>(opaque);
114     if (!provider) {
115         gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
116         return -1;
117     }
118     return (gpgme_ssize_t)provider->write(buf, buflen);
119 }
120
121 static gpgme_off_t
122 data_seek_callback(void *opaque, gpgme_off_t offset, int whence)
123 {
124     DataProvider *provider = static_cast<DataProvider *>(opaque);
125     if (!provider) {
126         gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
127         return -1;
128     }
129     if (whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END) {
130         gpgme_err_set_errno(gpgme_err_code_to_errno(GPG_ERR_EINVAL));
131         return -1;
132     }
133     return provider->seek((off_t)offset, whence);
134 }
135
136 static void data_release_callback(void *opaque)
137 {
138     DataProvider *provider = static_cast<DataProvider *>(opaque);
139     if (provider) {
140         provider->release();
141     }
142 }
143
144 const gpgme_data_cbs GpgME::data_provider_callbacks = {
145     &data_read_callback,
146     &data_write_callback,
147     &data_seek_callback,
148     &data_release_callback
149 };