diff --git a/gpgme++/editinteractor.cpp b/gpgme++/editinteractor.cpp index 2da115614..0e4cfdbae 100644 --- a/gpgme++/editinteractor.cpp +++ b/gpgme++/editinteractor.cpp @@ -1,325 +1,326 @@ /* 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 #include "editinteractor.h" #include "callbacks.h" #include "error.h" #include #ifdef _WIN32 # include #include #else # include #endif #include #include 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 ) { #ifdef Q_OS_WIN DWORD n; if ( !WriteFile( (HANDLE)fd, buf, toWrite, &n, NULL ) ) return -1; #else const int n = write( fd, buf, toWrite ); #endif 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 : "", 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?) gpg_err_code( 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 ) { errno = 0; - if ( writeAll( fd, result, std::strlen( result ) ) != std::strlen( result ) ) { + const ssize_t len = std::strlen( result ); + if ( writeAll( fd, result, len ) != len ) { err = Error( gpg_error_from_syserror() ); if ( ei->debug ) std::fprintf( ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, strerror( errno ) ); goto error; } } errno = 0; if ( writeAll( fd, "\n", 1 ) != 1 ) { err = Error( gpg_error_from_syserror() ); if ( ei->debug ) std::fprintf( ei->debug, "EditInteractor: Could not write to fd %d (%s)\n", fd, strerror( errno ) ); 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(), gpg_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 ); } 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; d = 0; } 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: return true; default: return false; } } // static Error status_to_error( unsigned int status ) { switch ( status ) { case GPGME_STATUS_MISSING_PASSPHRASE: return Error( gpg_error( GPG_ERR_NO_PASSPHRASE ) ); case GPGME_STATUS_ALREADY_SIGNED: return Error( gpg_error( GPG_ERR_ALREADY_SIGNED ) ); case GPGME_STATUS_KEYEXPIRED: return Error( gpg_error( GPG_ERR_CERT_EXPIRED ) ); case GPGME_STATUS_SIGEXPIRED: return Error( gpg_error( GPG_ERR_SIG_EXPIRED ) ); } return Error(); } void EditInteractor::setDebugChannel( std::FILE * debug ) { d->debug = debug; } static const char * 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)"; }