Revision: 1938 http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=1938&view=re... Author: alvesh88 Date: 2011-02-26 17:02:33 +0000 (Sat, 26 Feb 2011)
Log Message: ----------- GeanyPG -- GPG encryption plugin first commit
Added Paths: ----------- trunk/geanypg/ trunk/geanypg/src/ trunk/geanypg/src/aux.c trunk/geanypg/src/decrypt_cb.c trunk/geanypg/src/encrypt_cb.c trunk/geanypg/src/geanypg.c trunk/geanypg/src/geanypg.h trunk/geanypg/src/key_selection_dialog.c trunk/geanypg/src/pinentry.c trunk/geanypg/src/sign_cb.c trunk/geanypg/src/verify_aux.c trunk/geanypg/src/verify_cb.c
Added: trunk/geanypg/src/aux.c =================================================================== --- trunk/geanypg/src/aux.c (rev 0) +++ trunk/geanypg/src/aux.c 2011-02-26 17:02:33 UTC (rev 1938) @@ -0,0 +1,163 @@ +// aux.c +// +// Copyright 2011 Hans Alves alves.h88@gmail.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. + + +#include "geanypg.h" + +void geanypg_init_ed(encrypt_data * ed) +{ + ed->key_array = NULL; + ed->nkeys = 0; + ed->skey_array = NULL; + ed->nskeys = 0; +} + +int geanypg_get_keys(encrypt_data * ed) +{ + gpgme_error_t err; + unsigned long size = SIZE; + //initialize index to 0 + unsigned long index = 0; + //allocate array of size 1N + ed->key_array = (gpgme_key_t*) malloc(SIZE * sizeof(gpgme_key_t)); + err = gpgme_op_keylist_start(ed->ctx, NULL, 0); + while (!err) + { + err = gpgme_op_keylist_next(ed->ctx, ed->key_array + index); + if (err) + break; + ++index; + if (index >= size) + { + size += SIZE; + ed->key_array = (gpgme_key_t*) realloc(ed->key_array, size * sizeof(gpgme_key_t)); + } + } + ed->nkeys = index; + if (gpg_err_code(err) != GPG_ERR_EOF) + { + geanypg_show_err_msg(err); + return 0; + } + return 1; +} + +int geanypg_get_secret_keys(encrypt_data * ed) +{ + gpgme_error_t err; + unsigned long size = SIZE; + //initialize index to 0 + unsigned long index = 0; + //allocate array of size 1N + ed->skey_array = (gpgme_key_t*) malloc(SIZE * sizeof(gpgme_key_t)); + err = gpgme_op_keylist_start(ed->ctx, NULL, 1); + while (!err) + { + err = gpgme_op_keylist_next(ed->ctx, ed->skey_array + index); + if (err) + break; + ++index; + if (index >= size) + { + size += SIZE; + ed->skey_array = (gpgme_key_t*) realloc(ed->skey_array, size * sizeof(gpgme_key_t)); + } + } + ed->nskeys = index; + if (gpg_err_code(err) != GPG_ERR_EOF) + { + geanypg_show_err_msg(err); + return 0; + } + return 1; +} + +void geanypg_release_keys(encrypt_data * ed) +{ + gpgme_key_t * ptr; + if (ed->key_array) + { + ptr = ed->key_array; + while (ptr < ed->key_array + ed->nkeys) + gpgme_key_unref(*(ptr++)); + free(ed->key_array); + ed->key_array = NULL; + ed->nkeys = 0; + } + if (ed->skey_array) + { + ptr = ed->skey_array; + while (ptr < ed->skey_array + ed->nskeys) + gpgme_key_unref(*(ptr++)); + free(ed->skey_array); + ed->skey_array = NULL; + ed->nskeys = 0; + } +} + + +void geanypg_load_buffer(gpgme_data_t * buffer) +{ + //gpgme_data_new_from_mem(buffer, text, size, 0); + GeanyDocument * doc = document_get_current(); + //SCI_GETSELECTIONSTART-SCI_GETSELECTIONEND + char * data = NULL; + unsigned long sstart = scintilla_send_message(doc->editor->sci, SCI_GETSELECTIONSTART, 0, 0); + unsigned long send = scintilla_send_message(doc->editor->sci, SCI_GETSELECTIONEND, 0, 0); + unsigned long size = 0; + if (sstart - send) + { + size = scintilla_send_message(doc->editor->sci, SCI_GETSELTEXT, 0, 0); + data = (char *) malloc(size + 1); + scintilla_send_message(doc->editor->sci, SCI_GETSELTEXT, 0, (sptr_t)data); + gpgme_data_new_from_mem(buffer, data, size, 1); + } + else + { + size = scintilla_send_message(doc->editor->sci, SCI_GETLENGTH, 0, 0); + data = (char *) malloc(size + 1); + scintilla_send_message(doc->editor->sci, SCI_GETTEXT, (uptr_t)(size + 1), (sptr_t)data); + gpgme_data_new_from_mem(buffer, data, size, 1); + } + if (data) // if there is no text data may still be NULL + free(data); + gpgme_data_set_encoding(*buffer, GPGME_DATA_ENCODING_BINARY); +} + +void geanypg_write_file(FILE * file) +{ + unsigned bufsize = 2048; + unsigned long size; + char buffer[bufsize]; + GeanyDocument * doc = document_get_current(); + if (abs(sci_get_selection_start(doc->editor->sci) - sci_get_selection_end(doc->editor->sci))) + { // replace selected text + // clear selection, cursor should be at the end or beginneng of the selection + scintilla_send_message(doc->editor->sci, SCI_REPLACESEL, 0, (sptr_t)""); + while ((size = fread(buffer, 1, bufsize, file))) + // add at the cursor + scintilla_send_message(doc->editor->sci, SCI_ADDTEXT, (uptr_t) size, (sptr_t) buffer); + } + else + { //replace complete document + scintilla_send_message(doc->editor->sci, SCI_CLEARALL, 0, 0); + while ((size = fread(buffer, 1, bufsize, file))) + scintilla_send_message(doc->editor->sci, SCI_APPENDTEXT, (uptr_t) size, (sptr_t) buffer); + } +}
Added: trunk/geanypg/src/decrypt_cb.c =================================================================== --- trunk/geanypg/src/decrypt_cb.c (rev 0) +++ trunk/geanypg/src/decrypt_cb.c 2011-02-26 17:02:33 UTC (rev 1938) @@ -0,0 +1,76 @@ +// decrypt_cb.c +// +// Copyright 2011 Hans Alves alves.h88@gmail.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. + + +#include "geanypg.h" + +void geanypg_decrypt_verify(encrypt_data * ed) +{ + gpgme_data_t plain, cipher; + gpgme_error_t err; + FILE * tempfile; + + tempfile = tmpfile(); + if (!(tempfile)) + { + fprintf(stderr, "GEANYPG: couldn't create tempfile: %s.\n", strerror(errno)); + return ; + } + gpgme_data_new_from_stream(&plain, tempfile); + + geanypg_load_buffer(&cipher); + + err = gpgme_op_decrypt_verify(ed->ctx, cipher, plain); + if (gpgme_err_code(err) == GPG_ERR_NO_DATA) // no encription, but maybe signatures + { + // maybe reaload cipher + gpgme_data_release(cipher); + geanypg_load_buffer(&cipher); + rewind(tempfile); + err = gpgme_op_verify(ed->ctx, cipher, NULL, plain); + } + if (err != GPG_ERR_NO_ERROR) + geanypg_show_err_msg(err); + else + { + rewind(tempfile); + geanypg_write_file(tempfile); + geanypg_handle_signatures(ed); + } + + fclose(tempfile); + // release buffers + gpgme_data_release(cipher); + gpgme_data_release(plain); +} + +void geanypg_decrypt_cb(GtkMenuItem * menuitem, gpointer user_data) +{ + encrypt_data ed; + geanypg_init_ed(&ed); + gpgme_error_t err = gpgme_new(&ed.ctx); + if (err && geanypg_show_err_msg(err)) + return; + gpgme_set_protocol(ed.ctx, GPGME_PROTOCOL_OpenPGP); + gpgme_set_passphrase_cb(ed.ctx, geanypg_passphrase_cb, NULL); + if (geanypg_get_keys(&ed) && geanypg_get_secret_keys(&ed)) + geanypg_decrypt_verify(&ed); + geanypg_release_keys(&ed); + gpgme_release(ed.ctx); +}
Added: trunk/geanypg/src/encrypt_cb.c =================================================================== --- trunk/geanypg/src/encrypt_cb.c (rev 0) +++ trunk/geanypg/src/encrypt_cb.c 2011-02-26 17:02:33 UTC (rev 1938) @@ -0,0 +1,83 @@ +// encrypt_cb.c +// +// Copyright 2011 Hans Alves alves.h88@gmail.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. + + +#include "geanypg.h" + +void geanypg_encrypt(encrypt_data * ed, gpgme_key_t * recp, int sign) +{ // FACTORIZE + gpgme_data_t plain, cipher; + gpgme_error_t err; + FILE * tempfile; + tempfile = tmpfile(); + if (!(tempfile)) + { + fprintf(stderr, "GEANYPG: couldn't create tempfile: %s.\n", strerror(errno)); + return ; + } + gpgme_data_new_from_stream(&cipher, tempfile); + gpgme_data_set_encoding(cipher, GPGME_DATA_ENCODING_ARMOR); + + geanypg_load_buffer(&plain); + + // do the actual encryption + if (sign) + err = gpgme_op_encrypt_sign(ed->ctx, recp, 0, plain, cipher); + else + err = gpgme_op_encrypt(ed->ctx, recp, 0, plain, cipher); + if (err != GPG_ERR_NO_ERROR && gpgme_err_code(err) != GPG_ERR_CANCELED) + geanypg_show_err_msg(err); + else + { + rewind(tempfile); + geanypg_write_file(tempfile); + } + + fclose(tempfile); + // release buffers + gpgme_data_release(plain); + gpgme_data_release(cipher); +} + +void geanypg_encrypt_cb(GtkMenuItem * menuitem, gpointer user_data) +{ + int sign; + encrypt_data ed; + geanypg_init_ed(&ed); + gpgme_error_t err = gpgme_new(&ed.ctx); + if (err && geanypg_show_err_msg(err)) + return; + gpgme_set_armor(ed.ctx, 1); + gpgme_set_passphrase_cb(ed.ctx, geanypg_passphrase_cb, NULL); + if (geanypg_get_keys(&ed) && geanypg_get_secret_keys(&ed)) + { + gpgme_key_t * recp = NULL; + if (geanypg_encrypt_selection_dialog(&ed, &recp, &sign)) + { + if (*recp) + geanypg_encrypt(&ed, recp, sign); + else if (dialogs_show_question("No recipients were selected,\nuse symetric cipher?")) + geanypg_encrypt(&ed, NULL, sign); + } + if (recp) + free(recp); + } + geanypg_release_keys(&ed); + gpgme_release(ed.ctx); +}
Added: trunk/geanypg/src/geanypg.c =================================================================== --- trunk/geanypg/src/geanypg.c (rev 0) +++ trunk/geanypg/src/geanypg.c 2011-02-26 17:02:33 UTC (rev 1938) @@ -0,0 +1,110 @@ +// geanypg.c +// +// Copyright 2011 Hans Alves alves.h88@gmail.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. + +#include "geanypg.h" + +/* These items are set by Geany before plugin_init() is called. */ +GeanyPlugin *geany_plugin; +GeanyData *geany_data; +GeanyFunctions *geany_functions; +unsigned long fcounter; +/* Check that the running Geany supports the plugin API version used below, and check + * for binary compatibility. */ +PLUGIN_VERSION_CHECK(201) + +/* All plugins must set name, description, version and author. */ +PLUGIN_SET_INFO(_("GeanyPG"), + _("gpg encryption plugin for geany"), + "0.1", + _("Hans Alves alves.h88@gmail.com")) + +static GtkWidget * main_menu_item = NULL; + +static gpgme_error_t geanypg_init_gpgme(void) +{ + // Initialize the locale environment. + setlocale(LC_ALL, ""); + fprintf(stderr, "GEANYPG: Using libgpgme version: %s\n", + gpgme_check_version("1.1.0")); + gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL)); +#ifdef LC_MESSAGES // only necessary for portability to W32 systems + gpgme_set_locale(NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL)); +#endif + return gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP); +} + +gpgme_error_t geanypg_show_err_msg(gpgme_error_t err) +{ + gchar const * msg = (gchar const *)gpgme_strerror(err); + gchar const * src = (gchar const *)gpgme_strsource(err); + dialogs_show_msgbox(GTK_MESSAGE_ERROR, "Error from %s: %s\n.", src, msg); + fprintf(stderr, "GEANYPG: %s\nFrom %s.\n", msg, src); + return err; +} + +void plugin_init(GeanyData *data) +{ + fcounter = 0; + gpgme_error_t err = geanypg_init_gpgme(); + if (err) + { + geanypg_show_err_msg(err); + return; + } + // Create a new menu item and show it + main_menu_item = gtk_menu_item_new_with_mnemonic("GeanyPG"); + gtk_widget_show(main_menu_item); + + GtkWidget * submenu = gtk_menu_new(); + gtk_widget_show(submenu); + GtkWidget * encrypt = gtk_menu_item_new_with_mnemonic("Encrypt"); + GtkWidget * sign = gtk_menu_item_new_with_mnemonic("Sign"); + GtkWidget * decrypt = gtk_menu_item_new_with_mnemonic("Decrypt / Verify"); + GtkWidget * verify = gtk_menu_item_new_with_mnemonic("Verify detached signature"); + + gtk_widget_show(encrypt); + gtk_widget_show(sign); + gtk_widget_show(decrypt); + gtk_widget_show(verify); + + gtk_menu_append(GTK_MENU(submenu), encrypt); + gtk_menu_append(GTK_MENU(submenu), sign); + gtk_menu_append(GTK_MENU(submenu), decrypt); + gtk_menu_append(GTK_MENU(submenu), verify); + + gtk_menu_item_set_submenu(GTK_MENU_ITEM(main_menu_item), submenu); + + // Attach the new menu item to the Tools menu + gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), + main_menu_item); + + // Connect the menu item with a callback function + // which is called when the item is clicked + g_signal_connect(encrypt, "activate", G_CALLBACK(geanypg_encrypt_cb), NULL); + g_signal_connect(sign, "activate", G_CALLBACK(geanypg_sign_cb), NULL); + g_signal_connect(decrypt, "activate", G_CALLBACK(geanypg_decrypt_cb), NULL); + g_signal_connect(verify, "activate", G_CALLBACK(geanypg_verify_cb), NULL); +} + + +void plugin_cleanup(void) +{ + if (main_menu_item) + gtk_widget_destroy(main_menu_item); +}
Added: trunk/geanypg/src/geanypg.h =================================================================== --- trunk/geanypg/src/geanypg.h (rev 0) +++ trunk/geanypg/src/geanypg.h 2011-02-26 17:02:33 UTC (rev 1938) @@ -0,0 +1,80 @@ +// geanypg.h +// +// Copyright 2011 Hans Alves alves.h88@gmail.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <locale.h> + +#include <geanyplugin.h> +#include <Scintilla.h> +#include <gpgme.h> + +#define SIZE 32 + +enum +{ + READ = 0, + WRITE = 1 +}; + +typedef struct +{ + gpgme_ctx_t ctx; + gpgme_key_t * key_array; + unsigned long nkeys; + gpgme_key_t * skey_array; + unsigned long nskeys; +} encrypt_data; + +extern GeanyPlugin *geany_plugin; +extern GeanyData *geany_data; +extern GeanyFunctions *geany_functions; + +// auxiliary functions (aux.c) +void geanypg_init_ed(encrypt_data * ed); +int geanypg_get_keys(encrypt_data * ed); +int geanypg_get_secret_keys(encrypt_data * ed); +void geanypg_release_keys(encrypt_data * ed); +void geanypg_load_buffer(gpgme_data_t * buffer); +void geanypg_write_file(FILE * file); + +// some more auxiliary functions (verify_aux.c) +void geanypg_handle_signatures(encrypt_data * ed); +void geanypg_check_sig(encrypt_data * ed, gpgme_signature_t sig); + +// dialogs +int geanypg_encrypt_selection_dialog(encrypt_data * ed, gpgme_key_t ** selected, int * sign); +int geanypg_sign_selection_dialog(encrypt_data * ed); +gpgme_error_t geanypg_show_err_msg(gpgme_error_t err); + +// callback functions +void geanypg_encrypt_cb(GtkMenuItem * menuitem, gpointer user_data); +void geanypg_sign_cb(GtkMenuItem * menuitem, gpointer user_data); +void geanypg_decrypt_cb(GtkMenuItem * menuitem, gpointer user_data); +void geanypg_verify_cb(GtkMenuItem * menuitem, gpointer user_data); + +// pinentry callback +gpgme_error_t geanypg_passphrase_cb(void *hook, + const char *uid_hint, + const char *passphrase_info, + int prev_was_bad , + int fd);
Added: trunk/geanypg/src/key_selection_dialog.c =================================================================== --- trunk/geanypg/src/key_selection_dialog.c (rev 0) +++ trunk/geanypg/src/key_selection_dialog.c 2011-02-26 17:02:33 UTC (rev 1938) @@ -0,0 +1,244 @@ +// key_selection_dialog.c +// +// Copyright 2011 Hans Alves alves.h88@gmail.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. + +// something about premature optimization, it still needs to be done + +#include "geanypg.h" + +enum +{ + TOGGLE_COLUMN, + RECIPIENT_COLUMN, + KEYID_COLUMN, + N_COLUMNS +}; + +typedef struct +{ + GtkListStore * store; + gint column; +} listdata; + +static void geanypg_toggled_cb(GtkCellRendererToggle * cell_renderer, + gchar * path, + listdata * udata) +{ + GtkTreeIter iter; + gboolean value; + if (!udata) return; + if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(udata->store), &iter, path)) + { + gtk_tree_model_get(GTK_TREE_MODEL(udata->store), &iter, udata->column, &value, -1); + value = !value; + gtk_list_store_set(udata->store, &iter, udata->column, value, -1); + } +} + +static GtkListStore * geanypg_makelist(gpgme_key_t * key_array, unsigned long nkeys, int addnone) +{ + GtkTreeIter iter; + unsigned long index; + GtkListStore * list = gtk_list_store_new(N_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING); + if (addnone) + { + gtk_list_store_append(list, &iter); + gtk_list_store_set(list, &iter, + TOGGLE_COLUMN, FALSE, + RECIPIENT_COLUMN, "None", + KEYID_COLUMN, "", + -1); + } + for (index = 0; index < nkeys; ++index) + { + char * name = (key_array[index]->uids && key_array[index]->uids->name) ? key_array[index]->uids->name : ""; + char * email = (key_array[index]->uids && key_array[index]->uids->email) ? key_array[index]->uids->email : ""; + char buffer[strlen(name) + strlen(email) + 7]; + sprintf(buffer, "%s <%s>", name, email); + gtk_list_store_append(list, &iter); + gtk_list_store_set(list, &iter, + TOGGLE_COLUMN, FALSE, + RECIPIENT_COLUMN, buffer, + KEYID_COLUMN, key_array[index]->subkeys->keyid, + -1); + } + return list; +} + +static GtkWidget * geanypg_combobox(GtkListStore * list) +{ + GtkWidget * combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(list)); + GtkCellRenderer * cell1 = gtk_cell_renderer_text_new(); + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), cell1, FALSE); + gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combobox), cell1, + "text", RECIPIENT_COLUMN); + return combobox; +} + +static GtkWidget * geanypg_listview(GtkListStore * list, listdata * data) +{ + GtkTreeViewColumn * column; + GtkCellRenderer * togglerenderer, * textrenderer; + GtkWidget * listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(list)); + // checkbox column + togglerenderer = gtk_cell_renderer_toggle_new(); + g_signal_connect(G_OBJECT(togglerenderer), "toggled", G_CALLBACK(geanypg_toggled_cb), NULL); + column = gtk_tree_view_column_new_with_attributes("?", + togglerenderer, + "active", TOGGLE_COLUMN, + NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column); + data->store = list; + data->column = TOGGLE_COLUMN; + g_signal_connect(G_OBJECT(togglerenderer), "toggled", G_CALLBACK(geanypg_toggled_cb), (gpointer) data); + // recipient column + textrenderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes("recipient", + textrenderer, + "text", RECIPIENT_COLUMN, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column); + // keyid column + column = gtk_tree_view_column_new_with_attributes("keyid", + textrenderer, + "text", KEYID_COLUMN, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column); + return listview; +} + +int geanypg_encrypt_selection_dialog(encrypt_data * ed, gpgme_key_t ** selected, int * sign) +{ + GtkWidget * dialog = gtk_dialog_new(); + unsigned long index, sindex, capacity; + int response; + GtkWidget * contentarea, * listview, * scrollwin, * combobox; + GtkTreeIter iter; + listdata data; + gboolean active; + + *sign = 0; + + GtkListStore * list = geanypg_makelist(ed->key_array, ed->nkeys, 0); + listview = geanypg_listview(list, &data); + scrollwin = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollwin), + listview); + gtk_widget_set_size_request(scrollwin, 500, 160); + combobox = geanypg_combobox(geanypg_makelist(ed->skey_array, ed->nskeys, 1)); + + + contentarea = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + gtk_box_pack_start(GTK_BOX(contentarea), gtk_label_new("Please select any recipients"), FALSE, FALSE, 5); + gtk_box_pack_start(GTK_BOX(contentarea), scrollwin, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(contentarea), gtk_label_new("Sign the message as:"), FALSE, FALSE, 5); + gtk_box_pack_start(GTK_BOX(contentarea), combobox, FALSE, FALSE, 0); + + + // add ok and cancel buttons + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK); + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + + gtk_window_set_title(GTK_WINDOW(dialog), "Select recipients"); + gtk_widget_show_all(dialog); + // make sure dialog is destroyed when user responds + response = gtk_dialog_run(GTK_DIALOG(dialog)); + if (response == GTK_RESPONSE_CANCEL) + { + gtk_widget_destroy(dialog); + return 0; + } + index = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox)); + if (index && index <= ed->nskeys) + { + *sign = 1; + gpgme_signers_add(ed->ctx, ed->skey_array[index - 1]); // -1 because the first option is `None' + } + // try to loop all the keys in the list + // if they are active (the user checked the checkbox in front of the key) + // add it to the selected array, finaly make sure that the array + // is NULL terminated + if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(list), &iter)) + { + capacity = SIZE; + *selected = (gpgme_key_t*) malloc(SIZE * sizeof(gpgme_key_t)); + index = 0; + sindex = 0; + gtk_tree_model_get(GTK_TREE_MODEL(list), &iter, TOGGLE_COLUMN, &active, -1); + if (active) + (*selected)[sindex++] = ed->key_array[index]; + + while (gtk_tree_model_iter_next(GTK_TREE_MODEL(list), &iter)) + { + ++index; + gtk_tree_model_get(GTK_TREE_MODEL(list), &iter, TOGGLE_COLUMN, &active, -1); + if (active) + (*selected)[sindex++] = ed->key_array[index]; + if (sindex >= capacity - 1) + { + capacity += SIZE; + *selected = (gpgme_key_t*) realloc(*selected, capacity * sizeof(gpgme_key_t)); + } + } + (*selected)[sindex] = NULL; + } + else + { + gtk_widget_destroy(dialog); + return 0; + } + + gtk_widget_destroy(dialog); + return 1; +} + +int geanypg_sign_selection_dialog(encrypt_data * ed) +{ + GtkWidget * dialog = gtk_dialog_new(); + unsigned long index; + int response; + GtkWidget * contentarea = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + GtkWidget * combobox = geanypg_combobox( + geanypg_makelist(ed->skey_array, ed->nskeys, 0)); + + gtk_box_pack_start(GTK_BOX(contentarea), gtk_label_new("Choose a key to sign with:"), FALSE, FALSE, 5); + gtk_box_pack_start(GTK_BOX(contentarea), combobox, TRUE, TRUE, 0); + + // add ok and cancel buttons + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK); + gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); + + gtk_widget_show_all(dialog); + gtk_window_set_title(GTK_WINDOW(dialog), "Select signer"); + // make sure dialog is destroyed when user responds + response = gtk_dialog_run(GTK_DIALOG(dialog)); + if (response == GTK_RESPONSE_CANCEL) + { + gtk_widget_destroy(dialog); + return 0; + } + index = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox)); + gpgme_signers_clear(ed->ctx); + if (index < ed->nskeys) + gpgme_signers_add(ed->ctx, ed->skey_array[index]); + + gtk_widget_destroy(dialog); + return 1; +}
Added: trunk/geanypg/src/pinentry.c =================================================================== --- trunk/geanypg/src/pinentry.c (rev 0) +++ trunk/geanypg/src/pinentry.c 2011-02-26 17:02:33 UTC (rev 1938) @@ -0,0 +1,194 @@ +// pinentry.c +// +// Copyright 2011 Hans Alves alves.h88@gmail.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. + +#include "geanypg.h" + +static const char * geanypg_getname(const char * uid_hint) +{ + int space = 0; + if (!uid_hint) + return NULL; + while (*uid_hint && !(space && *uid_hint != ' ')) + { + if (*uid_hint == ' ') + space = 1; + ++uid_hint; + } + return uid_hint; +} + +#ifdef __unix__ + +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +static void geanypg_read_till(int fd, char delim) +{ + while (1) + { + char val; + unsigned long rv = read(fd, &val, 1); + if (!rv || val == delim) + break; + } +} + +static int geanypg_read(int fd, char delim, int max, char * buffer) +{ + int index, rv = 1; + char ch = 0; + for (index = 0; (index < max - 1) && rv && ch != delim; ++index) + { + rv = read(fd, &ch, 1); + buffer[index] = ch; + } + buffer[index ? index - 1 : 0] = 0; + return index ? index - 1 : 0; +} +gpgme_error_t geanypg_passphrase_cb(void * hook, + const char * uid_hint, + const char * passphrase_info, + int prev_was_bad , + int fd) +{ + int outpipe[2]; + int inpipe[2]; + int childpid; + int status; + char readbuffer[2080]; // pinentry should at least support passphrases of up to 2048 characters + FILE * childin; + + if (pipe(outpipe)) + { + fprintf(stderr, "GEANYPG: %s\n", strerror(errno)); + return gpgme_error_from_errno(errno); + } + if (pipe(inpipe)) + { + fprintf(stderr, "GEANYPG: %s\n", strerror(errno)); + return gpgme_error_from_errno(errno); + } + + childpid = fork(); + if (!childpid) + { // pinentry + char * argv[] = {"pinentry", NULL}; + + close(outpipe[READ]); + dup2(outpipe[WRITE], STDOUT_FILENO); + + close(inpipe[WRITE]); + dup2(inpipe[READ], STDIN_FILENO); + + execvp(*argv, argv); + // shouldn't get here + fprintf(stderr, "GEANYPG: could not use pinentry.\n%s\n", strerror(errno)); + exit(1); // kill the child + } + // GeanpyPG + close(outpipe[WRITE]); + close(inpipe[READ]); + childin = fdopen(inpipe[WRITE], "w"); + + // To understand what's happening here, read the pinentry documentation + geanypg_read(outpipe[READ], ' ', 2049, readbuffer); + if (strncmp(readbuffer, "OK", 3)) + { + fprintf(stderr, "GEANYPG: unexpected output from pinentry\n"); + fclose(childin); + waitpid(childpid, &status, 0); + close(outpipe[READ]); + close(fd); + return gpgme_err_make(GPG_ERR_SOURCE_PINENTRY, GPG_ERR_GENERAL); + } + geanypg_read_till(outpipe[READ], '\n'); // read the rest of the first line after OK + fprintf(childin, "SETTITLE GeanyPG Passphrase entry\n"); + fflush(childin); + geanypg_read_till(outpipe[READ], '\n'); + + fprintf(childin, "SETPROMPT%s\n", (uid_hint && *uid_hint ? "" : " Passphrase:")); + fflush(childin); + geanypg_read_till(outpipe[READ], '\n'); + + fprintf(childin, "SETDESC %s%s\n", + (uid_hint && *uid_hint ? "Enter passphrase for:%0A" : ""), + (uid_hint && *uid_hint ? geanypg_getname(uid_hint) : "")); + fflush(childin); + geanypg_read_till(outpipe[READ], '\n'); + + fprintf(childin, "GETPIN\n"); + fflush(childin); + + geanypg_read(outpipe[READ], ' ', 2049, readbuffer); + if (!strncmp(readbuffer, "D", 2)) + { + while (1) + { + char val; + register unsigned long rv = read(outpipe[READ], &val, 1); + if (!rv || val == '\n') + { + while (!write(fd, "\n", 1)); + break; + } + while (!write(fd, &val, 1)); + } + } + else + { + unsigned long errval; + if (!strncmp(readbuffer, "ERR", 4)) + { + geanypg_read(outpipe[READ], ' ', 2049, readbuffer); + sscanf(readbuffer, "%lu", &errval); + geanypg_read(outpipe[READ], '\n', 2049, readbuffer); + fprintf(stderr, "GEANYPG: pinentry gave error %lu %s\n", errval, readbuffer); + } + else + fprintf(stderr, "GEANYPG: unexpected error from pinentry\n"); + fclose(childin); + waitpid(childpid, &status, 0); + close(outpipe[READ]); + close(fd); + return gpgme_err_make(GPG_ERR_SOURCE_PINENTRY, + (!strncmp(readbuffer, "canceled", 9) ? GPG_ERR_CANCELED : GPG_ERR_GENERAL)); + } + + + fclose(childin); + waitpid(childpid, &status, 0); + close(outpipe[READ]); + close(fd); + return GPG_ERR_NO_ERROR; +} + +#else + +gpgme_error_t geanypg_passphrase_cb(void *hook, + const char *uid_hint, + const char *passphrase_info, + int prev_was_bad , + int fd) +{ + dialogs_show_msgbox(GTK_MESSAGE_ERROR, "Error, Passphrase input without using gpg-agent is not supported on Windows yet."); + return gpgme_err_make(GPG_ERR_SOURCE_PINENTRY, GPG_ERR_CANCELED); +} +#endif +
Added: trunk/geanypg/src/sign_cb.c =================================================================== --- trunk/geanypg/src/sign_cb.c (rev 0) +++ trunk/geanypg/src/sign_cb.c 2011-02-26 17:02:33 UTC (rev 1938) @@ -0,0 +1,73 @@ +// sign_cb.c +// +// Copyright 2011 Hans Alves alves.h88@gmail.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. + + +#include "geanypg.h" + +void geanypg_sign(encrypt_data * ed) +{ + gpgme_data_t plain, cipher; + gpgme_error_t err; + FILE * tempfile; + + tempfile = tmpfile(); + if (!(tempfile)) + { + fprintf(stderr, "GEANYPG: couldn't create tempfile: %s.\n", strerror(errno)); + return ; + } + gpgme_data_new_from_stream(&cipher, tempfile); + gpgme_data_set_encoding(cipher, GPGME_DATA_ENCODING_ARMOR); + + geanypg_load_buffer(&plain); + + err = gpgme_op_sign(ed->ctx, plain , cipher, GPGME_SIG_MODE_CLEAR); + if (err != GPG_ERR_NO_ERROR && gpgme_err_code(err) != GPG_ERR_CANCELED) + geanypg_show_err_msg(err); + else + { + rewind(tempfile); + geanypg_write_file(tempfile); + } + + fclose(tempfile); + // release buffers + gpgme_data_release(plain); + gpgme_data_release(cipher); +} + +void geanypg_sign_cb(GtkMenuItem * menuitem, gpointer user_data) +{ + encrypt_data ed; + geanypg_init_ed(&ed); + gpgme_error_t err = gpgme_new(&ed.ctx); + if (err && geanypg_show_err_msg(err)) + return; + ed.key_array = NULL; + ed.nkeys = 0; + //gpgme_set_armor(ed.ctx, 1); + gpgme_set_passphrase_cb(ed.ctx, geanypg_passphrase_cb, NULL); + if (geanypg_get_secret_keys(&ed)) + { + if (geanypg_sign_selection_dialog(&ed)) + geanypg_sign(&ed); + } + geanypg_release_keys(&ed); + gpgme_release(ed.ctx); +}
Added: trunk/geanypg/src/verify_aux.c =================================================================== --- trunk/geanypg/src/verify_aux.c (rev 0) +++ trunk/geanypg/src/verify_aux.c 2011-02-26 17:02:33 UTC (rev 1938) @@ -0,0 +1,178 @@ +// verify_aux.c +// +// Copyright 2011 Hans Alves alves.h88@gmail.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. + + +#include "geanypg.h" + + +void geanypg_get_keys_with_fp(encrypt_data * ed, char * buffer) +{ + unsigned long index, found = 0; + for (index = 0; index < ed->nkeys && ! found; ++index) + { + gpgme_subkey_t sub = ed->key_array[index]->subkeys; + while (sub && !found) + { + if (sub->fpr && !strncmp(sub->fpr, buffer, 40)) + { + + char * name = (ed->key_array[index]->uids && ed->key_array[index]->uids->name) ? ed->key_array[index]->uids->name : ""; + char * email = (ed->key_array[index]->uids && ed->key_array[index]->uids->email) ? ed->key_array[index]->uids->email : ""; + if (strlen(name) + strlen(email) < 500) + sprintf(buffer, "%s <%s>", name, email); + else + { + char tmp[62]; + strncpy(tmp, buffer, 41); + sprintf(buffer, "a key with fingerprint %s", tmp); + } + found = 1; + } + sub = sub->next; + } + } +} + +static const char * geanypg_validity(gpgme_sigsum_t summary) +{ + switch (summary) + { + case GPGME_VALIDITY_UNKNOWN: return "unknown"; + case GPGME_VALIDITY_UNDEFINED:return "undefined"; + case GPGME_VALIDITY_NEVER: return "never"; + case GPGME_VALIDITY_MARGINAL: return "marginal"; + case GPGME_VALIDITY_FULL: return "full"; + case GPGME_VALIDITY_ULTIMATE: return "ultimate"; + default : return "[bad validity value]"; + } + return "[bad validity value]"; +} + +static char * geanypg_summary(gpgme_sigsum_t summary, char * buffer) +{ // buffer should be more than 105 bytes long + if (summary & GPGME_SIGSUM_VALID) strcat(buffer, " valid"); + if (summary & GPGME_SIGSUM_GREEN) strcat(buffer, " green"); + if (summary & GPGME_SIGSUM_RED) strcat(buffer, " red"); + if (summary & GPGME_SIGSUM_KEY_REVOKED) strcat(buffer, " revoked"); + if (summary & GPGME_SIGSUM_KEY_EXPIRED) strcat(buffer, " key-expired"); + if (summary & GPGME_SIGSUM_SIG_EXPIRED) strcat(buffer, " sig-expired"); + if (summary & GPGME_SIGSUM_KEY_MISSING) strcat(buffer, " key-missing"); + if (summary & GPGME_SIGSUM_CRL_MISSING) strcat(buffer, " crl-missing"); + if (summary & GPGME_SIGSUM_CRL_TOO_OLD) strcat(buffer, " crl-too-old"); + if (summary & GPGME_SIGSUM_BAD_POLICY) strcat(buffer, " bad-policy"); + if (summary & GPGME_SIGSUM_SYS_ERROR) strcat(buffer, " sys-error"); + return buffer; +} + +static char * geanypg_result(gpgme_signature_t sig) +{ + char format[] = + "status ....: %s\n" + "summary ...:%s\n" + "fingerprint: %s\n" + "created ...: %s" + "expires ...: %s" + "validity ..: %s\n" + "val.reason : %s\n" + "pubkey algo: %s\n" + "digest algo: %s\n" + "pka address: %s\n" + "pka trust .: %s\n" + "other flags:%s%s\n" + "notations .: %s\n"; // 210 characters + char * buffer = (char *)calloc(2048, 1); // everything together probably won't be more + // than 1061 characters, but we don't want to + // take risks + char summary[128]; + const char * pubkey = gpgme_pubkey_algo_name(sig->pubkey_algo); + const char * hash = gpgme_hash_algo_name(sig->hash_algo); + char created[64]; + char expires[64]; + if (sig->timestamp) + strncpy(created, ctime((time_t*)&sig->timestamp), 64); + else + strcpy(created, "Unknown\n"); + + if (sig->exp_timestamp) + strncpy(expires, ctime((time_t*)&sig->exp_timestamp), 64); + else + strcpy(expires, "Unknown\n"); + + memset(summary, 0, 128); + sprintf(buffer, format, + gpgme_strerror(sig->status), // probably won't be more than 128 + geanypg_summary(sig->summary, summary), // max 105 characters + sig->fpr ? sig->fpr : "[None]", // max 40 characters + created, // probably about 24 characters + expires, // probably about 24 characters + geanypg_validity(sig->validity), // max 11 characters + gpgme_strerror(sig->status), // probably won't be more than 128 + pubkey ? pubkey : "Unknown", // probably won't be more than 32 + hash ? hash : "Unknown", // probably won't be more than 32 + sig->pka_address ? sig->pka_address : "[None]", // probably won't be more than 128 + sig->pka_trust == 0 ? "n/a" : sig->pka_trust == 1 ? "bad" : sig->pka_trust == 2 ? "okay": "RFU", // max 4 characters + sig->wrong_key_usage ? " wrong-key-usage" : "", sig->chain_model ? " chain-model" : "", // max 28 characters + sig->notations ? "yes" : "no"); // max 3 characters + return buffer; +} +void geanypg_check_sig(encrypt_data * ed, gpgme_signature_t sig) +{ + GtkWidget * dialog; + gpgme_sigsum_t summary; + char buffer[512]; + strncpy(buffer, sig->fpr, 40); + buffer[40] = 0; + geanypg_get_keys_with_fp(ed, buffer); + summary = sig->summary; + char * result = geanypg_result(sig); + + dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(geany->main_widgets->window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "Found a signature from %s\n<tt>%s</tt>", + buffer, + result); + gtk_window_set_title(GTK_WINDOW(dialog), "Signature"); + + gtk_dialog_run(GTK_DIALOG(dialog)); + free(result); + gtk_widget_destroy(dialog); +} + +void geanypg_handle_signatures(encrypt_data * ed) +{ + int verified = 0; + gpgme_verify_result_t vres = gpgme_op_verify_result(ed->ctx); + if (vres) + { + gpgme_signature_t sig = vres->signatures; + while (sig) + { + geanypg_check_sig(ed, sig); + sig = sig->next; + verified = 1; + } + } + if (!verified) + { + fprintf(stderr, "GEANYPG: could not find verification results\n"); + dialogs_show_msgbox(GTK_MESSAGE_ERROR, "Error, could not find verification results"); + } +}
Added: trunk/geanypg/src/verify_cb.c =================================================================== --- trunk/geanypg/src/verify_cb.c (rev 0) +++ trunk/geanypg/src/verify_cb.c 2011-02-26 17:02:33 UTC (rev 1938) @@ -0,0 +1,81 @@ +// verify_cb.c +// +// Copyright 2011 Hans Alves alves.h88@gmail.com +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. + +#include "geanypg.h" + +char * geanypg_choose_sig() +{ + int response; + char * file = NULL; + GtkWidget * dialog = gtk_file_chooser_dialog_new("Open a signature file", + GTK_WINDOW(geany->main_widgets->window), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_OPEN, GTK_RESPONSE_OK, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + NULL); + gtk_widget_show_all(dialog); + response = gtk_dialog_run(GTK_DIALOG(dialog)); + if (response == GTK_RESPONSE_OK) + file = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + gtk_widget_destroy(dialog); + return file; +} + +void geanypg_verify(encrypt_data * ed, char * signame) +{ + gpgme_data_t sig, text; + gpgme_error_t err; + FILE * sigfile = fopen(signame, "r"); + gpgme_data_new_from_stream(&sig, sigfile); + geanypg_load_buffer(&text); + + err = gpgme_op_verify(ed->ctx, sig, text, NULL); + + if (err != GPG_ERR_NO_ERROR) + geanypg_show_err_msg(err); + else + geanypg_handle_signatures(ed); + + gpgme_data_release(sig); + gpgme_data_release(text); + fclose(sigfile); +} + +void geanypg_verify_cb(GtkMenuItem * menuitem, gpointer user_data) +{ + char * sigfile = NULL; + encrypt_data ed; + geanypg_init_ed(&ed); + gpgme_error_t err = gpgme_new(&ed.ctx); + if (err && geanypg_show_err_msg(err)) + return; + gpgme_set_protocol(ed.ctx, GPGME_PROTOCOL_OpenPGP); + gpgme_set_passphrase_cb(ed.ctx, geanypg_passphrase_cb, NULL); + if (geanypg_get_keys(&ed) && geanypg_get_secret_keys(&ed)) + { + sigfile = geanypg_choose_sig(); + if (sigfile) + { + geanypg_verify(&ed, sigfile); + g_free(sigfile); + } + } + geanypg_release_keys(&ed); + gpgme_release(ed.ctx); +}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.