gboolean sgpgme_has_secret_key(void) { gpgme_error_t err = 0; gpgme_ctx_t ctx; gpgme_key_t key; err = gpgme_new (&ctx); if (err) { debug_print("err : %s\n", gpgme_strerror(err)); return TRUE; } check_again: err = gpgme_op_keylist_start(ctx, NULL, TRUE); if (!err) err = gpgme_op_keylist_next(ctx, &key); gpgme_op_keylist_end(ctx); if (gpg_err_code(err) == GPG_ERR_EOF) { if (gpgme_get_protocol(ctx) != GPGME_PROTOCOL_CMS) { gpgme_set_protocol(ctx, GPGME_PROTOCOL_CMS); goto check_again; } gpgme_release(ctx); return FALSE; } else { gpgme_release(ctx); return TRUE; } }
/* Not that this closure is called in the context of the waiter_thread. */ static void verify_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err) { if (!err) { gpgme_verify_result_t res; res = gpgme_op_verify_result (ctx); if (res) verify_dialog_box (gpgme_get_protocol (ctx), res, NULL); } gpgme_data_release (cld->sigobj); engine_private_finished (cld->filter, err); }
/* Not that this closure is called in the context of the waiter_thread. */ static void decrypt_closure (closure_data_t cld, gpgme_ctx_t ctx, gpg_error_t err) { update_passphrase_cache (err, &cld->pw_cb); if (!err && !cld->with_verify) ; else if (!err) { gpgme_verify_result_t res; /* Decryption succeeded. Now check the state of the signatures. */ res = gpgme_op_verify_result (ctx); if (res && res->signatures) verify_dialog_box (gpgme_get_protocol (ctx), res, NULL); } else if (gpg_err_code (err) == GPG_ERR_DECRYPT_FAILED) { /* The decryption failed. See whether we can figure out a more suitable error code. */ gpgme_decrypt_result_t res; res = gpgme_op_decrypt_result (ctx); if (res && res->recipients && gpgme_err_code (res->recipients->status) == GPG_ERR_NO_SECKEY) err = gpg_error (GPG_ERR_NO_SECKEY); /* Fixme: return the keyids */ } else { /* Decryption failed for other reasons. */ } /* If the passphrase callback indicated a cancel operation, change the the error code accordingly. */ if (err && (cld->pw_cb.opts & OPT_FLAG_CANCEL)) err = gpg_error (GPG_ERR_CANCELED); engine_private_finished (cld->filter, err); }
gboolean sgpgme_setup_signers(gpgme_ctx_t ctx, PrefsAccount *account, const gchar *from_addr) { GPGAccountConfig *config; const gchar *signer_addr = account->address; gpgme_signers_clear(ctx); if (from_addr) signer_addr = from_addr; config = prefs_gpg_account_get_config(account); switch(config->sign_key) { case SIGN_KEY_DEFAULT: debug_print("using default gnupg key\n"); break; case SIGN_KEY_BY_FROM: debug_print("using key for %s\n", signer_addr); break; case SIGN_KEY_CUSTOM: debug_print("using key for %s\n", config->sign_key_id); break; } if (config->sign_key != SIGN_KEY_DEFAULT) { const gchar *keyid; gpgme_key_t key, found_key; gpgme_error_t err; if (config->sign_key == SIGN_KEY_BY_FROM) keyid = signer_addr; else if (config->sign_key == SIGN_KEY_CUSTOM) keyid = config->sign_key_id; else goto bail; found_key = NULL; /* Look for any key, not just private ones, or GPGMe doesn't * correctly set the revoked flag. */ err = gpgme_op_keylist_start(ctx, keyid, 0); while ((err = gpgme_op_keylist_next(ctx, &key)) == 0) { if (key == NULL) continue; if (!key->can_sign) continue; if (key->protocol != gpgme_get_protocol(ctx)) { debug_print("skipping a key (wrong protocol %d)\n", key->protocol); gpgme_key_release(key); continue; } if (key->expired) { debug_print("skipping a key, expired"); gpgme_key_release(key); continue; } if (key->revoked) { debug_print("skipping a key, revoked"); gpgme_key_release(key); continue; } if (key->disabled) { debug_print("skipping a key, disabled"); gpgme_key_release(key); continue; } if (found_key != NULL) { gpgme_key_release(key); gpgme_op_keylist_end(ctx); g_warning("ambiguous specification of secret key '%s'\n", keyid); privacy_set_error(_("Secret key specification is ambiguous")); goto bail; } found_key = key; } gpgme_op_keylist_end(ctx); if (found_key == NULL) { g_warning("setup_signers start: %s", gpgme_strerror(err)); privacy_set_error(_("Secret key not found (%s)"), gpgme_strerror(err)); goto bail; } err = gpgme_signers_add(ctx, found_key); debug_print("got key (proto %d (pgp %d, smime %d).\n", found_key->protocol, GPGME_PROTOCOL_OpenPGP, GPGME_PROTOCOL_CMS); gpgme_key_release(found_key); if (err) { g_warning("error adding secret key: %s\n", gpgme_strerror(err)); privacy_set_error(_("Error setting secret key: %s"), gpgme_strerror(err)); goto bail; } } prefs_gpg_account_free_config(config); return TRUE; bail: prefs_gpg_account_free_config(config); return FALSE; }
gpgme_data_t sgpgme_decrypt_verify(gpgme_data_t cipher, gpgme_verify_result_t *status, gpgme_ctx_t ctx) { struct passphrase_cb_info_s info; gpgme_data_t plain; gpgme_error_t err; memset (&info, 0, sizeof info); if ((err = gpgme_data_new(&plain)) != GPG_ERR_NO_ERROR) { gpgme_release(ctx); privacy_set_error(_("Couldn't initialize data, %s"), gpgme_strerror(err)); return NULL; } if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) { prefs_gpg_enable_agent(prefs_gpg_get_config()->use_gpg_agent); if (!getenv("GPG_AGENT_INFO") || !prefs_gpg_get_config()->use_gpg_agent) { info.c = ctx; gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info); } } else { prefs_gpg_enable_agent(TRUE); info.c = ctx; gpgme_set_passphrase_cb (ctx, NULL, &info); } if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) { err = gpgme_op_decrypt_verify(ctx, cipher, plain); if (err != GPG_ERR_NO_ERROR) { debug_print("can't decrypt (%s)\n", gpgme_strerror(err)); privacy_set_error("%s", gpgme_strerror(err)); gpgmegtk_free_passphrase(); gpgme_data_release(plain); return NULL; } err = cm_gpgme_data_rewind(plain); if (err) { debug_print("can't seek (%d %d %s)\n", err, errno, strerror(errno)); } debug_print("decrypted.\n"); *status = gpgme_op_verify_result (ctx); } else { err = gpgme_op_decrypt(ctx, cipher, plain); if (err != GPG_ERR_NO_ERROR) { debug_print("can't decrypt (%s)\n", gpgme_strerror(err)); privacy_set_error("%s", gpgme_strerror(err)); gpgmegtk_free_passphrase(); gpgme_data_release(plain); return NULL; } err = cm_gpgme_data_rewind(plain); if (err) { debug_print("can't seek (%d %d %s)\n", err, errno, strerror(errno)); } debug_print("decrypted.\n"); *status = gpgme_op_verify_result (ctx); } return plain; }
static gpgme_key_t get_key_from_name(gpgme_ctx_t ctx, const gchar * name, gboolean secret, gboolean accept_all, GtkWindow * parent, GError ** error) { GList *keys = NULL; gpgme_key_t key; gpgme_error_t err; gboolean found_bad; time_t now = time(NULL); /* let gpgme list keys */ if ((err = gpgme_op_keylist_start(ctx, name, secret)) != GPG_ERR_NO_ERROR) { gchar *msg = g_strdup_printf(_("could not list keys for \"%s\""), name); g_set_error_from_gpgme(error, err, msg); g_free(msg); return NULL; } found_bad = FALSE; while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR) { /* check if this key and the relevant subkey are usable */ if (KEY_IS_OK(key)) { gpgme_subkey_t subkey = key->subkeys; while (subkey && ((secret && !subkey->can_sign) || (!secret && !subkey->can_encrypt))) subkey = subkey->next; if (subkey && KEY_IS_OK(subkey) && (subkey->expires == 0 || subkey->expires > now)) keys = g_list_append(keys, key); else found_bad = TRUE; } else found_bad = TRUE; } if (gpg_err_code(err) != GPG_ERR_EOF) { gchar *msg = g_strdup_printf(_("could not list keys for \"%s\""), name); g_set_error_from_gpgme(error, err, msg); g_free(msg); gpgme_op_keylist_end(ctx); g_list_foreach(keys, (GFunc) gpgme_key_unref, NULL); g_list_free(keys); return NULL; } gpgme_op_keylist_end(ctx); if (!keys) { if (error) { if (strchr(name, '@')) { if (found_bad) g_set_error(error, GPGME_ERROR_QUARK, GPG_ERR_KEY_SELECTION, _ ("%s: a key for %s is present, but it is expired, disabled, revoked or invalid"), "gmime-gpgme", name); else g_set_error(error, GPGME_ERROR_QUARK, GPG_ERR_KEY_SELECTION, _("%s: could not find a key for %s"), "gmime-gpgme", name); } else { if (found_bad) g_set_error(error, GPGME_ERROR_QUARK, GPG_ERR_KEY_SELECTION, _ ("%s: a key with id %s is present, but it is expired, disabled, revoked or invalid"), "gmime-gpgme", name); else g_set_error(error, GPGME_ERROR_QUARK, GPG_ERR_KEY_SELECTION, _("%s: could not find a key with id %s"), "gmime-gpgme", name); } } return NULL; } /* let the user select a key from the list if there is more than one */ if (g_list_length(keys) > 1) { if (select_key_cb) key = select_key_cb(name, secret, keys, gpgme_get_protocol(ctx), parent); else { if (error) g_set_error(error, GPGME_ERROR_QUARK, GPG_ERR_KEY_SELECTION, _("%s: multiple keys for %s"), "gmime-gpgme", name); key = NULL; } if (key) gpgme_key_ref(key); g_list_foreach(keys, (GFunc) gpgme_key_unref, NULL); } else key = (gpgme_key_t) keys->data; g_list_free(keys); /* OpenPGP: ask the user if a low-validity key should be trusted for * encryption */ // FIXME - shouldn't we do the same for S/MIME? if (key && !secret && !accept_all && gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) { gpgme_user_id_t uid = key->uids; gchar *upcase_name = g_ascii_strup(name, -1); gboolean found = FALSE; while (!found && uid) { /* check the email field which may or may not be present */ if (uid->email && !g_ascii_strcasecmp(uid->email, name)) found = TRUE; else { /* no email or no match, check the uid */ gchar *upcase_uid = g_ascii_strup(uid->uid, -1); if (strstr(upcase_uid, upcase_name)) found = TRUE; else uid = uid->next; g_free(upcase_uid); } } g_free(upcase_name); /* ask the user if a low-validity key shall be used */ if (uid && uid->validity < GPGME_VALIDITY_FULL) { if (!accept_low_trust_cb || !accept_low_trust_cb(name, uid, parent)) { gpgme_key_unref(key); key = NULL; if (error) g_set_error(error, GPGME_ERROR_QUARK, GPG_ERR_KEY_SELECTION, _("%s: insufficient validity for uid %s"), "gmime-gpgme", name); } } } return key; }
/** \brief Verify a signature * * \param content GMime stream of the signed matter. * \param sig_plain GMime signature stream for a detached signature, or the * output stream for the checked matter in single-part mode. * \param protocol GpgME crypto protocol of the signature. * \param singlepart_mode TRUE indicates single-part mode (i.e. sig_plain * an output stream). * \param error Filled with error information on error. * \return A new signature status object on success, or NULL on error. * * Verify a signature by calling GpgME on the passed streams, and create a * new signature object on success. */ GMimeGpgmeSigstat * libbalsa_gpgme_verify(GMimeStream * content, GMimeStream * sig_plain, gpgme_protocol_t protocol, gboolean singlepart_mode, GError ** error) { gpgme_error_t err; gpgme_ctx_t ctx; struct gpgme_data_cbs cbs = { (gpgme_data_read_cb_t) g_mime_gpgme_stream_rd, /* read method */ (gpgme_data_write_cb_t) g_mime_gpgme_stream_wr, /* write method */ NULL, /* seek method */ cb_data_release /* release method */ }; gpgme_data_t cont_data; gpgme_data_t sig_plain_data; GMimeGpgmeSigstat *result; /* paranoia checks */ g_return_val_if_fail(GMIME_IS_STREAM(content), NULL); g_return_val_if_fail(GMIME_IS_STREAM(sig_plain), NULL); g_return_val_if_fail(protocol == GPGME_PROTOCOL_OpenPGP || protocol == GPGME_PROTOCOL_CMS, NULL); /* create the GpgME context */ if ((err = gpgme_new_with_protocol(&ctx, protocol, NULL, error)) != GPG_ERR_NO_ERROR) return NULL; /* create the message stream */ if ((err = gpgme_data_new_from_cbs(&cont_data, &cbs, content)) != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("could not get data from stream")); gpgme_release(ctx); return NULL; } /* create data object for the detached signature stream or the * "decrypted" plaintext */ if ((err = gpgme_data_new_from_cbs(&sig_plain_data, &cbs, sig_plain)) != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("could not get data from stream")); gpgme_data_release(cont_data); gpgme_release(ctx); return NULL; } /* verify the signature */ if (singlepart_mode) err = gpgme_op_verify(ctx, cont_data, NULL, sig_plain_data); else err = gpgme_op_verify(ctx, sig_plain_data, cont_data, NULL); if (err != GPG_ERR_NO_ERROR) { g_set_error_from_gpgme(error, err, _("signature verification failed")); result = g_mime_gpgme_sigstat_new(); result->status = err; result->protocol = gpgme_get_protocol(ctx); } else result = g_mime_gpgme_sigstat_new_from_gpgme_ctx(ctx); /* release gmgme data buffers, destroy the context and return the * signature object */ gpgme_data_release(cont_data); gpgme_data_release(sig_plain_data); gpgme_release(ctx); return result; }
static gpg_error_t gpa_file_sign_operation_start (GpaFileSignOperation *op, gpa_file_item_t file_item) { gpg_error_t err; if (file_item->direct_in) { /* No copy is made. */ err = gpgme_data_new_from_mem (&op->plain, file_item->direct_in, file_item->direct_in_len, 0); if (err) { gpa_gpgme_warning (err); return err; } err = gpgme_data_new (&op->sig); if (err) { gpa_gpgme_warning (err); gpgme_data_release (op->plain); op->plain = NULL; return err; } } else { gchar *plain_filename = file_item->filename_in; char *filename_used; file_item->filename_out = destination_filename (plain_filename, gpgme_get_armor (GPA_OPERATION (op)->context->ctx), gpgme_get_protocol (GPA_OPERATION (op)->context->ctx), op->sign_type); /* Open the files */ op->plain_fd = gpa_open_input (plain_filename, &op->plain, GPA_OPERATION (op)->window); if (op->plain_fd == -1) /* FIXME: Error value. */ return gpg_error (GPG_ERR_GENERAL); op->sig_fd = gpa_open_output (file_item->filename_out, &op->sig, GPA_OPERATION (op)->window, &filename_used); if (op->sig_fd == -1) { gpgme_data_release (op->plain); close (op->plain_fd); xfree (filename_used); /* FIXME: Error value. */ return gpg_error (GPG_ERR_GENERAL); } xfree (file_item->filename_out); file_item->filename_out = filename_used; } /* Start the operation */ err = gpgme_op_sign_start (GPA_OPERATION (op)->context->ctx, op->plain, op->sig, op->sign_type); if (err) { gpa_gpgme_warning (err); return err; } /* Show and update the progress dialog */ gtk_widget_show_all (GPA_FILE_OPERATION (op)->progress_dialog); gpa_progress_dialog_set_label (GPA_PROGRESS_DIALOG (GPA_FILE_OPERATION (op)->progress_dialog), file_item->direct_name ? file_item->direct_name : file_item->filename_in); return 0; }
gboolean sgpgme_setup_signers(gpgme_ctx_t ctx, PrefsAccount *account, const gchar *from_addr) { GPGAccountConfig *config; const gchar *signer_addr = account->address; gpgme_signers_clear(ctx); if (from_addr) signer_addr = from_addr; config = prefs_gpg_account_get_config(account); switch(config->sign_key) { case SIGN_KEY_DEFAULT: debug_print("using default gnupg key\n"); break; case SIGN_KEY_BY_FROM: debug_print("using key for %s\n", signer_addr); break; case SIGN_KEY_CUSTOM: debug_print("using key for %s\n", config->sign_key_id); break; } if (config->sign_key != SIGN_KEY_DEFAULT) { const gchar *keyid; gpgme_key_t key, key2; gpgme_error_t err; if (config->sign_key == SIGN_KEY_BY_FROM) keyid = signer_addr; else if (config->sign_key == SIGN_KEY_CUSTOM) keyid = config->sign_key_id; else goto bail; err = gpgme_op_keylist_start(ctx, keyid, 1); if (!err) { do { err = gpgme_op_keylist_next(ctx, &key); if (!err && key && key->protocol == gpgme_get_protocol(ctx) && !key->expired && !key->revoked && !key->disabled) break; if (!err && key && key->protocol != gpgme_get_protocol(ctx)) { debug_print("skipping a key (wrong protocol %d)\n", key->protocol); gpgme_key_release(key); } if (!err && key && (key->expired || key->revoked || key->disabled)) { debug_print("skipping a key"); if (key->expired) debug_print(" expired"); if (key->revoked) debug_print(" revoked"); if (key->disabled) debug_print(" disabled"); debug_print("\n"); gpgme_key_release(key); } } while (!err); } if (err) { g_warning("setup_signers start: %s", gpgme_strerror(err)); privacy_set_error(_("Secret key not found (%s)"), gpgme_strerror(err)); goto bail; } do { err = gpgme_op_keylist_next(ctx, &key2); if (!err && key2 && key2->protocol == gpgme_get_protocol(ctx) && !key2->expired && !key2->revoked && !key2->disabled) break; if (!err && key2 && key2->protocol != gpgme_get_protocol(ctx)) { debug_print("skipping a key (wrong protocol %d)\n", key2->protocol); gpgme_key_release(key2); } if (!err && key2 && (key2->expired || key2->revoked || key2->disabled)) { debug_print("skipping a key"); if (key2->expired) debug_print(" expired"); if (key2->revoked) debug_print(" revoked"); if (key2->disabled) debug_print(" disabled"); debug_print("\n"); gpgme_key_release(key2); } } while (!err); if (!err) { gpgme_key_release(key2); g_warning("ambiguous specification of secret key '%s'\n", keyid); privacy_set_error(_("Secret key specification is ambiguous")); goto bail; } gpgme_op_keylist_end(ctx); err = gpgme_signers_add(ctx, key); debug_print("got key (proto %d (pgp %d, smime %d).\n", key->protocol, GPGME_PROTOCOL_OpenPGP, GPGME_PROTOCOL_CMS); gpgme_key_release(key); if (err) { g_warning("error adding secret key: %s\n", gpgme_strerror(err)); privacy_set_error(_("Error setting secret key: %s"), gpgme_strerror(err)); goto bail; } } prefs_gpg_account_free_config(config); return TRUE; bail: prefs_gpg_account_free_config(config); return FALSE; }
gboolean pgpmime_sign(MimeInfo *mimeinfo, PrefsAccount *account, const gchar *from_addr) { MimeInfo *msgcontent, *sigmultipart, *newinfo; gchar *textstr, *micalg = NULL; FILE *fp; gchar *boundary = NULL; gchar *sigcontent; gpgme_ctx_t ctx; gpgme_data_t gpgtext, gpgsig; gpgme_error_t err; size_t len; struct passphrase_cb_info_s info; gpgme_sign_result_t result = NULL; gchar *test_msg; fp = my_tmpfile(); if (fp == NULL) { perror("my_tmpfile"); privacy_set_error(_("Couldn't create temporary file: %s"), g_strerror(errno)); return FALSE; } procmime_write_mimeinfo(mimeinfo, fp); rewind(fp); /* read temporary file into memory */ test_msg = file_read_stream_to_str(fp); claws_fclose(fp); memset (&info, 0, sizeof info); /* remove content node from message */ msgcontent = (MimeInfo *) mimeinfo->node->children->data; g_node_unlink(msgcontent->node); /* create temporary multipart for content */ sigmultipart = procmime_mimeinfo_new(); sigmultipart->type = MIMETYPE_MULTIPART; sigmultipart->subtype = g_strdup("signed"); do { g_free(boundary); boundary = generate_mime_boundary("Sig"); } while (strstr(test_msg, boundary) != NULL); g_free(test_msg); g_hash_table_insert(sigmultipart->typeparameters, g_strdup("boundary"), g_strdup(boundary)); g_hash_table_insert(sigmultipart->typeparameters, g_strdup("protocol"), g_strdup("application/pgp-signature")); g_node_append(sigmultipart->node, msgcontent->node); g_node_append(mimeinfo->node, sigmultipart->node); /* write message content to temporary file */ fp = my_tmpfile(); if (fp == NULL) { perror("my_tmpfile"); privacy_set_error(_("Couldn't create temporary file: %s"), g_strerror(errno)); return FALSE; } procmime_write_mimeinfo(sigmultipart, fp); rewind(fp); /* read temporary file into memory */ textstr = get_canonical_content(fp, boundary); g_free(boundary); claws_fclose(fp); gpgme_data_new_from_mem(&gpgtext, textstr, (size_t)strlen(textstr), 0); gpgme_data_new(&gpgsig); if ((err = gpgme_new(&ctx)) != GPG_ERR_NO_ERROR) { debug_print(("Couldn't initialize GPG context, %s\n"), gpgme_strerror(err)); privacy_set_error(_("Couldn't initialize GPG context, %s"), gpgme_strerror(err)); return FALSE; } gpgme_set_textmode(ctx, 1); gpgme_set_armor(ctx, 1); gpgme_signers_clear (ctx); if (!sgpgme_setup_signers(ctx, account, from_addr)) { gpgme_release(ctx); return FALSE; } prefs_gpg_enable_agent(prefs_gpg_get_config()->use_gpg_agent); if (g_getenv("GPG_AGENT_INFO") && prefs_gpg_get_config()->use_gpg_agent) { debug_print("GPG_AGENT_INFO environment defined, running without passphrase callback\n"); } else { info.c = ctx; gpgme_set_passphrase_cb (ctx, gpgmegtk_passphrase_cb, &info); } err = gpgme_op_sign(ctx, gpgtext, gpgsig, GPGME_SIG_MODE_DETACH); if (err != GPG_ERR_NO_ERROR) { if (err == GPG_ERR_CANCELED) { /* ignore cancelled signing */ privacy_reset_error(); debug_print("gpgme_op_sign cancelled\n"); } else { privacy_set_error(_("Data signing failed, %s"), gpgme_strerror(err)); debug_print("gpgme_op_sign error : %x\n", err); } gpgme_release(ctx); return FALSE; } result = gpgme_op_sign_result(ctx); if (result && result->signatures) { gpgme_new_signature_t sig = result->signatures; if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) { gchar *down_algo = g_ascii_strdown(gpgme_hash_algo_name( result->signatures->hash_algo), -1); micalg = g_strdup_printf("pgp-%s", down_algo); g_free(down_algo); } else { micalg = g_strdup(gpgme_hash_algo_name( result->signatures->hash_algo)); } while (sig) { debug_print("valid signature: %s\n", sig->fpr); sig = sig->next; } } else if (result && result->invalid_signers) { gpgme_invalid_key_t invalid = result->invalid_signers; while (invalid) { g_warning("invalid signer: %s (%s)", invalid->fpr, gpgme_strerror(invalid->reason)); privacy_set_error(_("Data signing failed due to invalid signer: %s"), gpgme_strerror(invalid->reason)); invalid = invalid->next; } gpgme_release(ctx); return FALSE; } else { /* can't get result (maybe no signing key?) */ debug_print("gpgme_op_sign_result error\n"); privacy_set_error(_("Data signing failed, no results.")); gpgme_release(ctx); return FALSE; } sigcontent = sgpgme_data_release_and_get_mem(gpgsig, &len); gpgme_data_release(gpgtext); g_free(textstr); if (sigcontent == NULL || len <= 0) { g_warning("sgpgme_data_release_and_get_mem failed"); privacy_set_error(_("Data signing failed, no contents.")); g_free(micalg); g_free(sigcontent); return FALSE; } /* add signature */ g_hash_table_insert(sigmultipart->typeparameters, g_strdup("micalg"), micalg); newinfo = procmime_mimeinfo_new(); newinfo->type = MIMETYPE_APPLICATION; newinfo->subtype = g_strdup("pgp-signature"); newinfo->description = g_strdup(_("OpenPGP digital signature")); newinfo->content = MIMECONTENT_MEM; newinfo->data.mem = g_malloc(len + 1); g_memmove(newinfo->data.mem, sigcontent, len); newinfo->data.mem[len] = '\0'; g_node_append(sigmultipart->node, newinfo->node); g_free(sigcontent); gpgme_release(ctx); return TRUE; }
static PyObject * pygpgme_context_get_protocol(PyGpgmeContext *self) { return PyInt_FromLong(gpgme_get_protocol(self->ctx)); }