diff --git a/src/decrypt.c b/src/decrypt.c index 4fd92c61..4db68a10 100644 --- a/src/decrypt.c +++ b/src/decrypt.c @@ -38,6 +38,9 @@ typedef struct { struct _gpgme_op_decrypt_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + int okay; int failed; @@ -192,6 +195,10 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, switch (code) { + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* FIXME: These error values should probably be attributed to the underlying crypto engine (as error source). */ @@ -199,6 +206,8 @@ _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, return gpg_error (GPG_ERR_DECRYPT_FAILED); else if (!opd->okay) return gpg_error (GPG_ERR_NO_DATA); + else if (opd->failure_code) + return opd->failure_code; break; case GPGME_STATUS_DECRYPTION_INFO: diff --git a/src/encrypt.c b/src/encrypt.c index 792c25c5..9f5134de 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -36,6 +36,9 @@ typedef struct { struct _gpgme_op_encrypt_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + /* A pointer to the next pointer of the last invalid recipient in the list. This makes appending new invalid recipients painless while preserving the order. */ @@ -114,9 +117,15 @@ _gpgme_encrypt_status_handler (void *priv, gpgme_status_code_t code, switch (code) { + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: if (opd->result.invalid_recipients) return gpg_error (GPG_ERR_UNUSABLE_PUBKEY); + if (opd->failure_code) + return opd->failure_code; break; case GPGME_STATUS_INV_RECP: diff --git a/src/genkey.c b/src/genkey.c index 18765dde..3afd3b41 100644 --- a/src/genkey.c +++ b/src/genkey.c @@ -37,6 +37,9 @@ typedef struct { struct _gpgme_op_genkey_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + /* The key parameters passed to the crypto engine. */ gpgme_data_t key_parameter; } *op_data_t; @@ -118,10 +121,16 @@ genkey_status_handler (void *priv, gpgme_status_code_t code, char *args) } break; + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* FIXME: Should return some more useful error value. */ if (!opd->result.primary && !opd->result.sub) return gpg_error (GPG_ERR_GENERAL); + else if (opd->failure_code) + return opd->failure_code; break; case GPGME_STATUS_INQUIRE_MAXLEN: diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 76055708..432d18a1 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -548,7 +548,8 @@ typedef enum GPGME_STATUS_ATTRIBUTE = 89, GPGME_STATUS_BEGIN_SIGNING = 90, GPGME_STATUS_KEY_NOT_CREATED = 91, - GPGME_STATUS_INQUIRE_MAXLEN = 92 + GPGME_STATUS_INQUIRE_MAXLEN = 92, + GPGME_STATUS_FAILURE = 93 } gpgme_status_code_t; diff --git a/src/op-support.c b/src/op-support.c index 2bcb3a35..02940efd 100644 --- a/src/op-support.c +++ b/src/op-support.c @@ -337,3 +337,27 @@ _gpgme_parse_plaintext (char *args, char **filenamep) } return 0; } + + +/* Parse a FAILURE status line and return the error code. ARGS is + modified to contain the location part. */ +gpgme_error_t +_gpgme_parse_failure (char *args) +{ + char *where, *which; + + where = strchr (args, ' '); + if (!where) + return trace_gpg_error (GPG_ERR_INV_ENGINE); + + *where = '\0'; + which = where + 1; + + where = strchr (which, ' '); + if (where) + *where = '\0'; + + where = args; + + return atoi (which); +} diff --git a/src/ops.h b/src/ops.h index 782265e4..3662d571 100644 --- a/src/ops.h +++ b/src/ops.h @@ -65,6 +65,10 @@ gpgme_error_t _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key); FILENAMEP. */ gpgme_error_t _gpgme_parse_plaintext (char *args, char **filenamep); +/* Parse a FAILURE status line and return the error code. ARGS is + modified to contain the location part. */ +gpgme_error_t _gpgme_parse_failure (char *args); + /* From verify.c. */ diff --git a/src/passphrase.c b/src/passphrase.c index 5d656b17..c88e57d2 100644 --- a/src/passphrase.c +++ b/src/passphrase.c @@ -128,6 +128,19 @@ _gpgme_passphrase_status_handler (void *priv, gpgme_status_code_t code, } break; + case GPGME_STATUS_FAILURE: + /* We abuse this status handler to forward FAILURE status codes + to the caller. This should better be done in a generic + handler, but for now this is sufficient. */ + if (ctx->status_cb) + { + err = ctx->status_cb (ctx->status_cb_value, "FAILURE", args); + if (err) + return err; + } + break; + + default: /* Ignore all other codes. */ break; diff --git a/src/passwd.c b/src/passwd.c index e832026d..ff30df01 100644 --- a/src/passwd.c +++ b/src/passwd.c @@ -30,6 +30,9 @@ typedef struct { + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + int success_seen; int error_seen; } *op_data_t; @@ -92,6 +95,10 @@ passwd_status_handler (void *priv, gpgme_status_code_t code, char *args) opd->success_seen = 1; break; + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* In case the OpenPGP engine does not properly implement the passwd command we won't get a success status back and thus we @@ -102,6 +109,8 @@ passwd_status_handler (void *priv, gpgme_status_code_t code, char *args) if (ctx->protocol == GPGME_PROTOCOL_OpenPGP && !opd->error_seen && !opd->success_seen) err = gpg_error (GPG_ERR_NOT_SUPPORTED); + else if (opd->failure_code) + err = opd->failure_code; break; default: diff --git a/src/sign.c b/src/sign.c index 9e22fdb8..6c9fc03a 100644 --- a/src/sign.c +++ b/src/sign.c @@ -39,6 +39,9 @@ typedef struct { struct _gpgme_op_sign_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + /* A pointer to the next pointer of the last invalid signer in the list. This makes appending new invalid signers painless while preserving the order. */ @@ -327,6 +330,10 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args) opd->last_signer_p = &(*opd->last_signer_p)->next; break; + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: /* The UI server does not send information about the created signature. This is irrelevant for this protocol and thus we @@ -335,7 +342,7 @@ _gpgme_sign_status_handler (void *priv, gpgme_status_code_t code, char *args) err = gpg_error (GPG_ERR_UNUSABLE_SECKEY); else if (!opd->sig_created_seen && ctx->protocol != GPGME_PROTOCOL_UISERVER) - err = gpg_error (GPG_ERR_GENERAL); + err = opd->failure_code? opd->failure_code:gpg_error (GPG_ERR_GENERAL); break; case GPGME_STATUS_INQUIRE_MAXLEN: @@ -374,6 +381,7 @@ sign_init_result (gpgme_ctx_t ctx, int ignore_inv_recp) opd = hook; if (err) return err; + opd->failure_code = 0; opd->last_signer_p = &opd->result.invalid_signers; opd->last_sig_p = &opd->result.signatures; opd->ignore_inv_recp = !!ignore_inv_recp; diff --git a/src/status-table.c b/src/status-table.c index c85fa951..6d428d71 100644 --- a/src/status-table.c +++ b/src/status-table.c @@ -66,6 +66,7 @@ static struct status_table_s status_table[] = { "ERRSIG", GPGME_STATUS_ERRSIG }, { "EXPKEYSIG", GPGME_STATUS_EXPKEYSIG }, { "EXPSIG", GPGME_STATUS_EXPSIG }, + { "FAILURE", GPGME_STATUS_FAILURE }, { "FILE_DONE", GPGME_STATUS_FILE_DONE }, { "FILE_ERROR", GPGME_STATUS_FILE_ERROR }, { "FILE_START", GPGME_STATUS_FILE_START }, diff --git a/src/verify.c b/src/verify.c index 84487ee4..75914e22 100644 --- a/src/verify.c +++ b/src/verify.c @@ -38,6 +38,9 @@ typedef struct { struct _gpgme_op_verify_result result; + /* The error code from a FAILURE status line or 0. */ + gpg_error_t failure_code; + gpgme_signature_t current_sig; int did_prepare_new_sig; int only_newsig_seen; @@ -769,6 +772,10 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) error code if we are not ready to process this status. */ return parse_error (sig, args, !!sig ); + case GPGME_STATUS_FAILURE: + opd->failure_code = _gpgme_parse_failure (args); + break; + case GPGME_STATUS_EOF: if (sig && !opd->did_prepare_new_sig) calc_sig_summary (sig); @@ -795,6 +802,8 @@ _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) opd->current_sig = NULL; } opd->only_newsig_seen = 0; + if (opd->failure_code) + return opd->failure_code; break; case GPGME_STATUS_PLAINTEXT: