[rs-commit] r41 - in /redwax-signtext/trunk/src/linux: crypto.c crypto.h signtext.c signtext.h
rs-commit at redwax.eu
rs-commit at redwax.eu
Sat Sep 10 13:37:57 CEST 2022
Author: minfrin at redwax.eu
Date: Sat Sep 10 13:37:56 2022
New Revision: 41
Log:
Optimise error handling. Switch the CMS processing loop to being
called from idle in preparation for the ability to send messages
via the event loop.
Modified:
redwax-signtext/trunk/src/linux/crypto.c
redwax-signtext/trunk/src/linux/crypto.h
redwax-signtext/trunk/src/linux/signtext.c
redwax-signtext/trunk/src/linux/signtext.h
Modified: redwax-signtext/trunk/src/linux/crypto.c
==============================================================================
--- redwax-signtext/trunk/src/linux/crypto.c (original)
+++ redwax-signtext/trunk/src/linux/crypto.c Sat Sep 10 13:37:56 2022
@@ -282,22 +282,11 @@
}
if (gerror) {
- GtkWidget* dialog;
-
fatal:
-
- dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
- GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
- "%s", ("Redwax SignText - Error"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- ("Error: %s"),
- gerror->message);
-
+ signtext_error (NULL, gerror);
g_error_free (gerror);
-
- gtk_widget_show (dialog);
-
- }
+ }
+
}
@@ -433,6 +422,55 @@
}
+static void
+crypto_sign_loggedout (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *gerror = NULL;
+ SignTextInstance *instance = user_data;
+
+ g_printerr("crypto_sign_loggedout\n");
+
+ if (gck_session_logout_finish(instance->session, res, &gerror)) {
+
+ gtk_widget_set_visible(GTK_WIDGET(instance->progress), FALSE);
+
+ }
+
+ if (gerror) {
+ signtext_error (instance, gerror);
+ g_error_free (gerror);
+ }
+
+}
+
+
+static void
+crypto_sign_logout(SignTextInstance *instance)
+{
+ g_printerr("crypto_sign_logout\n");
+
+ gck_session_logout_async (instance->session, instance->signtext->cancellable, crypto_sign_loggedout, instance);
+}
+
+/*
+ *
+ */
+static gboolean
+crypto_sign_pulse (gpointer user_data)
+{
+ SignTextInstance *instance = user_data;
+
+ if (gtk_widget_is_visible(GTK_WIDGET(instance->progress))) {
+ gtk_progress_bar_pulse (instance->progress);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/*
* Handle the writing of the CMS structure.
*/
@@ -440,8 +478,20 @@
pem_writer_cb (void *cb_value, const void *buffer, size_t count)
{
SignTextInstance *instance = cb_value;
+ gsize len;
g_printerr("pem_writer_cb: %d\n", (int)count);
+
+ len = instance->payload_len + count;
+ instance->payload = g_realloc(instance->payload, len);
+ memcpy(instance->payload + instance->payload_len, buffer, count);
+ instance->payload_len = len;
+
+ if (len > 1024) {
+
+
+
+ }
return 0;
}
@@ -452,225 +502,183 @@
* Are we good to leave?
*/
static void
-crypto_sign_done (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
+crypto_sign_done (gpointer user_data)
{
SignTextInstance *instance = user_data;
GError *gerror = NULL;
- gchar *signature = NULL;
g_printerr("crypto_sign_done\n");
- signature = g_task_propagate_pointer (G_TASK (res), &gerror);
+ crypto_sign_logout(instance);
if (gerror) {
- GtkWidget* dialog;
-
- dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
- GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
- "%s", ("Redwax SignText - Error"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- ("Error: %s"),
- gerror->message);
-
+ signtext_error (instance, gerror);
g_error_free (gerror);
-
- gtk_widget_show (dialog);
-
- }
-
- if (signature) {
- g_free(signature);
- }
-
- ksba_cert_release(instance->signer);
+ }
}
/*
- * Generate and sign the CMS structure.
+ * Generate and sign the CMS structure in an idle loop.
*
* When done, jump to the completion step to send the message.
*/
static void
-crypto_sign_do (GTask *task,
- gpointer source_obj,
- gpointer task_data,
- GCancellable *cancellable)
-{
- SignTextInstance *instance = task_data;
+crypto_sign_do (gpointer user_data)
+{
+ SignTextInstance *instance = user_data;
GError *gerror = NULL;
- gchar *signature = NULL;
-
- ksba_writer_t w = NULL;
+
gpg_error_t err;
int rc;
- ksba_stop_reason_t stopreason;
-
g_printerr("crypto_sign_do\n");
- err = ksba_writer_new (&w);
- if (err) {
- gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_writer_new failed: %s", gpg_strerror (err));
- goto fatal;
- }
-
- err = ksba_writer_set_cb (w, pem_writer_cb, instance);
- if (err) {
- gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_writer_set_cb failed: %s", gpg_strerror (err));
- goto fatal;
- }
-
- err = ksba_cms_set_reader_writer (instance->cms, NULL, w);
- if (err) {
- gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_set_reader_writer failed: %s", gpg_strerror (err));
- goto fatal;
- }
-
-
-
/* Main building loop. */
- do {
- err = ksba_cms_build (instance->cms, &stopreason);
+ err = ksba_cms_build (instance->cms, &instance->stopreason);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_build failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+
+ if (instance->stopreason == KSBA_SR_BEGIN_DATA) {
+ g_printerr("crypto_sign_do: begin data\n");
+
+ }
+
+
+ else if (instance->stopreason == KSBA_SR_NEED_SIG) {
+
+ GckSlot *slot;
+ GArray *mechanisms;
+
+ gcry_md_hd_t md;
+
+ unsigned char *sigval;
+ size_t sigval_len;
+ gcry_sexp_t sexp;
+
+ unsigned char *digest;
+ size_t digest_len;
+
+ unsigned char *alg;
+ size_t alg_len;
+
+ unsigned char *sig;
+ gsize sig_len;
+
+ unsigned char *data;
+ gsize data_len;
+
+ g_printerr("crypto_sign_do: need sig\n");
+
+ slot = gck_session_get_slot(instance->session);
+ mechanisms = gck_slot_get_mechanisms(slot);
+
+ //int i;
+ //for (i = 0; i < gck_mechanisms_length(mechanisms); i++) {
+ //g_printerr("crypto_sign_do: mechs: 0x%lxUL (%s)\n", gck_mechanisms_at(mechanisms, i), gcry_pk_algo_name(gck_mechanisms_at(mechanisms, i)));
+ //}
+
+ if (!gck_mechanisms_check(mechanisms, CKM_RSA_PKCS, GCK_INVALID)) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "CKM_RSA_PKCS not supported by this card.");
+ goto fatal;
+ }
+
+ rc = gcry_md_open (&md, 0, 0);
+ if (rc) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_md_open failed: %s", gpg_strerror (rc));
+ goto fatal;
+ }
+
+ ksba_cms_set_hash_function (instance->cms, HASH_FNC, md);
+
+ gcry_md_enable (md, instance->hash_alg);
+
+ err = ksba_cms_hash_signed_attrs (instance->cms, 0);
if (err) {
- gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_build failed: %s", gpg_strerror (err));
- goto fatal;
- }
-
-
- if (stopreason == KSBA_SR_BEGIN_DATA) {
- g_printerr("crypto_sign_do: begin data\n");
-
- }
-
-
- else if (stopreason == KSBA_SR_NEED_SIG) {
-
- GckSlot *slot;
- GArray *mechanisms;
-
- gcry_md_hd_t md;
-
- unsigned char *sigval;
- size_t sigval_len;
- gcry_sexp_t sexp;
-
- unsigned char *digest;
- size_t digest_len;
-
- unsigned char *alg;
- size_t alg_len;
-
- unsigned char *sig;
- gsize sig_len;
-
- unsigned char *data;
- gsize data_len;
-
- g_printerr("crypto_sign_do: need sig\n");
-
- slot = gck_session_get_slot(instance->session);
- mechanisms = gck_slot_get_mechanisms(slot);
-
- //int i;
- //for (i = 0; i < gck_mechanisms_length(mechanisms); i++) {
- //g_printerr("crypto_sign_do: mechs: 0x%lxUL (%s)\n", gck_mechanisms_at(mechanisms, i), gcry_pk_algo_name(gck_mechanisms_at(mechanisms, i)));
- //}
-
- if (!gck_mechanisms_check(mechanisms, CKM_RSA_PKCS, GCK_INVALID)) {
- gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "CKM_RSA_PKCS not supported by this card.");
- goto fatal;
- }
-
- rc = gcry_md_open (&md, 0, 0);
- if (rc) {
- gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_md_open failed: %s", gpg_strerror (rc));
- goto fatal;
- }
-
- ksba_cms_set_hash_function (instance->cms, HASH_FNC, md);
-
- gcry_md_enable (md, instance->hash_alg);
-
- err = ksba_cms_hash_signed_attrs (instance->cms, 0);
- if (err) {
- gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_hash_signed_attrs failed: %s", gpg_strerror (err));
- gcry_md_close (md);
- goto fatal;
- }
-
- digest = gcry_md_read (md, instance->hash_alg);
- digest_len = gcry_md_get_algo_dlen (instance->hash_alg);
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_hash_signed_attrs failed: %s", gpg_strerror (err));
gcry_md_close (md);
- if (!digest || !digest_len) {
- gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_md_read / gcry_md_get_algo_dlen failed");
- goto fatal;
- }
-
- if (gcry_md_algo_info(instance->hash_alg, GCRYCTL_GET_ASNOID, NULL, &alg_len)) {
- gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_md_algo_info failed.");
- goto fatal;
- }
- alg = g_malloc(alg_len);
- gcry_md_algo_info(instance->hash_alg, GCRYCTL_GET_ASNOID, alg, &alg_len);
-
- /*
- * Our signature is a DER of the digest algorithm, followed by the digest.
- */
- data_len = alg_len + digest_len;
- data = g_malloc(data_len);
- memcpy(data, alg, alg_len);
- memcpy(data + alg_len, digest, digest_len);
- g_free(alg);
-
- /*
- * Sign on the line.
- */
- sig = gck_session_sign(instance->session, instance->key, CKM_RSA_PKCS, data, data_len, &sig_len, instance->signtext->cancellable, &gerror);
- g_free(data);
- if (gerror) {
- goto fatal;
- }
-
- rc = gcry_sexp_build(&sexp, NULL, "(sig-val(rsa(s %b)))",
- sig_len, (char *)sig);
-
- g_free(sig);
- if (rc) {
- gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_sexp_build failed: %s", gcry_strerror (rc));
- goto fatal;
- }
-
- sigval_len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
- sigval = g_malloc(sigval_len);
- gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, sigval, sigval_len);
- gcry_sexp_release(sexp);
-
- err = ksba_cms_set_sig_val (instance->cms, 0, sigval);
- g_free(sigval);
- if (err) {
- gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_set_sig_val failed: %s", gpg_strerror (err));
- goto fatal;
- }
-
- }
-
- } while (stopreason != KSBA_SR_READY);
-
+ goto fatal;
+ }
+
+ digest = gcry_md_read (md, instance->hash_alg);
+ digest_len = gcry_md_get_algo_dlen (instance->hash_alg);
+ gcry_md_close (md);
+ if (!digest || !digest_len) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_md_read / gcry_md_get_algo_dlen failed");
+ goto fatal;
+ }
+
+ if (gcry_md_algo_info(instance->hash_alg, GCRYCTL_GET_ASNOID, NULL, &alg_len)) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_md_algo_info failed.");
+ goto fatal;
+ }
+ alg = g_malloc(alg_len);
+ gcry_md_algo_info(instance->hash_alg, GCRYCTL_GET_ASNOID, alg, &alg_len);
+
+ /*
+ * Our signature is a DER of the digest algorithm, followed by the digest.
+ */
+ data_len = alg_len + digest_len;
+ data = g_malloc(data_len);
+ memcpy(data, alg, alg_len);
+ memcpy(data + alg_len, digest, digest_len);
+ g_free(alg);
+
+ /*
+ * Sign on the line.
+ */
+ sig = gck_session_sign(instance->session, instance->key, CKM_RSA_PKCS, data, data_len, &sig_len, instance->signtext->cancellable, &gerror);
+ g_free(data);
+ if (gerror) {
+ goto fatal;
+ }
+
+ rc = gcry_sexp_build(&sexp, NULL, "(sig-val(rsa(s %b)))",
+ sig_len, (char *)sig);
+
+ g_free(sig);
+ if (rc) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_sexp_build failed: %s", gcry_strerror (rc));
+ goto fatal;
+ }
+
+ sigval_len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
+ sigval = g_malloc(sigval_len);
+ gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, sigval, sigval_len);
+ gcry_sexp_release(sexp);
+
+ err = ksba_cms_set_sig_val (instance->cms, 0, sigval);
+ g_free(sigval);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_set_sig_val failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ }
+
+ if (instance->stopreason != KSBA_SR_READY) {
+ g_idle_add((GSourceFunc)crypto_sign_do, instance);
+ }
+ else {
+ g_idle_add((GSourceFunc)crypto_sign_done, instance);
+ }
if (gerror) {
fatal:
- g_task_return_error (task, gerror);
- }
- else {
- g_task_return_pointer(task, signature, NULL);
- }
-
- ksba_writer_release(w);
-
+ signtext_error (instance, gerror);
+ g_error_free (gerror);
+ }
+
+}
+
+void
+crypto_sign_continue (SignTextInstance *instance)
+{
+ g_idle_add((GSourceFunc)crypto_sign_do, instance);
}
/*
@@ -703,30 +711,15 @@
instance->key = GCK_OBJECT(keys->data);
- /* we sign synchronously, so do this in a task */
-
- GTask *task = g_task_new (instance->sign, instance->signtext->cancellable, crypto_sign_done, instance);
- g_task_set_task_data (task, instance, NULL);
- g_task_run_in_thread (task, crypto_sign_do);
- g_object_unref (task);
+ /* next up, the signing loop */
+ crypto_sign_continue(instance);
}
if (gerror) {
- GtkWidget* dialog;
-
fatal:
- dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
- GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
- "%s", ("Redwax SignText - Error"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- ("Error: %s"),
- gerror->message);
-
+ signtext_error (instance, gerror);
g_error_free (gerror);
-
- gtk_widget_show (dialog);
-
}
}
@@ -771,23 +764,12 @@
}
if (gerror) {
- GtkWidget* dialog;
+fatal:
+ signtext_error (instance, gerror);
+ g_error_free (gerror);
+ }
// FIXME: update the UI with the new status of PIN attempts
-
-fatal:
- dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
- GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
- "%s", ("Redwax SignText - Error"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- ("Error: %s"),
- gerror->message);
-
- g_error_free (gerror);
-
- gtk_widget_show (dialog);
-
- }
}
@@ -824,19 +806,8 @@
}
if (gerror) {
- GtkWidget* dialog;
-
- dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
- GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
- "%s", ("Redwax SignText - Error"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- ("Error: %s"),
- gerror->message);
-
+ signtext_error (instance, gerror);
g_error_free (gerror);
-
- gtk_widget_show (dialog);
-
}
if (instance->certificate) {
@@ -929,20 +900,9 @@
}
if (gerror) {
- GtkWidget* dialog;
-
fatal:
- dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
- GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
- "%s", ("Redwax SignText - Error"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- ("Error: %s"),
- gerror->message);
-
+ signtext_error (instance, gerror);
g_error_free (gerror);
-
- gtk_widget_show (dialog);
-
}
if (certificate) {
@@ -1130,26 +1090,38 @@
//ksba_cert_release (instance->signer);
+ err = ksba_writer_new (&instance->w);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_writer_new failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = ksba_writer_set_cb (instance->w, pem_writer_cb, instance);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_writer_set_cb failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = ksba_cms_set_reader_writer (instance->cms, NULL, instance->w);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_set_reader_writer failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
gcr_pkcs11_certificate_lookup_issuer_async(GCR_CERTIFICATE(instance->certificate), instance->signtext->cancellable, crypto_sign_lookup, instance);
+ g_timeout_add(250, crypto_sign_pulse, instance);
+
gtk_widget_set_visible(GTK_WIDGET(instance->progress), TRUE);
- gtk_progress_bar_pulse (instance->progress);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(instance->selector), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(instance->pin), FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(instance->sign), FALSE);
if (gerror) {
- GtkWidget* dialog;
-
fatal:
- dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
- GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
- "%s", ("Redwax SignText - Error"));
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- ("Error: %s"),
- gerror->message);
-
+ signtext_error (instance, gerror);
g_error_free (gerror);
-
- gtk_widget_show (dialog);
-
}
// if (certificate) {
Modified: redwax-signtext/trunk/src/linux/crypto.h
==============================================================================
--- redwax-signtext/trunk/src/linux/crypto.h (original)
+++ redwax-signtext/trunk/src/linux/crypto.h Sat Sep 10 13:37:56 2022
@@ -34,6 +34,9 @@
void
crypto_sign(SignTextInstance *instance);
+void
+crypto_sign_continue(SignTextInstance *instance);
+
#endif
Modified: redwax-signtext/trunk/src/linux/signtext.c
==============================================================================
--- redwax-signtext/trunk/src/linux/signtext.c (original)
+++ redwax-signtext/trunk/src/linux/signtext.c Sat Sep 10 13:37:56 2022
@@ -145,7 +145,37 @@
// if (instance->sign) g_object_unref(instance->sign);
if (instance->box) g_object_unref(instance->box);
if (instance->certificate) g_object_unref(instance->certificate);
+
+ if (instance->w) {
+ ksba_writer_release(instance->w);
+ }
}
g_free(instance);
}
+/*
+ * Display the error dialog.
+ *
+ * Switch off the progress bar, if it is running.
+ */
+void signtext_error(SignTextInstance *instance, GError *gerror)
+{
+ GtkWidget* dialog;
+
+ if (instance) {
+ gtk_widget_set_visible(GTK_WIDGET(instance->progress), FALSE);
+
+ gtk_widget_set_sensitive(GTK_WIDGET(instance->selector), TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(instance->sign), TRUE);
+ }
+
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ "%s", ("Redwax SignText - Error"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ ("Error: %s"),
+ gerror->message);
+
+ gtk_widget_show (dialog);
+}
+
Modified: redwax-signtext/trunk/src/linux/signtext.h
==============================================================================
--- redwax-signtext/trunk/src/linux/signtext.h (original)
+++ redwax-signtext/trunk/src/linux/signtext.h Sat Sep 10 13:37:56 2022
@@ -101,6 +101,11 @@
const char *hash_oid;
int hash_alg;
gcry_md_hd_t data_md;
+ ksba_writer_t w;
+ ksba_stop_reason_t stopreason;
+
+ gchar *payload;
+ gsize payload_len;
} SignTextInstance;
SignTextData *signtext_data_new();
@@ -112,5 +117,7 @@
SignTextInstance *signtext_instance_new(SignTextData *signtext, gint64 id, const gchar *uuid, GUri *uri);
void signtext_instance_free(SignTextInstance *instance);
+void signtext_error(SignTextInstance *instance, GError *gerror);
+
#endif
More information about the rs-commit
mailing list