diff options
| author | Andre Heinecke <[email protected]> | 2016-05-10 14:43:36 +0000 | 
|---|---|---|
| committer | Andre Heinecke <[email protected]> | 2016-05-10 14:43:36 +0000 | 
| commit | 34e5c5b33de3608bedc2826be27a06e6eec0ea44 (patch) | |
| tree | b04ce687c5dcb72d84af230e05335da0213bf6de /lang/cpp/src/editinteractor.cpp | |
| parent | Allow cc to detect missing cases in a switch. (diff) | |
| parent | Qt / Cpp: Fix make dist (diff) | |
| download | gpgme-34e5c5b33de3608bedc2826be27a06e6eec0ea44.tar.gz gpgme-34e5c5b33de3608bedc2826be27a06e6eec0ea44.zip | |
Merge branch 'gpgmepp'
Diffstat (limited to 'lang/cpp/src/editinteractor.cpp')
| -rw-r--r-- | lang/cpp/src/editinteractor.cpp | 344 | 
1 files changed, 344 insertions, 0 deletions
| diff --git a/lang/cpp/src/editinteractor.cpp b/lang/cpp/src/editinteractor.cpp new file mode 100644 index 00000000..c05ccd63 --- /dev/null +++ b/lang/cpp/src/editinteractor.cpp @@ -0,0 +1,344 @@ +/* +  editinteractor.cpp - Interface for edit interactors +  Copyright (C) 2007 Klarälvdalens Datakonsult AB + +  This file is part of GPGME++. + +  GPGME++ is free software; you can redistribute it and/or +  modify it under the terms of the GNU Library General Public +  License as published by the Free Software Foundation; either +  version 2 of the License, or (at your option) any later version. + +  GPGME++ is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +  GNU Library General Public License for more details. + +  You should have received a copy of the GNU Library General Public License +  along with GPGME++; see the file COPYING.LIB.  If not, write to the +  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +  Boston, MA 02110-1301, USA. +*/ + +#include "editinteractor.h" +#include "callbacks.h" +#include "error.h" + +#include <gpgme.h> + +#ifdef _WIN32 +# include <io.h> +#include <windows.h> +#else +# include <unistd.h> +#endif + +#include <cerrno> +#include <cstring> + +#ifndef GPG_ERR_ALREADY_SIGNED +# define GPG_ERR_ALREADY_SIGNED GPG_ERR_USER_1 +#endif + +using namespace GpgME; + +static const char *status_to_string(unsigned int status); +static Error status_to_error(unsigned int status); + +class EditInteractor::Private +{ +    friend class ::GpgME::EditInteractor; +    friend class ::GpgME::CallbackHelper; +    EditInteractor *const q; +public: +    explicit Private(EditInteractor *qq); +    ~Private(); + +private: +    unsigned int state; +    Error error; +    std::FILE *debug; +}; + +class GpgME::CallbackHelper +{ +private: +    static int writeAll(int fd, const void *buf, size_t count) +    { +        size_t toWrite = count; +        while (toWrite > 0) { +            const int n = gpgme_io_write(fd, buf, toWrite); +            if (n < 0) { +                return n; +            } +            toWrite -= n; +        } +        return count; +    } + +public: +    static int edit_interactor_callback_impl(void *opaque, gpgme_status_code_t status, const char *args, int fd) +    { +        EditInteractor::Private *ei = (EditInteractor::Private *)opaque; + +        Error err = status_to_error(status); + +        if (!err) { + +            // advance to next state based on input: +            const unsigned int oldState = ei->state; +            ei->state = ei->q->nextState(status, args, err); +            if (ei->debug) { +                std::fprintf(ei->debug, "EditInteractor: %u -> nextState( %s, %s ) -> %u\n", +                             oldState, status_to_string(status), args ? args : "<null>", ei->state); +            } +            if (err) { +                ei->state = oldState; +                goto error; +            } + +            if (ei->state != oldState && +                    // if there was an error from before, we stop here (### this looks weird, can this happen at all?) +                    ei->error.code() == GPG_ERR_NO_ERROR) { + +                // successful state change -> call action +                if (const char *const result = ei->q->action(err)) { +                    if (err) { +                        goto error; +                    } +                    if (ei->debug) { +                        std::fprintf(ei->debug, "EditInteractor: action result \"%s\"\n", result); +                    } +                    // if there's a result, write it: +                    if (*result) { +                        gpgme_err_set_errno(0); +                        const ssize_t len = std::strlen(result); +                        if (writeAll(fd, result, len) != len) { +                            err = Error::fromSystemError(); +                            if (ei->debug) { +                                std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asString()); +                            } +                            goto error; +                        } +                    } +                    gpgme_err_set_errno(0); +                    if (writeAll(fd, "\n", 1) != 1) { +                        err = Error::fromSystemError(); +                        if (ei->debug) { +                            std::fprintf(ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, err.asString()); +                        } +                        goto error; +                    } +                } else { +                    if (err) { +                        goto error; +                    } +                    if (ei->debug) { +                        std::fprintf(ei->debug, "EditInteractor: no action result\n"); +                    } +                } +            } else { +                if (ei->debug) { +                    std::fprintf(ei->debug, "EditInteractor: no action executed\n"); +                } +            } +        } + +    error: +        if (err) { +            ei->error = err; +            ei->state = EditInteractor::ErrorState; +        } + +        if (ei->debug) { +            std::fprintf(ei->debug, "EditInteractor: error now %u (%s)\n", +                         ei->error.encodedError(), gpgme_strerror(ei->error.encodedError())); +        } + +        return ei->error.encodedError(); +    } +}; + +static gpgme_error_t edit_interactor_callback(void *opaque, gpgme_status_code_t status, const char *args, int fd) +{ +    return CallbackHelper::edit_interactor_callback_impl(opaque, status, args, fd); +} + +const gpgme_edit_cb_t GpgME::edit_interactor_callback = ::edit_interactor_callback; + +EditInteractor::Private::Private(EditInteractor *qq) +    : q(qq), +      state(StartState), +      error(), +      debug(0) +{ + +} + +EditInteractor::Private::~Private() {} + +EditInteractor::EditInteractor() +    : d(new Private(this)) +{ + +} + +EditInteractor::~EditInteractor() +{ +    delete d; +} + +unsigned int EditInteractor::state() const +{ +    return d->state; +} + +Error EditInteractor::lastError() const +{ +    return d->error; +} + +bool EditInteractor::needsNoResponse(unsigned int status) const +{ +    switch (status) { +    case GPGME_STATUS_EOF: +    case GPGME_STATUS_GOT_IT: +    case GPGME_STATUS_NEED_PASSPHRASE: +    case GPGME_STATUS_NEED_PASSPHRASE_SYM: +    case GPGME_STATUS_GOOD_PASSPHRASE: +    case GPGME_STATUS_BAD_PASSPHRASE: +    case GPGME_STATUS_USERID_HINT: +    case GPGME_STATUS_SIGEXPIRED: +    case GPGME_STATUS_KEYEXPIRED: +    case GPGME_STATUS_PINENTRY_LAUNCHED: +        return true; +    default: +        return false; +    } +} + +// static +Error status_to_error(unsigned int status) +{ +    switch (status) { +    case GPGME_STATUS_MISSING_PASSPHRASE: +        return Error::fromCode(GPG_ERR_NO_PASSPHRASE); +    case GPGME_STATUS_ALREADY_SIGNED: +        return Error::fromCode(GPG_ERR_ALREADY_SIGNED); +    case GPGME_STATUS_KEYEXPIRED: +        return Error::fromCode(GPG_ERR_CERT_EXPIRED); +    case GPGME_STATUS_SIGEXPIRED: +        return Error::fromCode(GPG_ERR_SIG_EXPIRED); +    } +    return Error(); +} + +void EditInteractor::setDebugChannel(std::FILE *debug) +{ +    d->debug = debug; +} + +static const char *const status_strings[] = { +    "EOF", +    /* mkstatus processing starts here */ +    "ENTER", +    "LEAVE", +    "ABORT", + +    "GOODSIG", +    "BADSIG", +    "ERRSIG", + +    "BADARMOR", + +    "RSA_OR_IDEA", +    "KEYEXPIRED", +    "KEYREVOKED", + +    "TRUST_UNDEFINED", +    "TRUST_NEVER", +    "TRUST_MARGINAL", +    "TRUST_FULLY", +    "TRUST_ULTIMATE", + +    "SHM_INFO", +    "SHM_GET", +    "SHM_GET_BOOL", +    "SHM_GET_HIDDEN", + +    "NEED_PASSPHRASE", +    "VALIDSIG", +    "SIG_ID", +    "ENC_TO", +    "NODATA", +    "BAD_PASSPHRASE", +    "NO_PUBKEY", +    "NO_SECKEY", +    "NEED_PASSPHRASE_SYM", +    "DECRYPTION_FAILED", +    "DECRYPTION_OKAY", +    "MISSING_PASSPHRASE", +    "GOOD_PASSPHRASE", +    "GOODMDC", +    "BADMDC", +    "ERRMDC", +    "IMPORTED", +    "IMPORT_OK", +    "IMPORT_PROBLEM", +    "IMPORT_RES", +    "FILE_START", +    "FILE_DONE", +    "FILE_ERROR", + +    "BEGIN_DECRYPTION", +    "END_DECRYPTION", +    "BEGIN_ENCRYPTION", +    "END_ENCRYPTION", + +    "DELETE_PROBLEM", +    "GET_BOOL", +    "GET_LINE", +    "GET_HIDDEN", +    "GOT_IT", +    "PROGRESS", +    "SIG_CREATED", +    "SESSION_KEY", +    "NOTATION_NAME", +    "NOTATION_DATA", +    "POLICY_URL", +    "BEGIN_STREAM", +    "END_STREAM", +    "KEY_CREATED", +    "USERID_HINT", +    "UNEXPECTED", +    "INV_RECP", +    "NO_RECP", +    "ALREADY_SIGNED", +    "SIGEXPIRED", +    "EXPSIG", +    "EXPKEYSIG", +    "TRUNCATED", +    "ERROR", +    "NEWSIG", +    "REVKEYSIG", +    "SIG_SUBPACKET", +    "NEED_PASSPHRASE_PIN", +    "SC_OP_FAILURE", +    "SC_OP_SUCCESS", +    "CARDCTRL", +    "BACKUP_KEY_CREATED", +    "PKA_TRUST_BAD", +    "PKA_TRUST_GOOD", + +    "PLAINTEXT", +}; +static const unsigned int num_status_strings = sizeof status_strings / sizeof * status_strings ; + +const char *status_to_string(unsigned int idx) +{ +    if (idx < num_status_strings) { +        return status_strings[idx]; +    } else { +        return "(unknown)"; +    } +} | 
