gpgme_error_t _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) { gpgme_ctx_t ctx = (gpgme_ctx_t) priv; gpgme_error_t err; void *hook; op_data_t opd; gpgme_signature_t sig; char *end; err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL); opd = hook; if (err) return err; sig = opd->current_sig; switch (code) { case GPGME_STATUS_NEWSIG: if (sig) calc_sig_summary (sig); err = prepare_new_sig (opd); opd->only_newsig_seen = 1; return err; case GPGME_STATUS_GOODSIG: case GPGME_STATUS_EXPSIG: case GPGME_STATUS_EXPKEYSIG: case GPGME_STATUS_BADSIG: case GPGME_STATUS_ERRSIG: case GPGME_STATUS_REVKEYSIG: if (sig && !opd->did_prepare_new_sig) calc_sig_summary (sig); opd->only_newsig_seen = 0; return parse_new_sig (opd, code, args, ctx->protocol); case GPGME_STATUS_VALIDSIG: opd->only_newsig_seen = 0; return sig ? parse_valid_sig (sig, args, ctx->protocol) : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_NODATA: opd->only_newsig_seen = 0; if (!sig) return gpg_error (GPG_ERR_NO_DATA); sig->status = gpg_error (GPG_ERR_NO_DATA); break; case GPGME_STATUS_UNEXPECTED: opd->only_newsig_seen = 0; if (!sig) return gpg_error (GPG_ERR_GENERAL); sig->status = gpg_error (GPG_ERR_NO_DATA); break; case GPGME_STATUS_NOTATION_NAME: case GPGME_STATUS_NOTATION_FLAGS: case GPGME_STATUS_NOTATION_DATA: case GPGME_STATUS_POLICY_URL: opd->only_newsig_seen = 0; return sig ? parse_notation (sig, code, args) : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_TRUST_UNDEFINED: case GPGME_STATUS_TRUST_NEVER: case GPGME_STATUS_TRUST_MARGINAL: case GPGME_STATUS_TRUST_FULLY: case GPGME_STATUS_TRUST_ULTIMATE: opd->only_newsig_seen = 0; return sig ? parse_trust (sig, code, args) : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_PKA_TRUST_BAD: case GPGME_STATUS_PKA_TRUST_GOOD: opd->only_newsig_seen = 0; /* Check that we only get one of these status codes per signature; if not the crypto backend misbehaves. */ if (!sig || sig->pka_trust || sig->pka_address) return trace_gpg_error (GPG_ERR_INV_ENGINE); sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1; end = strchr (args, ' '); if (end) *end = 0; sig->pka_address = strdup (args); break; case GPGME_STATUS_TOFU_USER: opd->only_newsig_seen = 0; return sig ? parse_tofu_user (sig, args) /* */ : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_TOFU_STATS: opd->only_newsig_seen = 0; return sig ? parse_tofu_stats (sig, args) /* */ : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_TOFU_STATS_LONG: opd->only_newsig_seen = 0; return sig ? parse_tofu_stats_long (sig, args, ctx->raw_description) /* */ : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_ERROR: opd->only_newsig_seen = 0; /* Some error stati are informational, so we don't return an 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); if (opd->only_newsig_seen && sig) { gpgme_signature_t sig2; /* The last signature has no valid information - remove it from the list. */ assert (!sig->next); if (sig == opd->result.signatures) opd->result.signatures = NULL; else { for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next) if (sig2->next == sig) { sig2->next = NULL; break; } } /* Note that there is no need to release the members of SIG because we won't be here if they have been set. */ free (sig); opd->current_sig = NULL; } opd->only_newsig_seen = 0; if (opd->failure_code) return opd->failure_code; break; case GPGME_STATUS_PLAINTEXT: if (++opd->plaintext_seen > 1) return gpg_error (GPG_ERR_BAD_DATA); err = _gpgme_parse_plaintext (args, &opd->result.file_name); if (err) return err; default: break; } return 0; }
gpgme_error_t _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args) { gpgme_ctx_t ctx = (gpgme_ctx_t) priv; gpgme_error_t err; void *hook; op_data_t opd; err = _gpgme_passphrase_status_handler (priv, code, args); if (err) return err; err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL); opd = hook; if (err) return err; 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). */ if (opd->failed) 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: /* Fixme: Provide a way to return the used symmetric algorithm. */ break; case GPGME_STATUS_DECRYPTION_OKAY: opd->okay = 1; break; case GPGME_STATUS_DECRYPTION_FAILED: opd->failed = 1; break; case GPGME_STATUS_ERROR: /* Note that this is an informational status code which should not lead to an error return unless it is something not related to the backend. */ { const char d_alg[] = "decrypt.algorithm"; const char k_alg[] = "decrypt.keyusage"; if (!strncmp (args, d_alg, sizeof (d_alg) - 1)) { args += sizeof (d_alg) - 1; while (*args == ' ') args++; if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM) { char *end; while (*args && *args != ' ') args++; while (*args == ' ') args++; end = strchr (args, ' '); if (end) *end = '\0'; if (!(*args == '?' && *(args + 1) == '\0')) { opd->result.unsupported_algorithm = strdup (args); if (!opd->result.unsupported_algorithm) return gpg_error_from_syserror (); } } } else if (!strncmp (args, k_alg, sizeof (k_alg) - 1)) { args += sizeof (k_alg) - 1; while (*args == ' ') args++; if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE) opd->result.wrong_key_usage = 1; } } break; case GPGME_STATUS_ENC_TO: err = parse_enc_to (args, opd->last_recipient_p, ctx->protocol); if (err) return err; opd->last_recipient_p = &(*opd->last_recipient_p)->next; break; case GPGME_STATUS_NO_SECKEY: { gpgme_recipient_t rec = opd->result.recipients; while (rec) { if (!strcmp (rec->keyid, args)) { rec->status = gpg_error (GPG_ERR_NO_SECKEY); break; } rec = rec->next; } /* FIXME: Is this ok? */ if (!rec) return trace_gpg_error (GPG_ERR_INV_ENGINE); } break; case GPGME_STATUS_PLAINTEXT: err = _gpgme_parse_plaintext (args, &opd->result.file_name); if (err) return err; break; case GPGME_STATUS_INQUIRE_MAXLEN: if (ctx->status_cb) { err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args); if (err) return err; } break; default: break; } return 0; }