diff options
Diffstat (limited to 'gcr')
253 files changed, 0 insertions, 50351 deletions
diff --git a/gcr/.gitignore b/gcr/.gitignore deleted file mode 100644 index ff88723d..00000000 --- a/gcr/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/gcr.pc -/gcr-0.pc -/gcr-3.pc -/gcr-viewer.desktop -/gcr-viewer.desktop.in -/Gcr-3.0.gir -/Gcr-3.0.typelib diff --git a/gcr/Makefile.am b/gcr/Makefile.am deleted file mode 100644 index f1fd40b7..00000000 --- a/gcr/Makefile.am +++ /dev/null @@ -1,376 +0,0 @@ -SUBDIRS = . icons tests - -# ------------------------------------------------------------------ -# UI BUILDER -# - -uidir = $(datadir)/gcr-@GCR_MAJOR@/ui/ - -ui_DATA = \ - gcr-pkcs11-import-dialog.ui \ - gcr-unlock-options-widget.ui - -# ------------------------------------------------------------------ -# HEADERS - -HEADER_BASE_FILES = \ - gcr-base.h \ - gcr-certificate.h \ - gcr-certificate-chain.h \ - gcr-collection.h \ - gcr-comparable.h \ - gcr-deprecated-base.h \ - gcr-fingerprint.h \ - gcr-icons.h \ - gcr-importer.h \ - gcr-import-interaction.h \ - gcr-library.h \ - gcr-parser.h \ - gcr-pkcs11-certificate.h \ - gcr-secret-exchange.h \ - gcr-simple-certificate.h \ - gcr-trust.h \ - gcr-types.h \ - gcr-union-collection.h \ - gcr-unlock-options.h - -HEADER_UI_FILES = \ - gcr.h \ - gcr-certificate-basics-widget.h \ - gcr-certificate-details-widget.h \ - gcr-certificate-renderer.h \ - gcr-certificate-widget.h \ - gcr-collection-model.h \ - gcr-column.h \ - gcr-combo-selector.h \ - gcr-deprecated.h \ - gcr-failure-renderer.h \ - gcr-key-renderer.h \ - gcr-key-widget.h \ - gcr-import-button.h \ - gcr-list-selector.h \ - gcr-renderer.h \ - gcr-simple-collection.h \ - gcr-tree-selector.h \ - gcr-unlock-options-widget.h \ - gcr-viewer.h \ - gcr-viewer-widget.h - -incdir = $(includedir)/gcr-@GCR_MAJOR@/gcr - -inc_HEADERS = \ - $(HEADER_BASE_FILES) \ - $(HEADER_UI_FILES) \ - gcr-enum-types-base.h \ - gcr-enum-types.h - -# ------------------------------------------------------------------ -# LIBRARY - -INCLUDES = \ - -I$(top_builddir) \ - -I$(top_srcdir) \ - $(GOBJECT_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(LIBGCRYPT_CFLAGS) \ - $(P11_KIT_CFLAGS) \ - -DG_LOG_DOMAIN=\"Gcr\" - -lib_LTLIBRARIES = \ - libgcr-base-@GCR_MAJOR@.la \ - libgcr-@GCR_MAJOR@.la - -BUILT_BASE_FILES = \ - gcr-marshal.c gcr-marshal.h \ - gcr-enum-types-base.c gcr-enum-types-base.h \ - gcr-oids.c gcr-oids.h - -BUILT_UI_FILES = \ - gcr-marshal.c gcr-marshal.h \ - gcr-enum-types.c gcr-enum-types.h \ - gcr-oids.c gcr-oids.h - -BUILT_SOURCES = \ - $(BUILT_BASE_FILES) \ - $(BUILT_UI_FILES) - -libgcr_base_@GCR_MAJOR@_la_SOURCES = \ - gcr-callback-output-stream.c gcr-callback-output-stream.h \ - gcr-certificate.c gcr-certificate.h \ - gcr-certificate-chain.c gcr-certificate-chain.h \ - gcr-collection.c gcr-collection.h \ - gcr-comparable.c gcr-comparable.h \ - gcr-debug.c gcr-debug.h \ - gcr-fingerprint.c gcr-fingerprint.h \ - gcr-gnupg-collection.c gcr-gnupg-collection.h \ - gcr-gnupg-importer.c gcr-gnupg-importer.h \ - gcr-gnupg-key.c gcr-gnupg-key.h \ - gcr-gnupg-process.c gcr-gnupg-process.h \ - gcr-gnupg-records.c gcr-gnupg-records.h \ - gcr-gnupg-util.c gcr-gnupg-util.h \ - gcr-icons.c gcr-icons.h \ - gcr-importer.c gcr-importer.h \ - gcr-import-interaction.c gcr-import-interaction.h \ - gcr-internal.h \ - gcr-library.c gcr-library.h \ - gcr-memory.c \ - gcr-memory-icon.c gcr-memory-icon.h \ - gcr-openpgp.c gcr-openpgp.h \ - gcr-openssh.c gcr-openssh.h \ - gcr-parser.c gcr-parser.h \ - gcr-pkcs11-certificate.c gcr-pkcs11-certificate.h \ - gcr-pkcs11-importer.c gcr-pkcs11-importer.h \ - gcr-record.c gcr-record.h \ - gcr-secret-exchange.c gcr-secret-exchange.h \ - gcr-simple-certificate.c gcr-simple-certificate.h \ - gcr-simple-collection.c gcr-simple-collection.h \ - gcr-single-collection.c gcr-single-collection.h \ - gcr-trust.c gcr-trust.h \ - gcr-types.h \ - gcr-union-collection.c gcr-union-collection.h \ - gcr-util.c gcr-util.h \ - $(BUILT_BASE_FILES) - -libgcr_@GCR_MAJOR@_la_SOURCES = \ - gcr-certificate-basics-widget.c gcr-certificate-basics-widget.h \ - gcr-certificate-details-widget.c gcr-certificate-details-widget.h \ - gcr-certificate-exporter.c gcr-certificate-exporter.h \ - gcr-certificate-extensions.c gcr-certificate-extensions.h \ - gcr-certificate-renderer.c gcr-certificate-renderer.h \ - gcr-certificate-widget.c gcr-certificate-widget.h \ - gcr-collection-model.c gcr-collection-model.h \ - gcr-combo-selector.c gcr-combo-selector.h \ - gcr-debug.c gcr-debug.h \ - gcr-dialog-util.c gcr-dialog-util.h \ - gcr-display-scrolled.c gcr-display-scrolled.h \ - gcr-display-view.c gcr-display-view.h \ - gcr-failure-renderer.c gcr-failure-renderer.h \ - gcr-gnupg-renderer.c gcr-gnupg-renderer.h \ - gcr-gnupg-records.c gcr-gnupg-records.h \ - gcr-import-button.c gcr-import-button.h \ - gcr-key-renderer.c gcr-key-renderer.h \ - gcr-key-widget.c gcr-key-widget.h \ - gcr-list-selector.c gcr-list-selector.h gcr-list-selector-private.h \ - gcr-live-search.c gcr-live-search.h \ - gcr-memory.c \ - gcr-memory-icon.c gcr-memory-icon.h \ - gcr-menu-button.c gcr-menu-button.h \ - gcr-pkcs11-import-interaction.c gcr-pkcs11-import-interaction.h \ - gcr-pkcs11-import-dialog.c gcr-pkcs11-import-dialog.h \ - gcr-record.c gcr-record.h \ - gcr-renderer.c gcr-renderer.h \ - gcr-tree-selector.c gcr-tree-selector.h \ - gcr-unlock-options.h \ - gcr-unlock-options-widget.c gcr-unlock-options-widget.h \ - gcr-unlock-renderer.c gcr-unlock-renderer.h \ - gcr-viewer.c gcr-viewer.h \ - gcr-viewer-widget.c gcr-viewer-widget.h \ - gcr-viewer-window.c gcr-viewer-window.h \ - $(BUILT_UI_FILES) - -libgcr_base_@GCR_MAJOR@_la_CFLAGS = \ - -DGCK_API_SUBJECT_TO_CHANGE \ - -DGCR_API_SUBJECT_TO_CHANGE \ - -DP11_KIT_API_SUBJECT_TO_CHANGE \ - -DGCR_COMPILATION - -libgcr_@GCR_MAJOR@_la_CFLAGS = \ - $(GTK_CFLAGS) \ - -DUIDIR=\""$(uidir)"\" \ - $(libgcr_base_@GCR_MAJOR@_la_CFLAGS) - -libgcr_base_@GCR_MAJOR@_la_LDFLAGS = \ - -version-info $(GCR_LT_RELEASE) \ - -no-undefined \ - -export-symbols-regex '^gcr_*' - -libgcr_@GCR_MAJOR@_la_LDFLAGS = \ - $(libgcr_base_@GCR_MAJOR@_la_LDFLAGS) - -libgcr_base_@GCR_MAJOR@_la_LIBADD = \ - $(top_builddir)/egg/libegg.la \ - $(top_builddir)/gck/libgck-@GCK_MAJOR@.la \ - $(GOBJECT_LIBS) \ - $(GLIB_LIBS) \ - $(LIBGCRYPT_LIBS) \ - $(P11_KIT_LIBS) - -libgcr_@GCR_MAJOR@_la_LIBADD = \ - $(GTK_LIBS) \ - $(libgcr_base_@GCR_MAJOR@_la_LIBADD) \ - $(top_builddir)/egg/libegg-entry-buffer.la \ - $(builddir)/libgcr-base-$(GCR_MAJOR).la - -noinst_LTLIBRARIES = libgcr-testable.la -libgcr_testable_la_SOURCES = -libgcr_testable_la_LIBADD = \ - $(libgcr_base_@GCR_MAJOR@_la_OBJECTS) \ - $(libgcr_@GCR_MAJOR@_la_OBJECTS) \ - $(libgcr_@GCR_MAJOR@_la_LIBADD) -libgcr_testable_la_DEPENDENCIES = \ - $(libgcr_base_@GCR_MAJOR@_la_OBJECTS) \ - $(libgcr_@GCR_MAJOR@_la_OBJECTS) - -gcr-marshal.h: gcr-marshal.list $(GLIB_GENMARSHAL) - $(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=_gcr_marshal > $@ - -gcr-marshal.c: gcr-marshal.list $(GLIB_GENMARSHAL) - $(AM_V_GEN) ( echo "#include \"gcr-marshal.h\"" > $@ && \ - $(GLIB_GENMARSHAL) $< --body --prefix=_gcr_marshal >> $@ ) - -gcr-enum-types.h: $(HEADER_UI_FILES) gcr-enum-types.h.template - $(AM_V_GEN) $(GLIB_MKENUMS) --template $(srcdir)/gcr-enum-types.h.template \ - $(HEADER_UI_FILES) > $@ - -gcr-enum-types.c: $(HEADER_UI_FILES) gcr-enum-types.c.template - $(AM_V_GEN) $(GLIB_MKENUMS) --template $(srcdir)/gcr-enum-types.c.template \ - $(HEADER_UI_FILES) > $@ - -gcr-enum-types-base.h: $(HEADER_BASE_FILES) gcr-enum-types.h.template - $(AM_V_GEN) $(GLIB_MKENUMS) --template $(srcdir)/gcr-enum-types.h.template \ - $(HEADER_BASE_FILES) > $@ - -gcr-enum-types-base.c: $(HEADER_BASE_FILES) gcr-enum-types.c.template - $(AM_V_GEN) $(GLIB_MKENUMS) --template $(srcdir)/gcr-enum-types.c.template \ - $(HEADER_BASE_FILES) > $@ - -gcr-oids.c: gcr-oids.list gcr-mkoids - $(AM_V_GEN) sh gcr-mkoids -p GCR -c gcr-oids.c -h gcr-oids.h gcr-oids.list - -gcr-oids.h: gcr-oids.c - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = gcr-$(GCR_MAJOR).pc gcr-base-$(GCR_MAJOR).pc - -gcr-$(GCR_MAJOR).pc: gcr.pc - cp gcr.pc gcr-$(GCR_MAJOR).pc -gcr-base-$(GCR_MAJOR).pc: gcr-base.pc - cp gcr-base.pc gcr-base-$(GCR_MAJOR).pc - -# ---------------------------------------------------------------- -# SYSTEM INTEGRATION - -# The new mime system -mimedir = $(datadir)/mime/packages -mime_DATA = gcr-crypto-types.xml - -if WITH_UPDATE_MIME -update_mime_database_cmd = update-mime-database $(datadir)/mime/ - -install-data-hook: update_mime_database -uninstall-hook: update_mime_database - -update_mime_database: - @-if test -z "$(DESTDIR)"; then \ - echo "Updating MIME database."; \ - $(update_mime_database_cmd); \ - else \ - echo "*** MIME database not updated. After (un)install, run this:"; \ - echo "*** $(update_mime_database_cmd)"; \ - fi -endif - -desktopdir = $(datadir)/applications -desktop_in_in_files = gcr-viewer.desktop.in.in -desktop_in_files = $(desktop_in_in_files:.desktop.in.in=.desktop.in) -desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) -@INTLTOOL_DESKTOP_RULE@ - -# ---------------------------------------------------------------- -# TOOLS - -bin_PROGRAMS = gcr-viewer - -gcr_viewer_SOURCES = \ - gcr-viewer-tool.c - -gcr_viewer_CFLAGS = \ - $(GTK_CFLAGS) \ - -DLOCALEDIR=\""$(datadir)/locale"\" \ - -DGCR_API_SUBJECT_TO_CHANGE - -gcr_viewer_LDADD = \ - $(builddir)/libgcr-$(GCR_MAJOR).la \ - $(top_builddir)/gck/libgck-@GCK_MAJOR@.la \ - $(GTK_LIBS) - -# ------------------------------------------------------------------ -# INTROSPECTION - -if HAVE_INTROSPECTION - -include $(INTROSPECTION_MAKEFILE) - -INTROSPECTION_GIRS = Gcr-@GCR_MAJOR@.gir -INTROSPECTION_SCANNER_ARGS = $(INTROSPECTION_FLAGS) --warn-all --add-include-path=$(srcdir) --add-include-path=$(top_builddir)/gck -INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir) --includedir=$(top_builddir)/gck - -Gcr-@GCR_MAJOR@.gir: libgcr-@GCR_MAJOR@.la - -Gcr_@GCR_MAJOR@_gir_PACKAGES = gobject-2.0 gtk+-3.0 p11-kit-1 -Gcr_@GCR_MAJOR@_gir_EXPORT_PACKAGES = gcr-3 -Gcr_@GCR_MAJOR@_gir_INCLUDES = GObject-2.0 Gtk-3.0 Gck-@GCK_MAJOR@ -Gcr_@GCR_MAJOR@_gir_LIBS = libgcr-base-@GCR_MAJOR@.la libgcr-@GCR_MAJOR@.la -Gcr_@GCR_MAJOR@_gir_CFLAGS = -I$(top_srcdir) -I$(top_builddir) -DGCR_COMPILATION -DGCR_API_SUBJECT_TO_CHANGE -Gcr_@GCR_MAJOR@_gir_FILES = $(libgcr_base_@GCR_MAJOR@_la_SOURCES) $(libgcr_@GCR_MAJOR@_la_SOURCES) -Gcr_@GCR_MAJOR@_gir_SCANNERFLAGS = --c-include "gcr.h" --c-include "gcr-base.h" - -girdir = $(datadir)/gir-1.0 -gir_DATA = $(INTROSPECTION_GIRS) - -typelibsdir = $(libdir)/girepository-1.0 -typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib) - -endif - -# ---------------------------------------------------------------- - -gcr-expected-base.abi: gcr-base.symbols - $(AM_V_GEN) cpp -P $< | sort > $@ -gcr-expected.abi: gcr.symbols - $(AM_V_GEN) cpp -P $< | sort > $@ - -gcr-actual-base.abi: $(builddir)/.libs/libgcr-base-@GCR_MAJOR@.so - $(AM_V_GEN) $(NM) -D -g --defined-only $< | \ - cut -d ' ' -f 3 | grep -Ev '^(__bss_start|_edata|_end)' | sort > $@ -gcr-actual.abi: $(builddir)/.libs/libgcr-@GCR_MAJOR@.so - $(AM_V_GEN) $(NM) -D -g --defined-only $< | \ - cut -d ' ' -f 3 | grep -Ev '^(__bss_start|_edata|_end)' | sort > $@ - -check-symbols: gcr-expected.abi gcr-actual.abi gcr-expected-base.abi gcr-actual-base.abi - $(AM_V_GEN) diff -U0 --ignore-blank-lines gcr-expected-base.abi gcr-actual-base.abi || \ - (echo "check-symbols: Symbols have CHANGED. Fix gcr-base.symbols"; exit 1) - $(AM_V_GEN) diff -U0 --ignore-blank-lines gcr-expected.abi gcr-actual.abi || \ - (echo "check-symbols: Symbols have CHANGED. Fix gcr.symbols"; exit 1) - -check-local: check-symbols - -EXTRA_DIST = \ - gcr.pc.in \ - gcr-base.pc.in \ - gcr-marshal.list \ - gcr-oids.list \ - gcr-mkoids \ - $(ui_DATA) \ - $(conf_DATA) \ - gcr-enum-types.h.template \ - gcr-enum-types.c.template \ - gcr.symbols \ - gcr-base.symbols \ - $(desktop_in_in_files) \ - $(desktop_in_files) \ - $(desktop_DATA) \ - $(mime_DATA) - -CLEANFILES = \ - $(BUILT_SOURCES) \ - $(pkgconfig_DATA) \ - gcr-actual.abi \ - gcr-actual-base.abi \ - gcr-expected.abi \ - gcr-expected-base.abi - -DISTCLEANFILES = \ - $(desktop_in_files) \ - $(desktop_DATA) \ - $(pkgconfig_DATA) diff --git a/gcr/gcr-base.h b/gcr/gcr-base.h deleted file mode 100644 index 69133f11..00000000 --- a/gcr/gcr-base.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef GCR_API_SUBJECT_TO_CHANGE -#error "This API has not yet reached stability." -#endif - -#ifndef __GCR_BASE_H__ -#define __GCR_BASE_H__ - -#include <glib.h> - -#define __GCR_INSIDE_HEADER__ - -#include "gcr-types.h" - -#include "gcr-certificate.h" -#include "gcr-certificate-chain.h" -#include "gcr-deprecated-base.h" -#include "gcr-enum-types-base.h" -#include "gcr-icons.h" -#include "gcr-importer.h" -#include "gcr-library.h" -#include "gcr-parser.h" -#include "gcr-pkcs11-certificate.h" -#include "gcr-secret-exchange.h" -#include "gcr-simple-certificate.h" -#include "gcr-simple-collection.h" -#include "gcr-trust.h" -#include "gcr-union-collection.h" -#include "gcr-unlock-options.h" - -#undef __GCR_INSIDE_HEADER__ - -#endif /* __GCR_BASE_H__ */ diff --git a/gcr/gcr-base.pc.in b/gcr/gcr-base.pc.in deleted file mode 100644 index 629882ab..00000000 --- a/gcr/gcr-base.pc.in +++ /dev/null @@ -1,16 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -datarootdir=@datarootdir@ -datadir=@datadir@ -sysconfdir=@sysconfdir@ -pkcs11dir=@P11_MODULE_PATH@ -pkcs11standalonedir=@pkcs11standalonedir@ - -Name: gcr-base-@GCR_MAJOR@ -Description: GObject library for high level crypto parsing -Version: @VERSION@ -Requires: glib-2.0 gck-@GCK_MAJOR@ p11-kit-1 -Libs: -L${libdir} -lgcr-base-@GCR_MAJOR@ -Cflags: -I${includedir}/gcr-@GCR_MAJOR@ diff --git a/gcr/gcr-base.symbols b/gcr/gcr-base.symbols deleted file mode 100644 index 0d48bd1f..00000000 --- a/gcr/gcr-base.symbols +++ /dev/null @@ -1,157 +0,0 @@ -/* This file lists all exported symbols. It is used to guarantee that we - * only consciously change our ABI. - */ - -gcr_certificate_compare -gcr_certificate_chain_add -gcr_certificate_chain_build -gcr_certificate_chain_build_async -gcr_certificate_chain_build_finish -gcr_certificate_chain_flags_get_type -gcr_certificate_chain_get_anchor -gcr_certificate_chain_get_certificate -gcr_certificate_chain_get_endpoint -gcr_certificate_chain_get_length -gcr_certificate_chain_get_status -gcr_certificate_chain_get_type -gcr_certificate_chain_new -gcr_certificate_chain_status_get_type -gcr_certificate_get_columns -gcr_certificate_get_der_data -gcr_certificate_get_expiry_date -gcr_certificate_get_fingerprint -gcr_certificate_get_fingerprint_hex -gcr_certificate_get_icon -gcr_certificate_get_issued_date -gcr_certificate_get_issuer_cn -gcr_certificate_get_issuer_dn -gcr_certificate_get_issuer_part -gcr_certificate_get_issuer_raw -gcr_certificate_get_key_size -gcr_certificate_get_serial_number -gcr_certificate_get_serial_number_hex -gcr_certificate_get_subject_cn -gcr_certificate_get_subject_dn -gcr_certificate_get_subject_part -gcr_certificate_get_subject_raw -gcr_certificate_get_type -gcr_certificate_mixin_class_init -gcr_certificate_mixin_comparable_init -gcr_certificate_mixin_get_property -gcr_certificate_is_issuer -gcr_collection_contains -gcr_collection_emit_added -gcr_collection_emit_removed -gcr_collection_get_length -gcr_collection_get_objects -gcr_collection_get_type -gcr_comparable_compare -gcr_comparable_get_type -gcr_comparable_memcmp -gcr_data_error_get_domain -gcr_data_error_get_type -gcr_data_format_get_type -gcr_error_get_domain -gcr_fingerprint_from_attributes -gcr_fingerprint_from_certificate_public_key -gcr_fingerprint_from_subject_public_key_info -gcr_icon_for_token -gcr_importer_create_for_parsed -gcr_importer_get_interaction -gcr_importer_get_parser -gcr_importer_get_prompt_behavior -gcr_importer_get_slot -gcr_importer_get_type -gcr_importer_import -gcr_importer_import_async -gcr_importer_import_finish -gcr_importer_prompt_behavior_get_type -gcr_importer_queue_and_filter_for_parsed -gcr_importer_queue_for_parsed -gcr_importer_register -gcr_importer_register_well_known -gcr_importer_set_interaction -gcr_importer_set_parser -gcr_importer_set_prompt_behavior -gcr_importer_set_slot -gcr_import_interaction_get_type -gcr_import_interaction_supplement -gcr_import_interaction_supplement_async -gcr_import_interaction_supplement_finish -gcr_import_interaction_supplement_prep -gcr_parsed_get_attributes -gcr_parsed_get_data -gcr_parsed_get_description -gcr_parsed_get_format -gcr_parsed_get_label -gcr_parsed_get_type -gcr_parsed_ref -gcr_parsed_unref -gcr_parser_add_password -gcr_parser_format_disable -gcr_parser_format_enable -gcr_parser_format_supported -gcr_parser_get_parsed -gcr_parser_get_parsed_attributes -gcr_parser_get_parsed_block -gcr_parser_get_parsed_description -gcr_parser_get_parsed_format -gcr_parser_get_parsed_label -gcr_parser_get_type -gcr_parser_new -gcr_parser_parse_data -gcr_parser_parse_stream -gcr_parser_parse_stream_async -gcr_parser_parse_stream_finish -gcr_pkcs11_add_module -gcr_pkcs11_add_module_from_file -gcr_pkcs11_certificate_get_attributes -gcr_pkcs11_certificate_get_type -gcr_pkcs11_certificate_lookup_issuer -gcr_pkcs11_certificate_lookup_issuer_async -gcr_pkcs11_certificate_lookup_issuer_finish -gcr_pkcs11_get_modules -gcr_pkcs11_get_trust_lookup_slots -gcr_pkcs11_get_trust_lookup_uris -gcr_pkcs11_get_trust_store_slot -gcr_pkcs11_get_trust_store_uri -gcr_pkcs11_initialize -gcr_pkcs11_initialize_async -gcr_pkcs11_initialize_finish -gcr_pkcs11_set_modules -gcr_pkcs11_set_trust_lookup_uris -gcr_pkcs11_set_trust_store_uri -gcr_secret_exchange_begin -gcr_secret_exchange_get_protocol -gcr_secret_exchange_get_secret -gcr_secret_exchange_get_type -gcr_secret_exchange_new -gcr_secret_exchange_receive -gcr_secret_exchange_send -gcr_simple_certificate_get_type -gcr_simple_certificate_new -gcr_simple_certificate_new_static -gcr_simple_collection_add -gcr_simple_collection_contains -gcr_simple_collection_get_type -gcr_simple_collection_new -gcr_simple_collection_remove -gcr_trust_add_pinned_certificate -gcr_trust_add_pinned_certificate_async -gcr_trust_add_pinned_certificate_finish -gcr_trust_is_certificate_anchored -gcr_trust_is_certificate_anchored_async -gcr_trust_is_certificate_anchored_finish -gcr_trust_is_certificate_pinned -gcr_trust_is_certificate_pinned_async -gcr_trust_is_certificate_pinned_finish -gcr_trust_remove_pinned_certificate -gcr_trust_remove_pinned_certificate_async -gcr_trust_remove_pinned_certificate_finish -gcr_union_collection_add -gcr_union_collection_get_type -gcr_union_collection_have -gcr_union_collection_new -gcr_union_collection_remove -gcr_union_collection_size -gcr_union_collection_take diff --git a/gcr/gcr-callback-output-stream.c b/gcr/gcr-callback-output-stream.c deleted file mode 100644 index 91bdbf3f..00000000 --- a/gcr/gcr-callback-output-stream.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-callback-output-stream.h" -#define DEBUG_FLAG GCR_DEBUG_GNUPG -#include "gcr-debug.h" - -#include <glib/gi18n.h> - -struct _GcrCallbackOutputStream { - GOutputStream parent; - GcrCallbackOutputFunc callback; - gpointer user_data; - GDestroyNotify destroy_func; -}; - -struct _GcrCallbackOutputStreamClass { - GOutputStreamClass parent_class; -}; - -G_DEFINE_TYPE (GcrCallbackOutputStream, _gcr_callback_output_stream, G_TYPE_OUTPUT_STREAM); - -static void -_gcr_callback_output_stream_init (GcrCallbackOutputStream *self) -{ - -} - -static gssize -_gcr_callback_output_stream_write (GOutputStream *stream, - const void *buffer, - gsize count, - GCancellable *cancellable, - GError **error) -{ - GcrCallbackOutputStream *self = GCR_CALLBACK_OUTPUT_STREAM (stream); - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) { - return -1; - } else if (self->callback == NULL) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED, - _("The stream was closed")); - return -1; - } - - return (self->callback) (buffer, count, cancellable, self->user_data, error); -} - -static gboolean -_gcr_callback_output_stream_close (GOutputStream *stream, - GCancellable *cancellable, - GError **error) -{ - GcrCallbackOutputStream *self = GCR_CALLBACK_OUTPUT_STREAM (stream); - if (g_cancellable_set_error_if_cancelled (cancellable, error)) { - return FALSE; - } else if (self->callback == NULL) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED, - _("The stream was closed")); - return FALSE; - } - - if (self->destroy_func != NULL) - (self->destroy_func) (self->user_data); - self->destroy_func = NULL; - self->user_data = NULL; - self->callback = NULL; - - return TRUE; -} - -static void -_gcr_callback_output_stream_dispose (GObject *obj) -{ - _gcr_callback_output_stream_close (G_OUTPUT_STREAM (obj), NULL, NULL); - G_OBJECT_CLASS (_gcr_callback_output_stream_parent_class)->dispose (obj); -} - -static void -_gcr_callback_output_stream_class_init (GcrCallbackOutputStreamClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GOutputStreamClass *output_class = G_OUTPUT_STREAM_CLASS (klass); - - gobject_class->dispose = _gcr_callback_output_stream_dispose; - output_class->write_fn = _gcr_callback_output_stream_write; - output_class->close_fn = _gcr_callback_output_stream_close; -} - -/** - * _gcr_callback_output_stream_new: (skip) - * - * Returns: (transfer full) (type Gcr.CallbackOutputStream): the new stream - */ -GOutputStream * -_gcr_callback_output_stream_new (GcrCallbackOutputFunc callback, - gpointer user_data, - GDestroyNotify destroy_func) -{ - GcrCallbackOutputStream *self; - - g_return_val_if_fail (callback, NULL); - - self = g_object_new (GCR_TYPE_CALLBACK_OUTPUT_STREAM, NULL); - self->callback = callback; - self->user_data = user_data; - self->destroy_func = destroy_func; - - return G_OUTPUT_STREAM (self); -} diff --git a/gcr/gcr-callback-output-stream.h b/gcr/gcr-callback-output-stream.h deleted file mode 100644 index 51d618e5..00000000 --- a/gcr/gcr-callback-output-stream.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef GCR_CALLBACK_OUTPUT_STREAM_H -#define GCR_CALLBACK_OUTPUT_STREAM_H - -#include "gcr-base.h" -#include "gcr-collection.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_CALLBACK_OUTPUT_STREAM (_gcr_callback_output_stream_get_type ()) -#define GCR_CALLBACK_OUTPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CALLBACK_OUTPUT_STREAM, GcrCallbackOutputStream)) -#define GCR_CALLBACK_OUTPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CALLBACK_OUTPUT_STREAM, GcrCallbackOutputStreamClass)) -#define GCR_IS_CALLBACK_OUTPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CALLBACK_OUTPUT_STREAM)) -#define GCR_IS_CALLBACK_OUTPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CALLBACK_OUTPUT_STREAM)) -#define GCR_CALLBACK_OUTPUT_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CALLBACK_OUTPUT_STREAM, GcrCallbackOutputStreamClass)) - -typedef struct _GcrCallbackOutputStream GcrCallbackOutputStream; -typedef struct _GcrCallbackOutputStreamClass GcrCallbackOutputStreamClass; - -GType _gcr_callback_output_stream_get_type (void); - -typedef gssize (*GcrCallbackOutputFunc) (gconstpointer buffer, - gsize count, - GCancellable *cancellable, - gpointer user_data, - GError **error); - -GOutputStream * _gcr_callback_output_stream_new (GcrCallbackOutputFunc callback, - gpointer user_data, - GDestroyNotify destroy_func); - -G_END_DECLS - -#endif /* GCR_CALLBACK_OUTPUT_STREAM_H */ diff --git a/gcr/gcr-certificate-basics-widget.c b/gcr/gcr-certificate-basics-widget.c deleted file mode 100644 index f1d45283..00000000 --- a/gcr/gcr-certificate-basics-widget.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" -#include "gcr-certificate-basics-widget.h" - -#ifndef GCR_DISABLE_DEPRECATED - -/* These are all stubs for GcrCertificateWidget */ - -GType -gcr_certificate_basics_widget_get_type (void) -{ - return gcr_certificate_widget_get_type (); -} - -/** - * gcr_certificate_basics_widget_new: (skip) - * - * Deprecated: Since 2.30 - * - * Returns: (transfer full) (type Gcr.CertificateWidget): a new certificate widget - */ -GcrCertificateBasicsWidget * -gcr_certificate_basics_widget_new (GcrCertificate *cert) -{ - return gcr_certificate_widget_new (cert); -} - -/** - * gcr_certificate_basics_widget_get_certificate: (skip) - * - * Deprecated: Since 2.30 - * - * Returns: (transfer none): the certificate - */ -GcrCertificate * -gcr_certificate_basics_widget_get_certificate (GcrCertificateBasicsWidget *basics) -{ - return gcr_certificate_widget_get_certificate (basics); -} - -/** - * gcr_certificate_basics_widget_set_certificate: (skip) - * @basics: the certificate widget - * @cert: the certificate - * - * Deprecated: Since 2.30 - */ -void -gcr_certificate_basics_widget_set_certificate (GcrCertificateBasicsWidget *basics, - GcrCertificate *cert) -{ - return gcr_certificate_widget_set_certificate (basics, cert); -} - -#endif /* GCR_DISABLE_DEPRECATED */ diff --git a/gcr/gcr-certificate-basics-widget.h b/gcr/gcr-certificate-basics-widget.h deleted file mode 100644 index 4dee8e5d..00000000 --- a/gcr/gcr-certificate-basics-widget.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_CERTIFICATE_BASICS_WIDGET_H__ -#define __GCR_CERTIFICATE_BASICS_WIDGET_H__ - -/* - * GcrCertificateBasicsWidget has been replaced with GcrCertificateWidget. - * These functions are stubs for GcrCertificateWidget. - */ - -#ifndef GCR_DISABLE_DEPRECATED - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-certificate.h" -#include "gcr-certificate-widget.h" -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_CERTIFICATE_BASICS_WIDGET (gcr_certificate_basics_widget_get_type ()) -#define GCR_CERTIFICATE_BASICS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_BASICS_WIDGET, GcrCertificateBasicsWidget)) -#define GCR_CERTIFICATE_BASICS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_BASICS_WIDGET, GcrCertificateBasicsWidgetClass)) -#define GCR_IS_CERTIFICATE_BASICS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_BASICS_WIDGET)) -#define GCR_IS_CERTIFICATE_BASICS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_BASICS_WIDGET)) -#define GCR_CERTIFICATE_BASICS_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_BASICS_WIDGET, GcrCertificateBasicsWidgetClass)) - -typedef GcrCertificateWidget GcrCertificateBasicsWidget; -typedef GcrCertificateWidgetClass GcrCertificateBasicsWidgetClass; - -GType gcr_certificate_basics_widget_get_type (void); - -GcrCertificateBasicsWidget* gcr_certificate_basics_widget_new (GcrCertificate *cert); - -GcrCertificate* gcr_certificate_basics_widget_get_certificate (GcrCertificateBasicsWidget *basics); - -void gcr_certificate_basics_widget_set_certificate (GcrCertificateBasicsWidget *basics, - GcrCertificate *cert); - -G_END_DECLS - -#endif /* GCR_DISABLE_DEPRECATED */ - -#endif /* __GCR_CERTIFICATE_BASICS_WIDGET_H__ */ diff --git a/gcr/gcr-certificate-chain.c b/gcr/gcr-certificate-chain.c deleted file mode 100644 index 78a88323..00000000 --- a/gcr/gcr-certificate-chain.c +++ /dev/null @@ -1,825 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-certificate-chain.h" - -#include "gcr-certificate.h" -#define DEBUG_FLAG GCR_DEBUG_CERTIFICATE_CHAIN -#include "gcr-debug.h" -#include "gcr-pkcs11-certificate.h" -#include "gcr-simple-certificate.h" -#include "gcr-trust.h" - -#include "egg/egg-error.h" - -/** - * SECTION:gcr-certificate-chain - * @title: GcrCertificateChain - * @short_description: A certificate chain - * - * #GcrCertificateChain represents a chain of certificates, normally used to - * validate the trust in a certificate. An X.509 certificate chain has one - * endpoint certificate (the one for which trust is being verified) and then - * in turn the certificate that issued each previous certificate in the chain. - * - * This functionality is for building of certificate chains not for validating - * them. Use your favorite crypto library to validate trust in a certificate - * chain once its built. - * - * The order of certificates in the chain should be first the endpoint - * certificates and then the signing certificates. - * - * Create a new certificate chain with gcr_certificate_chain_new() and then - * add the certificates with gcr_certificate_chain_add(). - * - * You can then use gcr_certificate_chain_build() to build the remainder of - * the chain. This will lookup missing certificates in PKCS\#11 modules and - * also check that each certificate in the chain is the signer of the previous - * one. If a trust anchor, pinned certificate, or self-signed certificate is - * found, then the chain is considered built. Any extra certificates are - * removed from the chain. - * - * Once the certificate chain has been built, you can access its status - * through gcr_certificate_chain_get_status(). The status signifies whether - * the chain is anchored on a trust root, self-signed, incomplete etc. See - * #GcrCertificateChainStatus for information on the various statuses. - * - * It's important to understand that the building of a certificate chain is - * merely the first step towards verifying trust in a certificate. - */ - - -/** - * GCR_TYPE_CERTIFICATE_CHAIN_STATUS: - * - * The flags #GType for #GcrCertificateChainFlags. - */ - -/** - * GcrCertificateChain: - * - * A chain of certificates. - */ - -/** - * GcrCertificateChainClass: - * @parent_class: The parent class - * - * The class for #GcrCertificateChain. - */ - -enum { - PROP_0, - PROP_STATUS, - PROP_LENGTH, -}; - -struct _GcrCertificateChainPrivate { - GPtrArray *certificates; - GcrCertificateChainStatus status; - - /* Used in build operation */ - gchar *purpose; - gchar *peer; - guint flags; -}; - -static GQuark Q_ORIGINAL_CERT = 0; -static GQuark Q_OPERATION_DATA = 0; - -G_DEFINE_TYPE (GcrCertificateChain, gcr_certificate_chain, G_TYPE_OBJECT); - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -static void -free_chain_private (gpointer data) -{ - GcrCertificateChainPrivate *pv = data; - g_ptr_array_unref (pv->certificates); - g_free (pv->purpose); - g_free (pv->peer); - g_slice_free (GcrCertificateChainPrivate, pv); -} - -static GcrCertificateChainPrivate* -new_chain_private (void) -{ - GcrCertificateChainPrivate *pv = g_slice_new0 (GcrCertificateChainPrivate); - pv->certificates = g_ptr_array_new_with_free_func (g_object_unref); - return pv; -} - -static GcrCertificateChainPrivate* -prep_chain_private (GcrCertificateChainPrivate *orig, const gchar *purpose, - const gchar *peer, guint flags) -{ - GcrCertificateChainPrivate *pv; - GcrCertificate *certificate; - guint i; - - g_assert (orig); - g_assert (purpose); - - pv = new_chain_private (); - for (i = 0; i < orig->certificates->len; ++i) { - certificate = g_ptr_array_index (orig->certificates, i); - g_ptr_array_add (pv->certificates, g_object_ref (certificate)); - } - - pv->status = orig->status; - pv->purpose = g_strdup (purpose); - pv->peer = g_strdup (peer); - pv->flags = flags; - return pv; -} - -static GcrCertificateChainPrivate* -prep_chain_private_thread_safe (GcrCertificateChainPrivate *orig, const gchar *purpose, - const gchar *peer, guint flags) -{ - GcrCertificateChainPrivate *pv; - GcrCertificate *certificate, *safe; - gconstpointer der; - gsize n_der; - guint i; - - g_assert (orig); - - pv = prep_chain_private (orig, purpose, peer, flags); - - for (i = 0; i < pv->certificates->len; ++i) { - certificate = g_ptr_array_index (pv->certificates, i); - - /* We regard these types as thread safe */ - if (GCR_IS_SIMPLE_CERTIFICATE (certificate) || - GCR_IS_PKCS11_CERTIFICATE (certificate)) { - safe = g_object_ref (certificate); - - /* Otherwise copy the certificate data */ - } else { - der = gcr_certificate_get_der_data (certificate, &n_der); - g_return_val_if_fail (der, NULL); - safe = gcr_simple_certificate_new (der, n_der); - - _gcr_debug ("copying certificate so it's thread safe"); - - /* Always set the original certificate onto the safe one */ - g_object_set_qdata_full (G_OBJECT (safe), Q_ORIGINAL_CERT, - g_object_ref (certificate), g_object_unref); - } - - g_ptr_array_index (pv->certificates, i) = safe; - g_object_unref (certificate); - } - - return pv; -} - -static GcrCertificateChainPrivate* -cleanup_chain_private (GcrCertificateChainPrivate *pv) -{ - GcrCertificate *certificate, *orig; - guint i; - - for (i = 0; i < pv->certificates->len; ++i) { - certificate = g_ptr_array_index (pv->certificates, i); - - /* If there's an original certificate set, then replace it back */ - orig = g_object_get_qdata (G_OBJECT (certificate), Q_ORIGINAL_CERT); - if (orig != NULL) { - g_ptr_array_index (pv->certificates, i) = g_object_ref (orig); - g_object_unref (certificate); - } - } - - return pv; -} - -static gboolean -perform_build_chain (GcrCertificateChainPrivate *pv, GCancellable *cancellable, - GError **rerror) -{ - GError *error = NULL; - GcrCertificate *certificate; - gboolean lookups; - gboolean ret; - guint length; - gchar *subject; - - g_assert (pv); - g_assert (pv->certificates); - - pv->status = GCR_CERTIFICATE_CHAIN_UNKNOWN; - lookups = !((pv->flags & GCR_CERTIFICATE_CHAIN_NO_LOOKUPS) == GCR_CERTIFICATE_CHAIN_NO_LOOKUPS); - - /* This chain is built */ - if (!pv->certificates->len) { - _gcr_debug ("empty certificate chain"); - return TRUE; - } - - /* First check for pinned certificates */ - certificate = g_ptr_array_index (pv->certificates, 0); - if (_gcr_debugging) { - subject = gcr_certificate_get_subject_dn (certificate); - _gcr_debug ("first certificate: %s", subject); - g_free (subject); - } - - if (lookups && pv->peer) { - ret = gcr_trust_is_certificate_pinned (certificate, pv->purpose, - pv->peer, cancellable, &error); - if (!ret && error) { - _gcr_debug ("failed to lookup pinned certificate: %s", - egg_error_message (error)); - g_propagate_error (rerror, error); - return FALSE; - } - - /* - * This is a pinned certificate and the rest of the chain - * is irrelevant, so truncate chain and consider built. - */ - if (ret) { - _gcr_debug ("found pinned certificate for peer '%s', truncating chain", - pv->peer); - - g_ptr_array_set_size (pv->certificates, 1); - pv->status = GCR_CERTIFICATE_CHAIN_PINNED; - return TRUE; - } - } - - length = 1; - - /* The first certificate is always unconditionally in the chain */ - while (pv->status == GCR_CERTIFICATE_CHAIN_UNKNOWN) { - - /* Stop the chain if previous was self-signed */ - if (gcr_certificate_is_issuer (certificate, certificate)) { - _gcr_debug ("found self-signed certificate"); - pv->status = GCR_CERTIFICATE_CHAIN_SELFSIGNED; - break; - } - - /* Try the next certificate in the chain */ - if (length < pv->certificates->len) { - certificate = g_ptr_array_index (pv->certificates, length); - if (_gcr_debugging) { - subject = gcr_certificate_get_subject_dn (certificate); - _gcr_debug ("next certificate: %s", subject); - g_free (subject); - } - - /* No more in chain, try to lookup */ - } else if (lookups) { - certificate = gcr_pkcs11_certificate_lookup_issuer (certificate, - cancellable, &error); - if (error != NULL) { - _gcr_debug ("failed to lookup issuer: %s", error->message); - g_propagate_error (rerror, error); - return FALSE; - - } else if (certificate) { - g_ptr_array_add (pv->certificates, certificate); - if (_gcr_debugging) { - subject = gcr_certificate_get_subject_dn (certificate); - _gcr_debug ("found issuer certificate: %s", subject); - g_free (subject); - } - - } else { - _gcr_debug ("no issuer found"); - } - - /* No more in chain, and can't lookup */ - } else { - _gcr_debug ("no more certificates available, and no lookups"); - certificate = NULL; - } - - /* Stop the chain if nothing found */ - if (certificate == NULL) { - _gcr_debug ("chain is incomplete"); - pv->status = GCR_CERTIFICATE_CHAIN_INCOMPLETE; - break; - } - - ++length; - - /* See if this certificate is an anchor */ - if (lookups) { - ret = gcr_trust_is_certificate_anchored (certificate, pv->purpose, - cancellable, &error); - - if (!ret && error) { - _gcr_debug ("failed to lookup anchored certificate: %s", - egg_error_message (error)); - g_propagate_error (rerror, error); - return FALSE; - - /* Stop the chain at the first anchor */ - } else if (ret) { - _gcr_debug ("found anchored certificate"); - pv->status = GCR_CERTIFICATE_CHAIN_ANCHORED; - break; - } - } - } - - /* TODO: Need to check each certificate in the chain for distrusted */ - - /* Truncate to the appropriate length */ - g_assert (length <= pv->certificates->len); - g_ptr_array_set_size (pv->certificates, length); - return TRUE; -} - -static void -thread_build_chain (GSimpleAsyncResult *result, GObject *object, - GCancellable *cancellable) -{ - GcrCertificateChainPrivate *pv; - GError *error = NULL; - - pv = g_object_get_qdata (G_OBJECT (result), Q_OPERATION_DATA); - g_assert (pv); - - _gcr_debug ("building asynchronously in another thread"); - - if (!perform_build_chain (pv, cancellable, &error)) { - g_simple_async_result_set_from_error (result, error); - g_clear_error (&error); - } -} - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static void -gcr_certificate_chain_init (GcrCertificateChain *self) -{ - self->pv = new_chain_private (); -} - -static void -gcr_certificate_chain_dispose (GObject *obj) -{ - GcrCertificateChain *self = GCR_CERTIFICATE_CHAIN (obj); - - g_ptr_array_set_size (self->pv->certificates, 0); - self->pv->status = GCR_CERTIFICATE_CHAIN_UNKNOWN; - - G_OBJECT_CLASS (gcr_certificate_chain_parent_class)->dispose (obj); -} - -static void -gcr_certificate_chain_finalize (GObject *obj) -{ - GcrCertificateChain *self = GCR_CERTIFICATE_CHAIN (obj); - - free_chain_private (self->pv); - self->pv = NULL; - - G_OBJECT_CLASS (gcr_certificate_chain_parent_class)->finalize (obj); -} - -static void -gcr_certificate_chain_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrCertificateChain *self = GCR_CERTIFICATE_CHAIN (obj); - - switch (prop_id) { - case PROP_STATUS: - g_value_set_enum (value, gcr_certificate_chain_get_status (self)); - break; - case PROP_LENGTH: - g_value_set_uint (value, gcr_certificate_chain_get_length (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_certificate_chain_class_init (GcrCertificateChainClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gcr_certificate_chain_parent_class = g_type_class_peek_parent (klass); - - gobject_class->dispose = gcr_certificate_chain_dispose; - gobject_class->finalize = gcr_certificate_chain_finalize; - gobject_class->get_property = gcr_certificate_chain_get_property; - - /** - * GcrCertificateChain:status: - * - * The certificate chain status. See #GcrCertificateChainStatus - */ - g_object_class_install_property (gobject_class, PROP_STATUS, - g_param_spec_enum ("status", "Status", "Status of certificate chain", - GCR_TYPE_CERTIFICATE_CHAIN_STATUS, - GCR_CERTIFICATE_CHAIN_UNKNOWN, G_PARAM_READABLE)); - - /** - * GcrCertificateChain:length: - * - * The length of the certificate chain. - */ - g_object_class_install_property (gobject_class, PROP_LENGTH, - g_param_spec_uint ("length", "Length", "Length of certificate chain", - 0, G_MAXUINT, 0, G_PARAM_READABLE)); - - Q_ORIGINAL_CERT = g_quark_from_static_string ("gcr-certificate-chain-original-cert"); - Q_OPERATION_DATA = g_quark_from_static_string ("gcr-certificate-chain-operation-data"); -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * GcrCertificateChainStatus: - * @GCR_CERTIFICATE_CHAIN_UNKNOWN: The certificate chain's status is unknown. - * When a chain is not yet built it has this status. If a chain is modified after - * being built, it has this status. - * @GCR_CERTIFICATE_CHAIN_INCOMPLETE: A full chain could not be loaded. The - * chain does not end with a self-signed certificate, a trusted anchor, or a - * pinned certificate. - * @GCR_CERTIFICATE_CHAIN_SELFSIGNED: The chain ends with a self-signed - * certificate. No trust anchor was found. - * @GCR_CERTIFICATE_CHAIN_DISTRUSTED: The certificate chain contains a revoked - * or otherwise explicitly distrusted certificate. The entire chain should - * be distrusted. - * @GCR_CERTIFICATE_CHAIN_ANCHORED: The chain ends with an anchored - * certificate. The anchored certificate is not necessarily self-signed. - * @GCR_CERTIFICATE_CHAIN_PINNED: The chain represents a pinned certificate. A - * pinned certificate is an exception which trusts a given certificate - * explicitly for a purpose and communication with a certain peer. - * - * The status of a built certificate chain. Will be set to - * %GCR_CERTIFICATE_CHAIN_UNKNOWN for certificate chains that have not been - * built. - */ - -/** - * GCR_TYPE_CERTIFICATE_CHAIN_STATUS: - * - * The enum #GType for #GcrCertificateChainStatus. - */ - -/** - * GcrCertificateChainFlags: - * @GCR_CERTIFICATE_CHAIN_NONE: no flags - * @GCR_CERTIFICATE_CHAIN_NO_LOOKUPS: If this flag is specified then no - * lookups for anchors or pinned certificates are done, and the resulting chain - * will be neither anchored or pinned. Additionally no missing certificate - * authorities are looked up in PKCS\#11. - * - * Flags to be used with the gcr_certificate_chain_build() operation. - */ - -/** - * GCR_TYPE_CERTIFICATE_CHAIN_FLAGS: - * - * The flags #GType for #GcrCertificateChainFlags. - */ - -/** - * gcr_certificate_chain_new: - * - * Create a new #GcrCertificateChain. - * - * Returns: (transfer full): a newly allocated certificate chain - */ -GcrCertificateChain * -gcr_certificate_chain_new (void) -{ - return g_object_new (GCR_TYPE_CERTIFICATE_CHAIN, NULL); -} - -/** - * gcr_certificate_chain_add: - * @self: the #GcrCertificateChain - * @certificate: a #GcrCertificate to add to the chain - * - * Add @certificate to the chain. The order of certificates in the chain are - * important. The first certificate should be the endpoint certificate, and - * then come the signers (certificate authorities) each in turn. If a root - * certificate authority is present, it should come last. - * - * Adding a certificate an already built chain (see - * gcr_certificate_chain_build()) resets the type of the certificate chain - * to %GCR_CERTIFICATE_CHAIN_UNKNOWN - */ -void -gcr_certificate_chain_add (GcrCertificateChain *self, GcrCertificate *certificate) -{ - g_return_if_fail (GCR_IS_CERTIFICATE_CHAIN (self)); - g_return_if_fail (GCR_IS_CERTIFICATE (certificate)); - g_ptr_array_add (self->pv->certificates, g_object_ref (certificate)); - self->pv->status = GCR_CERTIFICATE_CHAIN_UNKNOWN; - g_object_notify (G_OBJECT (self), "status"); - g_object_notify (G_OBJECT (self), "length"); -} - -/** - * gcr_certificate_chain_get_status: - * @self: the #GcrCertificateChain - * - * Get the status of a certificate chain. If the certificate chain has not - * been built, then the status will be %GCR_CERTIFICATE_CHAIN_UNKNOWN. - * - * A status of %GCR_CERTIFICATE_CHAIN_ANCHORED does not mean that the - * certificate chain has been verified, but merely that an anchor has been - * found. - * - * Returns: the status of the certificate chain. - */ -GcrCertificateChainStatus -gcr_certificate_chain_get_status (GcrCertificateChain *self) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), GCR_CERTIFICATE_CHAIN_UNKNOWN); - return self->pv->status; -} - -/** - * gcr_certificate_chain_get_anchor: - * @self: the #GcrCertificateChain - * - * If the certificate chain has been built and is of status - * %GCR_CERTIFICATE_CHAIN_ANCHORED, then this will return the anchor - * certificate that was found. This is not necessarily a root certificate - * authority. If an intermediate certificate authority in the chain was - * found to be anchored, then that certificate will be returned. - * - * If an anchor is returned it does not mean that the certificate chain has - * been verified, but merely that an anchor has been found. - * - * Returns: (transfer none): the anchor certificate, or NULL if not anchored. - */ -GcrCertificate * -gcr_certificate_chain_get_anchor (GcrCertificateChain *self) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), NULL); - if (self->pv->status != GCR_CERTIFICATE_CHAIN_ANCHORED) - return NULL; - g_assert (self->pv->certificates->len > 0); - return GCR_CERTIFICATE (g_ptr_array_index (self->pv->certificates, - self->pv->certificates->len - 1)); -} - -/** - * gcr_certificate_chain_get_endpoint: - * @self: the #GcrCertificateChain - * - * Get the endpoint certificate in the chain. This is always the first - * certificate in the chain. The endpoint certificate cannot be anchored. - * - * Returns: (transfer none): the endpoint certificate, or %NULL if the chain - * is empty - */ -GcrCertificate* -gcr_certificate_chain_get_endpoint (GcrCertificateChain *self) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), NULL); - if (!self->pv->certificates->len) - return NULL; - return GCR_CERTIFICATE (g_ptr_array_index (self->pv->certificates, 0)); -} - -/** - * gcr_certificate_chain_get_length: - * @self: the #GcrCertificateChain - * - * Get the length of the certificate chain. - * - * Returns: the length of the certificate chain - */ -guint -gcr_certificate_chain_get_length (GcrCertificateChain *self) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), 0); - return self->pv->certificates->len; -} - -/** - * gcr_certificate_chain_get_certificate: - * @self: the #GcrCertificateChain - * @index: index of the certificate to get - * - * Get a certificate in the chain. It is an error to call this function - * with an invalid index. - * - * Returns: (transfer none): the certificate - */ -GcrCertificate * -gcr_certificate_chain_get_certificate (GcrCertificateChain *self, guint index) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), NULL); - g_return_val_if_fail (index < self->pv->certificates->len, NULL); - return GCR_CERTIFICATE (g_ptr_array_index (self->pv->certificates, index)); -} - -/** - * gcr_certificate_chain_build: - * @self: the #GcrCertificateChain - * @purpose: the purpose the certificate chain will be used for - * @peer: (allow-none): the peer the certificate chain will be used with, or %NULL - * @flags: chain completion flags - * @cancellable: a #GCancellable or %NULL - * @error: a #GError or %NULL - * - * Complete a certificate chain. Once a certificate chain has been built - * its status can be examined. - * - * This operation will lookup missing certificates in PKCS\#11 - * modules and also that each certificate in the chain is the signer of the - * previous one. If a trust anchor, pinned certificate, or self-signed certificate - * is found, then the chain is considered built. Any extra certificates are - * removed from the chain. - * - * It's important to understand that building of a certificate chain does not - * constitute verifying that chain. This is merely the first step towards - * trust verification. - * - * The @purpose is a string like %GCR_PURPOSE_CLIENT_AUTH and is the purpose - * for which the certificate chain will be used. Trust anchors are looked up - * for this purpose. This argument is required. - * - * The @peer is usually the host name of the peer whith which this certificate - * chain is being used. It is used to look up pinned certificates that have - * been stored for this peer. If %NULL then no pinned certificates will - * be considered. - * - * If the %GCR_CERTIFICATE_CHAIN_NO_LOOKUPS flag is specified then no - * lookups for anchors or pinned certificates are done, and the resulting chain - * will be neither anchored or pinned. Additionally no missing certificate - * authorities are looked up in PKCS\#11 - * - * This call will block, see gcr_certificate_chain_build_async() for the - * asynchronous version. - * - * Returns: whether the operation completed successfully - */ -gboolean -gcr_certificate_chain_build (GcrCertificateChain *self, - const gchar *purpose, - const gchar *peer, - GcrCertificateChainFlags flags, - GCancellable *cancellable, - GError **error) -{ - GcrCertificateChainPrivate *pv; - gboolean ret; - - g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), FALSE); - g_return_val_if_fail (purpose != NULL, FALSE); - - pv = prep_chain_private (self->pv, purpose, peer, flags); - - ret = perform_build_chain (pv, cancellable, error); - - if (ret) { - free_chain_private (self->pv); - self->pv = cleanup_chain_private (pv); - g_object_notify (G_OBJECT (self), "status"); - g_object_notify (G_OBJECT (self), "length"); - } else { - free_chain_private (pv); - } - - return ret; -} - -/** - * gcr_certificate_chain_build_async: - * @self: the #GcrCertificateChain - * @purpose: the purpose the certificate chain will be used for - * @peer: (allow-none): the peer the certificate chain will be used with, or %NULL - * @flags: chain completion flags - * @cancellable: a #GCancellable or %NULL - * @callback: this will be called when the operation completes. - * @user_data: data to pass to the callback - * - * Complete a certificate chain. Once a certificate chain has been built - * its status can be examined. - * - * This will lookup missing certificates in PKCS\#11 - * modules and also that each certificate in the chain is the signer of the - * previous one. If a trust anchor, pinned certificate, or self-signed certificate - * is found, then the chain is considered built. Any extra certificates are - * removed from the chain. - * - * It's important to understand that building of a certificate chain does not - * constitute verifying that chain. This is merely the first step towards - * trust verification. - * - * The @purpose is a string like %GCR_PURPOSE_CLIENT_AUTH and is the purpose - * for which the certificate chain will be used. Trust anchors are looked up - * for this purpose. This argument is required. - * - * The @peer is usually the host name of the peer whith which this certificate - * chain is being used. It is used to look up pinned certificates that have - * been stored for this peer. If %NULL then no pinned certificates will - * be considered. - * - * If the %GCR_CERTIFICATE_CHAIN_NO_LOOKUPS flag is specified then no - * lookups for anchors or pinned certificates are done, and the resulting chain - * will be neither anchored or pinned. Additionally no missing certificate - * authorities are looked up in PKCS\#11 - * - * When the operation is finished, @callback will be called. You can then call - * gcr_certificate_chain_build_finish() to get the result of the operation. - */ -void -gcr_certificate_chain_build_async (GcrCertificateChain *self, - const gchar *purpose, - const gchar *peer, - GcrCertificateChainFlags flags, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GcrCertificateChainPrivate *pv; - GSimpleAsyncResult *result; - - g_return_if_fail (GCR_IS_CERTIFICATE_CHAIN (self)); - - g_return_if_fail (GCR_IS_CERTIFICATE_CHAIN (self)); - g_return_if_fail (purpose); - - pv = prep_chain_private_thread_safe (self->pv, purpose, peer, flags); - - result = g_simple_async_result_new (G_OBJECT (self), callback, user_data, - gcr_certificate_chain_build_async); - g_object_set_qdata_full (G_OBJECT (result), Q_OPERATION_DATA, pv, free_chain_private); - - g_simple_async_result_run_in_thread (result, thread_build_chain, - G_PRIORITY_DEFAULT, cancellable); - g_object_unref (result); -} - -/** - * gcr_certificate_chain_build_finish: - * @self: the #GcrCertificateChain - * @result: the #GAsyncResult passed to the callback - * @error: a #GError, or NULL - * - * Finishes an asynchronous operation started by - * gcr_certificate_chain_build_async(). - * - * Returns: whether the operation succeeded - */ -gboolean -gcr_certificate_chain_build_finish (GcrCertificateChain *self, GAsyncResult *result, - GError **error) -{ - GcrCertificateChainPrivate *pv; - - g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), FALSE); - g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), - gcr_certificate_chain_build_async), FALSE); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return FALSE; - - pv = g_object_steal_qdata (G_OBJECT (result), Q_OPERATION_DATA); - g_return_val_if_fail (pv, FALSE); - - free_chain_private (self->pv); - self->pv = cleanup_chain_private (pv); - - g_object_notify (G_OBJECT (self), "status"); - g_object_notify (G_OBJECT (self), "length"); - return TRUE; -} diff --git a/gcr/gcr-certificate-chain.h b/gcr/gcr-certificate-chain.h deleted file mode 100644 index ef8bdcfa..00000000 --- a/gcr/gcr-certificate-chain.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_CERTIFICATE_CHAIN_H__ -#define __GCR_CERTIFICATE_CHAIN_H__ - -#include <glib-object.h> - -#include "gcr-certificate.h" -#include "gcr-types.h" - -G_BEGIN_DECLS - -typedef enum { - GCR_CERTIFICATE_CHAIN_UNKNOWN, - GCR_CERTIFICATE_CHAIN_INCOMPLETE, - GCR_CERTIFICATE_CHAIN_DISTRUSTED, - GCR_CERTIFICATE_CHAIN_SELFSIGNED, - GCR_CERTIFICATE_CHAIN_PINNED, - GCR_CERTIFICATE_CHAIN_ANCHORED, -} GcrCertificateChainStatus; - -typedef enum { - GCR_CERTIFICATE_CHAIN_NONE = 0, - GCR_CERTIFICATE_CHAIN_NO_LOOKUPS = 1 << 0, -} GcrCertificateChainFlags; - -#define GCR_TYPE_CERTIFICATE_CHAIN (gcr_certificate_chain_get_type ()) -#define GCR_CERTIFICATE_CHAIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_CHAIN, GcrCertificateChain)) -#define GCR_CERTIFICATE_CHAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_CHAIN, GcrCertificateChainClass)) -#define GCR_IS_CERTIFICATE_CHAIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_CHAIN)) -#define GCR_IS_CERTIFICATE_CHAIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_CHAIN)) -#define GCR_CERTIFICATE_CHAIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_CHAIN, GcrCertificateChainClass)) - -typedef struct _GcrCertificateChain GcrCertificateChain; -typedef struct _GcrCertificateChainClass GcrCertificateChainClass; -typedef struct _GcrCertificateChainPrivate GcrCertificateChainPrivate; - -struct _GcrCertificateChain { - GObject parent; - - /*< private >*/ - GcrCertificateChainPrivate *pv; -}; - -struct _GcrCertificateChainClass { - GObjectClass parent_class; -}; - -GType gcr_certificate_chain_get_type (void) G_GNUC_CONST; - -GcrCertificateChain* gcr_certificate_chain_new (void); - -void gcr_certificate_chain_add (GcrCertificateChain *self, - GcrCertificate *certificate); - -GcrCertificateChainStatus gcr_certificate_chain_get_status (GcrCertificateChain *self); - -GcrCertificate* gcr_certificate_chain_get_anchor (GcrCertificateChain *self); - -GcrCertificate* gcr_certificate_chain_get_endpoint (GcrCertificateChain *self); - -guint gcr_certificate_chain_get_length (GcrCertificateChain *self); - -GcrCertificate* gcr_certificate_chain_get_certificate (GcrCertificateChain *self, - guint index); - -gboolean gcr_certificate_chain_build (GcrCertificateChain *self, - const gchar *purpose, - const gchar *peer, - guint flags, - GCancellable *cancellable, - GError **error); - -void gcr_certificate_chain_build_async (GcrCertificateChain *self, - const gchar *purpose, - const gchar *peer, - guint flags, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean gcr_certificate_chain_build_finish (GcrCertificateChain *self, - GAsyncResult *result, - GError **error); - -G_END_DECLS - -#endif /* __GCR_CERTIFICATE_CHAIN_H__ */ diff --git a/gcr/gcr-certificate-details-widget.c b/gcr/gcr-certificate-details-widget.c deleted file mode 100644 index 9fc23070..00000000 --- a/gcr/gcr-certificate-details-widget.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" -#include "gcr-certificate-details-widget.h" - -#ifndef GCR_DISABLE_DEPRECATED - -/* These are all stubs for GcrCertificateWidget */ - -GType -gcr_certificate_details_widget_get_type (void) -{ - return gcr_certificate_widget_get_type (); -} - -/** - * gcr_certificate_details_widget_new: (skip) - * - * Deprecated: Since 2.30 - * - * Returns: (transfer full) (type Gcr.CertificateWidget): a new certificate widget - */ -GcrCertificateDetailsWidget * -gcr_certificate_details_widget_new (GcrCertificate *cert) -{ - return gcr_certificate_widget_new (cert); -} - -/** - * gcr_certificate_details_widget_get_certificate: (skip) - * - * Deprecated: Since 2.30 - * - * Returns: (transfer none): the certificate - */ -GcrCertificate* -gcr_certificate_details_widget_get_certificate (GcrCertificateDetailsWidget *details) -{ - return gcr_certificate_widget_get_certificate (details); -} - -/** - * gcr_certificate_details_widget_set_certificate: (skip) - * @details: the certificate widget - * @cert: the certificate - * - * Deprecated: Since 2.30 - */ -void -gcr_certificate_details_widget_set_certificate (GcrCertificateDetailsWidget *details, - GcrCertificate *cert) -{ - return gcr_certificate_widget_set_certificate (details, cert); -} - -#endif /* GCR_DISABLE_DEPRECATED */ diff --git a/gcr/gcr-certificate-details-widget.h b/gcr/gcr-certificate-details-widget.h deleted file mode 100644 index 5a3d74b0..00000000 --- a/gcr/gcr-certificate-details-widget.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_CERTIFICATE_DETAILS_WIDGET_H__ -#define __GCR_CERTIFICATE_DETAILS_WIDGET_H__ - -/* - * GcrCertificateDetailsWidget has been replaced with GcrCertificateWidget. - * These functions are stubs for GcrCertificateWidget. - */ - -#ifndef GCR_DISABLE_DEPRECATED - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-certificate.h" -#include "gcr-certificate-widget.h" -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_CERTIFICATE_DETAILS_WIDGET (gcr_certificate_details_widget_get_type ()) -#define GCR_CERTIFICATE_DETAILS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_DETAILS_WIDGET, GcrCertificateDetailsWidget)) -#define GCR_CERTIFICATE_DETAILS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_DETAILS_WIDGET, GcrCertificateDetailsWidgetClass)) -#define GCR_IS_CERTIFICATE_DETAILS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_DETAILS_WIDGET)) -#define GCR_IS_CERTIFICATE_DETAILS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_DETAILS_WIDGET)) -#define GCR_CERTIFICATE_DETAILS_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_DETAILS_WIDGET, GcrCertificateDetailsWidgetClass)) - -typedef GcrCertificateWidget GcrCertificateDetailsWidget; -typedef GcrCertificateWidgetClass GcrCertificateDetailsWidgetClass; - -GType gcr_certificate_details_widget_get_type (void); - -GcrCertificateDetailsWidget* gcr_certificate_details_widget_new (GcrCertificate *cert); - -GcrCertificate* gcr_certificate_details_widget_get_certificate (GcrCertificateDetailsWidget *details); - -void gcr_certificate_details_widget_set_certificate (GcrCertificateDetailsWidget *details, - GcrCertificate *cert); - -G_END_DECLS - -#endif /* GCR_DISABLE_DEPRECATED */ - -#endif /* __GCR_CERTIFICATE_DETAILS_WIDGET_H__ */ diff --git a/gcr/gcr-certificate-exporter.c b/gcr/gcr-certificate-exporter.c deleted file mode 100644 index 7806533e..00000000 --- a/gcr/gcr-certificate-exporter.c +++ /dev/null @@ -1,567 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-certificate.h" -#include "gcr-certificate-exporter.h" - -#include "egg/egg-armor.h" -#include "egg/egg-openssl.h" - -#include <glib/gi18n-lib.h> - -enum { - PROP_0, - PROP_CERTIFICATE, - PROP_LABEL, - PROP_TRANSIENT_FOR -}; - -struct _GcrCertificateExporterPrivate { - - /* Setup stuff */ - GcrCertificate *certificate; - gchar *label; - GtkWindow *transient_for; - - /* Used during operation */ - GtkFileChooser *chooser_dialog; - GFile *output_file; - GByteArray *buffer; - guint buffer_at; - - /* Async stuff */ - GAsyncReadyCallback callback; - gpointer user_data; - GCancellable *cancellable; - GError *error; - gboolean completed; -}; - -static const gchar *BAD_FILENAME_CHARS = "/\\<>|?*"; - -/* Forward declarations */ -static void _gcr_certificate_exporter_async_result_init (GAsyncResultIface *iface); -static void write_to_outputstream (GcrCertificateExporter *self, GOutputStream *os); - -G_DEFINE_TYPE_WITH_CODE (GcrCertificateExporter, _gcr_certificate_exporter, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, _gcr_certificate_exporter_async_result_init)); - -typedef void (*PrepareDataFunc) (GcrCertificateExporter *self); - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -static void -prepare_data_for_der (GcrCertificateExporter *self) -{ - gconstpointer data; - gsize n_data; - - data = gcr_certificate_get_der_data (self->pv->certificate, &n_data); - g_return_if_fail (data); - - self->pv->buffer = g_byte_array_new (); - g_byte_array_append (self->pv->buffer, data, n_data); -} - -static void -prepare_data_for_pem (GcrCertificateExporter *self) -{ - gconstpointer data; - gpointer encoded; - gsize n_data, n_encoded; - - data = gcr_certificate_get_der_data (self->pv->certificate, &n_data); - g_return_if_fail (data); - - self->pv->buffer = g_byte_array_new (); - - encoded = egg_armor_write (data, n_data, - g_quark_from_static_string ("CERTIFICATE"), - NULL, &n_encoded); - - g_byte_array_append (self->pv->buffer, encoded, n_encoded); - g_free (encoded); -} - -static void -complete_async_result (GcrCertificateExporter *self) -{ - g_assert (self->pv->callback); - g_assert (!self->pv->completed); - - if (self->pv->chooser_dialog) - gtk_widget_hide (GTK_WIDGET (self->pv->chooser_dialog)); - - self->pv->completed = TRUE; - (self->pv->callback) (G_OBJECT (self), G_ASYNC_RESULT (self), - self->pv->user_data); -} - -static void -on_outputstream_write_ready (GObject *source, GAsyncResult *res, gpointer user_data) -{ - GcrCertificateExporter *self = GCR_CERTIFICATE_EXPORTER (user_data); - GOutputStream *os = G_OUTPUT_STREAM (source); - gssize written; - - written = g_output_stream_write_finish (os, res, &self->pv->error); - - if (self->pv->error) { - complete_async_result (self); - return; - } - - g_return_if_fail (written >= 0); - g_return_if_fail (written <= self->pv->buffer->len - self->pv->buffer_at); - self->pv->buffer_at += written; - - /* Write next bit, or finished */ - write_to_outputstream (self, os); -} - -static void -on_outputstream_closed (GObject *source, GAsyncResult *res, gpointer user_data) -{ - GcrCertificateExporter *self = GCR_CERTIFICATE_EXPORTER (user_data); - g_output_stream_close_finish (G_OUTPUT_STREAM (source), res, &self->pv->error); - complete_async_result (self); -} - -static void -write_to_outputstream (GcrCertificateExporter *self, GOutputStream *os) -{ - gtk_widget_hide (GTK_WIDGET (self->pv->chooser_dialog)); - g_assert (GTK_IS_WIDGET (self->pv->chooser_dialog)); - - /* Are we all done? */ - g_assert (self->pv->buffer_at <= self->pv->buffer->len); - if (self->pv->buffer_at == self->pv->buffer->len) { - g_output_stream_close_async (os, G_PRIORITY_DEFAULT, - self->pv->cancellable, - on_outputstream_closed, self); - return; - } - - g_output_stream_write_async (os, self->pv->buffer->data + self->pv->buffer_at, - self->pv->buffer->len - self->pv->buffer_at, - G_PRIORITY_DEFAULT, self->pv->cancellable, - on_outputstream_write_ready, self); -} - -static void -on_replace_file_ready (GObject *source, GAsyncResult *res, gpointer user_data) -{ - GcrCertificateExporter *self = GCR_CERTIFICATE_EXPORTER (user_data); - GFile *file = G_FILE (source); - GFileOutputStream *os; - - os = g_file_replace_finish (file, res, &self->pv->error); - - if (self->pv->error) { - complete_async_result (self); - return; - } - - write_to_outputstream (self, G_OUTPUT_STREAM (os)); -} - -static void -on_replace_dialog_response (GtkDialog *dialog, gint response_id, gpointer user_data) -{ - GcrCertificateExporter *self = GCR_CERTIFICATE_EXPORTER (user_data); - - if (response_id == GTK_RESPONSE_ACCEPT) { - g_file_replace_async (self->pv->output_file, NULL, FALSE, G_FILE_CREATE_NONE, - G_PRIORITY_DEFAULT, self->pv->cancellable, - on_replace_file_ready, self); - } - - gtk_widget_destroy (GTK_WIDGET (dialog)); -} - -static void -on_cancel_replace_dialog (GCancellable *cancellable, gpointer user_data) -{ - gtk_widget_destroy (user_data); -} - -static void -on_create_file_ready (GObject *source, GAsyncResult *res, gpointer user_data) -{ - GcrCertificateExporter *self = GCR_CERTIFICATE_EXPORTER (user_data); - GFileOutputStream *os; - GtkWidget *dialog; - - os = g_file_create_finish (self->pv->output_file, res, &self->pv->error); - - /* Try again this time replacing the file */ - if (g_error_matches (self->pv->error, G_IO_ERROR, G_IO_ERROR_EXISTS)) { - g_clear_error (&self->pv->error); - - dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (self->pv->chooser_dialog), - GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, - GTK_BUTTONS_NONE, _("<b>A file already exists with this name.</b>\n\nDo you want to replace it with a new file?")); - gtk_dialog_add_buttons (GTK_DIALOG (dialog), - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - _("_Replace"), GTK_RESPONSE_ACCEPT, NULL); - - g_signal_connect (dialog, "response", - G_CALLBACK (on_replace_dialog_response), self); - if (self->pv->cancellable) - g_cancellable_connect (self->pv->cancellable, - G_CALLBACK (on_cancel_replace_dialog), - g_object_ref (dialog), g_object_unref); - gtk_widget_show (dialog); - - return; - } - - if (self->pv->error) { - complete_async_result (self); - return; - } - - write_to_outputstream (self, G_OUTPUT_STREAM (os)); -} - -static void -on_chooser_dialog_response (GtkDialog *dialog, gint response_id, gpointer user_data) -{ - GcrCertificateExporter *self = GCR_CERTIFICATE_EXPORTER (user_data); - GtkFileFilter *filter; - PrepareDataFunc prepare_data; - - if (response_id != GTK_RESPONSE_ACCEPT) { - g_set_error (&self->pv->error, G_IO_ERROR, G_IO_ERROR_CANCELLED, - _("The operation was cancelled.")); - complete_async_result (self); - return; - } - - if (self->pv->output_file) - g_object_unref (self->pv->output_file); - self->pv->output_file = gtk_file_chooser_get_file (self->pv->chooser_dialog); - g_return_if_fail (self->pv->output_file); - - filter = gtk_file_chooser_get_filter (self->pv->chooser_dialog); - prepare_data = g_object_get_data (G_OBJECT (filter), "prepare-data-func"); - g_assert (prepare_data); - - if (self->pv->buffer) - g_byte_array_free (self->pv->buffer, TRUE); - self->pv->buffer = NULL; - self->pv->buffer_at = 0; - - /* Prepare the for writing out */ - (prepare_data) (self); - - /* Try to open the file */ - g_file_create_async (self->pv->output_file, G_FILE_CREATE_NONE, G_PRIORITY_DEFAULT, - self->pv->cancellable, on_create_file_ready, - self); -} - -static void -on_cancel_chooser_dialog (GCancellable *cancellable, gpointer user_data) -{ - GtkDialog *dialog = GTK_DIALOG (user_data); - gtk_dialog_response (dialog, GTK_RESPONSE_CANCEL); -} - -static void -exporter_display_chooser (GcrCertificateExporter *self) -{ - GtkFileFilter* filter; - GtkWidget *dialog; - gchar *filename; - - g_assert (!self->pv->chooser_dialog); - - dialog = gtk_file_chooser_dialog_new (_("Export certificate"), - NULL, GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - - self->pv->chooser_dialog = g_object_ref_sink(dialog); - gtk_dialog_set_default_response (GTK_DIALOG (dialog), - GTK_RESPONSE_ACCEPT); - gtk_file_chooser_set_local_only (self->pv->chooser_dialog, FALSE); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("Certificate files")); - gtk_file_filter_add_mime_type (filter, "application/x-x509-ca-cert"); - gtk_file_filter_add_mime_type (filter, "application/x-x509-user-cert"); - gtk_file_filter_add_mime_type (filter, "application/pkix-cert"); - gtk_file_filter_add_pattern (filter, "*.cer"); - gtk_file_filter_add_pattern (filter, "*.crt"); - g_object_set_data (G_OBJECT (filter), "prepare-data-func", prepare_data_for_der); - gtk_file_chooser_add_filter (self->pv->chooser_dialog, filter); - gtk_file_chooser_set_filter (self->pv->chooser_dialog, filter); - - filter = gtk_file_filter_new (); - gtk_file_filter_set_name (filter, _("PEM files")); - gtk_file_filter_add_mime_type (filter, "text/plain"); - gtk_file_filter_add_pattern (filter, "*.pem"); - g_object_set_data (G_OBJECT (filter), "prepare-data-func", prepare_data_for_pem); - gtk_file_chooser_add_filter (self->pv->chooser_dialog, filter); - - filename = g_strconcat (self->pv->label, ".crt", NULL); - g_strdelimit (filename, BAD_FILENAME_CHARS, '_'); - gtk_file_chooser_set_current_name (self->pv->chooser_dialog, filename); - g_free (filename); - - g_signal_connect (self->pv->chooser_dialog, "response", - G_CALLBACK (on_chooser_dialog_response), self); - if (self->pv->cancellable) - g_cancellable_connect (self->pv->cancellable, - G_CALLBACK (on_cancel_chooser_dialog), self, NULL); - - gtk_widget_show (GTK_WIDGET (self->pv->chooser_dialog)); -} - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static void -_gcr_certificate_exporter_init (GcrCertificateExporter *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_EXPORTER, - GcrCertificateExporterPrivate)); -} - -static void -_gcr_certificate_exporter_dispose (GObject *obj) -{ - GcrCertificateExporter *self = GCR_CERTIFICATE_EXPORTER (obj); - - if (self->pv->certificate) - g_object_unref (self->pv->certificate); - self->pv->certificate = NULL; - - if (self->pv->cancellable) - g_object_unref (self->pv->cancellable); - self->pv->cancellable = NULL; - - G_OBJECT_CLASS (_gcr_certificate_exporter_parent_class)->dispose (obj); -} - -static void -_gcr_certificate_exporter_finalize (GObject *obj) -{ - GcrCertificateExporter *self = GCR_CERTIFICATE_EXPORTER (obj); - - g_free (self->pv->label); - - /* - * Should have been freed in _export_finish, which holds a ref to self - * so this should never be reached without being finished. - */ - g_assert (!self->pv->chooser_dialog); - g_assert (!self->pv->output_file); - g_assert (!self->pv->buffer); - - g_clear_error (&self->pv->error); - - G_OBJECT_CLASS (_gcr_certificate_exporter_parent_class)->finalize (obj); -} - -static void -_gcr_certificate_exporter_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrCertificateExporter *self = GCR_CERTIFICATE_EXPORTER (obj); - GcrCertificate *cert; - - switch (prop_id) { - case PROP_CERTIFICATE: - cert = g_value_dup_object (value); - if (self->pv->certificate) - g_object_unref (self->pv->certificate); - self->pv->certificate = cert; - g_object_notify (G_OBJECT (self), "certificate"); - break; - case PROP_LABEL: - g_free (self->pv->label); - self->pv->label = g_value_dup_string (value); - g_object_notify (obj, "label"); - break; - case PROP_TRANSIENT_FOR: - self->pv->transient_for = g_value_get_object (value); - g_object_notify (obj, "transient-for"); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_certificate_exporter_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrCertificateExporter *self = GCR_CERTIFICATE_EXPORTER (obj); - - switch (prop_id) { - case PROP_CERTIFICATE: - g_value_set_object (value, self->pv->certificate); - break; - case PROP_LABEL: - g_value_take_string (value, self->pv->label); - break; - case PROP_TRANSIENT_FOR: - g_value_set_object (value, self->pv->transient_for); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_certificate_exporter_class_init (GcrCertificateExporterClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - _gcr_certificate_exporter_parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private (klass, sizeof (GcrCertificateExporterPrivate)); - - gobject_class->dispose = _gcr_certificate_exporter_dispose; - gobject_class->finalize = _gcr_certificate_exporter_finalize; - gobject_class->set_property = _gcr_certificate_exporter_set_property; - gobject_class->get_property = _gcr_certificate_exporter_get_property; - - g_object_class_install_property (gobject_class, PROP_CERTIFICATE, - g_param_spec_object ("certificate", "Certificate", "Certificate to display.", - GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_LABEL, - g_param_spec_string ("label", "Label", "Label of certificate.", - _("Certificate"), G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_TRANSIENT_FOR, - g_param_spec_object ("transient-for", "Transient For", "Transient for this Window", - GTK_TYPE_WINDOW, G_PARAM_READWRITE)); -} - -static GObject* -_gcr_certificate_exporter_get_source_object (GAsyncResult *result) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE_EXPORTER (result), NULL); - return G_OBJECT (result); -} - -static gpointer -_gcr_certificate_exporter_get_user_data (GAsyncResult *result) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE_EXPORTER (result), NULL); - return GCR_CERTIFICATE_EXPORTER (result)->pv->user_data; -} - -static void -_gcr_certificate_exporter_async_result_init (GAsyncResultIface *iface) -{ - iface->get_source_object = _gcr_certificate_exporter_get_source_object; - iface->get_user_data = _gcr_certificate_exporter_get_user_data; -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -GcrCertificateExporter* -_gcr_certificate_exporter_new (GcrCertificate *certificate, const gchar *label, - GtkWindow *transient_for) -{ - return g_object_new (GCR_TYPE_CERTIFICATE_EXPORTER, - "certificate", certificate, - "label", label, - "transient-for", transient_for, - NULL); -} - -void -_gcr_certificate_exporter_export_async (GcrCertificateExporter *self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_return_if_fail (GCR_IS_CERTIFICATE_EXPORTER (self)); - g_return_if_fail (callback); - - /* Must not have already started */ - g_return_if_fail (!self->pv->callback); - g_return_if_fail (!self->pv->cancellable); - - self->pv->callback = callback; - self->pv->user_data = user_data; - if (cancellable) - self->pv->cancellable = g_object_ref (cancellable); - - exporter_display_chooser (self); - - /* Matching in export_finish */ - g_object_ref (self); -} - -gboolean -_gcr_certificate_exporter_export_finish (GcrCertificateExporter *self, - GAsyncResult *result, - GError **error) -{ - gboolean ret = TRUE; - - g_return_val_if_fail (G_ASYNC_RESULT (self) == result, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - g_return_val_if_fail (self->pv->completed, FALSE); - - /* Cleanup all the operation stuff */ - self->pv->callback = NULL; - - if (self->pv->chooser_dialog) - g_object_unref (self->pv->chooser_dialog); - self->pv->chooser_dialog = NULL; - - if (self->pv->output_file) - g_object_unref (self->pv->output_file); - self->pv->output_file = NULL; - - if (self->pv->buffer) - g_byte_array_free (self->pv->buffer, TRUE); - self->pv->buffer = NULL; - self->pv->buffer_at = 0; - - self->pv->completed = FALSE; - - if (self->pv->error) { - g_propagate_error (error, self->pv->error); - ret = FALSE; - } - - /* Matches in export_async */ - g_object_unref (self); - return ret; -} diff --git a/gcr/gcr-certificate-exporter.h b/gcr/gcr-certificate-exporter.h deleted file mode 100644 index fd04a20a..00000000 --- a/gcr/gcr-certificate-exporter.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_CERTIFICATE_EXPORTER_H__ -#define __GCR_CERTIFICATE_EXPORTER_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_CERTIFICATE_EXPORTER (_gcr_certificate_exporter_get_type ()) -#define GCR_CERTIFICATE_EXPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_EXPORTER, GcrCertificateExporter)) -#define GCR_CERTIFICATE_EXPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_EXPORTER, GcrCertificateExporterClass)) -#define GCR_IS_CERTIFICATE_EXPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_EXPORTER)) -#define GCR_IS_CERTIFICATE_EXPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_EXPORTER)) -#define GCR_CERTIFICATE_EXPORTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_EXPORTER, GcrCertificateExporterClass)) - -typedef struct _GcrCertificateExporter GcrCertificateExporter; -typedef struct _GcrCertificateExporterClass GcrCertificateExporterClass; -typedef struct _GcrCertificateExporterPrivate GcrCertificateExporterPrivate; - -struct _GcrCertificateExporter { - /*< private >*/ - GObject parent; - GcrCertificateExporterPrivate *pv; -}; - -struct _GcrCertificateExporterClass { - GObjectClass parent_class; -}; - -GType _gcr_certificate_exporter_get_type (void); - -GcrCertificateExporter* _gcr_certificate_exporter_new (GcrCertificate *certificate, - const gchar *label, - GtkWindow *transient_for); - -void _gcr_certificate_exporter_export_async (GcrCertificateExporter *self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean _gcr_certificate_exporter_export_finish (GcrCertificateExporter *self, - GAsyncResult *result, - GError **error); - -G_END_DECLS - -#endif /* __GCR_CERTIFICATE_EXPORTER_H__ */ diff --git a/gcr/gcr-certificate-extensions.c b/gcr/gcr-certificate-extensions.c deleted file mode 100644 index 8256da23..00000000 --- a/gcr/gcr-certificate-extensions.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ -#include "config.h" - -#include "gcr-certificate-extensions.h" -#include "gcr-oids.h" - -#include "egg/egg-asn1x.h" -#include "egg/egg-asn1-defs.h" -#include "egg/egg-dn.h" - -#include <glib/gi18n-lib.h> - -gboolean -_gcr_certificate_extension_basic_constraints (gconstpointer data, gsize n_data, - gboolean *is_ca, gint *path_len) -{ - gboolean ret = TRUE; - GNode *asn = NULL; - GNode *node; - gulong value; - - g_return_val_if_fail (data, FALSE); - g_return_val_if_fail (n_data, FALSE); - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "BasicConstraints", data, n_data); - if (asn == NULL) - return FALSE; - - if (path_len) { - node = egg_asn1x_node (asn, "pathLenConstraint", NULL); - if (!egg_asn1x_have (node)) - *path_len = -1; - else if (!egg_asn1x_get_integer_as_ulong (node, &value)) - ret = FALSE; - else - *path_len = value; - } - - if (is_ca) { - node = egg_asn1x_node (asn, "cA", NULL); - if (!egg_asn1x_have (node)) - *is_ca = FALSE; - else if (!egg_asn1x_get_boolean (node, is_ca)) - ret = FALSE; - } - - egg_asn1x_destroy (asn); - return ret; -} - -GQuark* -_gcr_certificate_extension_extended_key_usage (gconstpointer data, gsize n_data) -{ - GNode *asn = NULL; - GNode *node; - GArray *array; - GQuark oid; - int i; - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "ExtKeyUsageSyntax", data, n_data); - if (asn == NULL) - return NULL; - - array = g_array_new (TRUE, TRUE, sizeof (GQuark)); - for (i = 0; TRUE; ++i) { - node = egg_asn1x_node (asn, i + 1, NULL); - if (node == NULL) - break; - oid = egg_asn1x_get_oid_as_quark (node); - g_array_append_val (array, oid); - } - - egg_asn1x_destroy (asn); - return (GQuark*)g_array_free (array, FALSE); -} - -gpointer -_gcr_certificate_extension_subject_key_identifier (gconstpointer data, gsize n_data, - gsize *n_keyid) -{ - GNode *asn = NULL; - gpointer result; - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectKeyIdentifier", data, n_data); - if (asn == NULL) - return NULL; - - result = egg_asn1x_get_string_as_raw (asn, g_realloc, n_keyid); - egg_asn1x_destroy (asn); - - return result; -} - -gboolean -_gcr_certificate_extension_key_usage (gconstpointer data, gsize n_data, - gulong *key_usage) -{ - GNode *asn = NULL; - gboolean ret = TRUE; - guint n_bits; - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "KeyUsage", data, n_data); - if (asn == NULL) - return FALSE; - - ret = egg_asn1x_get_bits_as_ulong (asn, key_usage, &n_bits); - egg_asn1x_destroy (asn); - return ret; -} - -static void -general_name_parse_other (GNode *node, GcrGeneralName *general) -{ - GNode *decode = NULL; - GQuark oid; - gconstpointer value; - gsize n_value; - - general->type = GCR_GENERAL_NAME_OTHER; - general->description = _("Other Name"); - - oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "type-id", NULL)); - value = egg_asn1x_get_raw_element (egg_asn1x_node (node, "value", NULL), &n_value); - - if (value == NULL) - return; - - if (oid == GCR_OID_ALT_NAME_XMPP_ADDR) { - general->description = _("XMPP Addr"); - decode = egg_asn1x_create_and_decode (pkix_asn1_tab, "UTF8String", value, n_value); - general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc); - } else if (oid == GCR_OID_ALT_NAME_DNS_SRV) { - general->description = _("DNS SRV"); - decode = egg_asn1x_create_and_decode (pkix_asn1_tab, "IA5String", value, n_value); - general->display = egg_asn1x_get_string_as_utf8 (decode, g_realloc); - } - - egg_asn1x_destroy (decode); -} - -static void -general_name_parse_rfc822 (GNode *node, GcrGeneralName *general) -{ - general->type = GCR_GENERAL_NAME_RFC822; - general->description = _("Email"); - general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc); -} - -static void -general_name_parse_dns (GNode *node, GcrGeneralName *general) -{ - general->type = GCR_GENERAL_NAME_DNS; - general->description = _("DNS"); - general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc); -} - -static void -general_name_parse_x400 (GNode *node, GcrGeneralName *general) -{ - general->type = GCR_GENERAL_NAME_X400; - general->description = _("X400 Address"); -} - -static void -general_name_parse_dn (GNode *node, GcrGeneralName *general) -{ - general->type = GCR_GENERAL_NAME_DNS; - general->description = _("Directory Name"); - general->display = egg_dn_read (node); -} - -static void -general_name_parse_edi (GNode *node, GcrGeneralName *general) -{ - general->type = GCR_GENERAL_NAME_EDI; - general->description = _("EDI Party Name"); -} - -static void -general_name_parse_uri (GNode *node, GcrGeneralName *general) -{ - general->type = GCR_GENERAL_NAME_URI; - general->description = _("URI"); - general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc); -} - -static void -general_name_parse_ip (GNode *node, GcrGeneralName *general) -{ - general->type = GCR_GENERAL_NAME_IP; - general->description = _("IP Address"); - general->display = egg_asn1x_get_string_as_utf8 (node, g_realloc); -} - -static void -general_name_parse_registered (GNode *node, GcrGeneralName *general) -{ - general->type = GCR_GENERAL_NAME_REGISTERED_ID; - general->description = _("Registered ID"); - general->display = egg_asn1x_get_oid_as_string (node); -} - -GArray* -_gcr_certificate_extension_subject_alt_name (gconstpointer data, gsize n_data) -{ - GNode *asn = NULL; - guint count, i; - const gchar *node_name; - GArray *names; - GcrGeneralName general; - GNode *choice; - - _gcr_oids_init (); - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectAltName", data, n_data); - if (asn == NULL) - return NULL; - - names = g_array_new (FALSE, TRUE, sizeof (GcrGeneralName)); - count = egg_asn1x_count (asn); - - for (i = 0; i < count; i++) { - choice = egg_asn1x_get_choice (egg_asn1x_node (asn, i + 1, NULL)); - g_return_val_if_fail (choice, NULL); - - node_name = egg_asn1x_name (choice); - g_return_val_if_fail (node_name, NULL); - - memset (&general, 0, sizeof (general)); - - if (g_str_equal (node_name, "otherName")) - general_name_parse_other (choice, &general); - - else if (g_str_equal (node_name, "rfc822Name")) - general_name_parse_rfc822 (choice, &general); - - else if (g_str_equal (node_name, "dNSName")) - general_name_parse_dns (choice, &general); - - else if (g_str_equal (node_name, "x400Address")) - general_name_parse_x400 (choice, &general); - - else if (g_str_equal (node_name, "directoryName")) - general_name_parse_dn (choice, &general); - - else if (g_str_equal (node_name, "ediPartyName")) - general_name_parse_edi (choice, &general); - - else if (g_str_equal (node_name, "uniformResourceIdentifier")) - general_name_parse_uri (choice, &general); - - else if (g_str_equal (node_name, "IPAddress")) - general_name_parse_ip (choice, &general); - - else if (g_str_equal (node_name, "registeredID")) - general_name_parse_registered (choice, &general); - - general.raw = egg_asn1x_get_raw_element (choice, &general.n_raw); - g_array_append_val (names, general); - } - - egg_asn1x_destroy (asn); - return names; -} - -void -_gcr_general_names_free (GArray *names) -{ - guint i; - - for (i = 0; names && i < names->len; i++) - g_free (g_array_index (names, GcrGeneralName, i).display); - g_array_free (names, TRUE); -} diff --git a/gcr/gcr-certificate-extensions.h b/gcr/gcr-certificate-extensions.h deleted file mode 100644 index 9101008d..00000000 --- a/gcr/gcr-certificate-extensions.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef GCR_CERTIFICATE_EXTENSIONS_H -#define GCR_CERTIFICATE_EXTENSIONS_H - -#include <glib.h> - -G_BEGIN_DECLS - -gboolean _gcr_certificate_extension_basic_constraints (gconstpointer data, - gsize n_data, - gboolean *is_ca, - gint *path_len); - -GQuark* _gcr_certificate_extension_extended_key_usage (gconstpointer data, - gsize n_data); - -gpointer _gcr_certificate_extension_subject_key_identifier (gconstpointer data, - gsize n_data, - gsize *n_keyid); - -typedef enum { - GCR_KEY_USAGE_DIGITAL_SIGNATURE = 1 << 0, - GCR_KEY_USAGE_NON_REPUDIATION = 1 << 1, - GCR_KEY_USAGE_KEY_ENCIPHERMENT = 1 << 2, - GCR_KEY_USAGE_DATA_ENCIPHERMENT = 1 << 3, - GCR_KEY_USAGE_KEY_AGREEMENT = 1 << 4, - GCR_KEY_USAGE_KEY_CERT_SIGN = 1 << 5, - GCR_KEY_USAGE_CRL_SIGN = 1 << 6, -} GcrCertificateExtensionKeyUsage; - -gboolean _gcr_certificate_extension_key_usage (gconstpointer data, - gsize n_data, - gulong *key_usage); - -typedef enum { - GCR_GENERAL_NAME_OTHER, - GCR_GENERAL_NAME_RFC822, - GCR_GENERAL_NAME_DNS, - GCR_GENERAL_NAME_X400, - GCR_GENERAL_NAME_DN, - GCR_GENERAL_NAME_EDI, - GCR_GENERAL_NAME_URI, - GCR_GENERAL_NAME_IP, - GCR_GENERAL_NAME_REGISTERED_ID, -} GcrGeneralNameType; - -typedef struct { - GcrGeneralNameType type; - const gchar *description; - gchar *display; - gconstpointer raw; - gsize n_raw; -} GcrGeneralName; - -GArray * _gcr_certificate_extension_subject_alt_name (gconstpointer data, - gsize n_data); - -void _gcr_general_names_free (GArray *names); - -G_END_DECLS - -#endif /* GCR_CERTIFICATE_H */ diff --git a/gcr/gcr-certificate-renderer.c b/gcr/gcr-certificate-renderer.c deleted file mode 100644 index 7995917e..00000000 --- a/gcr/gcr-certificate-renderer.c +++ /dev/null @@ -1,909 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-certificate.h" -#include "gcr-certificate-exporter.h" -#include "gcr-certificate-extensions.h" -#include "gcr-certificate-renderer.h" -#include "gcr-display-view.h" -#include "gcr-fingerprint.h" -#include "gcr-icons.h" -#include "gcr-oids.h" -#include "gcr-simple-certificate.h" -#include "gcr-renderer.h" - -#include "egg/egg-asn1x.h" -#include "egg/egg-asn1-defs.h" -#include "egg/egg-dn.h" -#include "egg/egg-oid.h" -#include "egg/egg-hex.h" - -#include "gck/gck.h" - -#include <gdk/gdk.h> -#include <glib/gi18n-lib.h> - -/** - * GcrCertificateRenderer: - * - * An implementation of #GcrRenderer which renders certificates. - */ - -/** - * GcrCertificateRendererClass: - * @parent_class: The parent class. - * - * The class for #GcrCertificateRenderer. - */ - -enum { - PROP_0, - PROP_CERTIFICATE, - PROP_LABEL, - PROP_ATTRIBUTES -}; - -struct _GcrCertificateRendererPrivate { - GcrCertificate *opt_cert; - GckAttributes *opt_attrs; - guint key_size; - gchar *label; -}; - -static void gcr_renderer_iface_init (GcrRendererIface *iface); -static void gcr_renderer_certificate_iface_init (GcrCertificateIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrCertificateRenderer, gcr_certificate_renderer, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_renderer_iface_init); - GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE (); - G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_renderer_certificate_iface_init); -); - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -static gchar* -calculate_label (GcrCertificateRenderer *self) -{ - gchar *label; - - if (self->pv->label) - return g_strdup (self->pv->label); - - if (self->pv->opt_attrs) { - if (gck_attributes_find_string (self->pv->opt_attrs, CKA_LABEL, &label)) - return label; - } - - label = gcr_certificate_get_subject_cn (GCR_CERTIFICATE (self)); - if (label != NULL) - return label; - - return g_strdup (_("Certificate")); -} - -static gboolean -append_extension_basic_constraints (GcrCertificateRenderer *self, GcrDisplayView *view, - gconstpointer data, gsize n_data) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - gboolean is_ca = FALSE; - gint path_len = -1; - gchar *number; - - if (!_gcr_certificate_extension_basic_constraints (data, n_data, &is_ca, &path_len)) - return FALSE; - - _gcr_display_view_append_heading (view, renderer, _("Basic Constraints")); - - _gcr_display_view_append_value (view, renderer, _("Certificate Authority"), - is_ca ? _("Yes") : _("No"), FALSE); - - number = g_strdup_printf ("%d", path_len); - _gcr_display_view_append_value (view, renderer, _("Max Path Length"), - path_len < 0 ? _("Unlimited") : number, FALSE); - g_free (number); - - return TRUE; -} - -static gboolean -append_extension_extended_key_usage (GcrCertificateRenderer *self, GcrDisplayView *view, - gconstpointer data, gsize n_data) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - GQuark *oids; - GString *text; - guint i; - - oids = _gcr_certificate_extension_extended_key_usage (data, n_data); - if (oids == NULL) - return FALSE; - - _gcr_display_view_append_heading (view, renderer, _("Extended Key Usage")); - - text = g_string_new (""); - for (i = 0; oids[i] != 0; i++) { - if (i > 0) - g_string_append_unichar (text, GCR_DISPLAY_VIEW_LINE_BREAK); - g_string_append (text, egg_oid_get_description (oids[i])); - } - - g_free (oids); - - _gcr_display_view_append_value (view, renderer, _("Allowed Purposes"), - text->str, FALSE); - - g_string_free (text, TRUE); - - return TRUE; -} - -static gboolean -append_extension_subject_key_identifier (GcrCertificateRenderer *self, GcrDisplayView *view, - gconstpointer data, gsize n_data) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - gpointer keyid; - gsize n_keyid; - - keyid = _gcr_certificate_extension_subject_key_identifier (data, n_data, &n_keyid); - if (keyid == NULL) - return FALSE; - - _gcr_display_view_append_heading (view, renderer, _("Subject Key Identifier")); - _gcr_display_view_append_hex (view, renderer, _("Key Identifier"), keyid, n_keyid); - - g_free (keyid); - - return TRUE; -} - -static const struct { - guint usage; - const gchar *description; -} usage_descriptions[] = { - { GCR_KEY_USAGE_DIGITAL_SIGNATURE, N_("Digital signature") }, - { GCR_KEY_USAGE_KEY_ENCIPHERMENT, N_("Key encipherment") }, - { GCR_KEY_USAGE_DATA_ENCIPHERMENT, N_("Data encipherment") }, - { GCR_KEY_USAGE_KEY_AGREEMENT, N_("Key agreement") }, - { GCR_KEY_USAGE_KEY_CERT_SIGN, N_("Certificate signature") }, - { GCR_KEY_USAGE_CRL_SIGN, N_("Revocation list signature") } -}; - -static gboolean -append_extension_key_usage (GcrCertificateRenderer *self, GcrDisplayView *view, - gconstpointer data, gsize n_data) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - gulong key_usage; - GString *text; - guint i; - - if (!_gcr_certificate_extension_key_usage (data, n_data, &key_usage)) - return FALSE; - - text = g_string_new (""); - - for (i = 0; i < G_N_ELEMENTS (usage_descriptions); i++) { - if (key_usage & usage_descriptions[i].usage) { - if (text->len > 0) - g_string_append_unichar (text, GCR_DISPLAY_VIEW_LINE_BREAK); - g_string_append (text, gettext (usage_descriptions[i].description)); - } - } - - _gcr_display_view_append_heading (view, renderer, _("Key Usage")); - _gcr_display_view_append_value (view, renderer, _("Usages"), text->str, FALSE); - - g_string_free (text, TRUE); - - return TRUE; -} - -static gboolean -append_extension_subject_alt_name (GcrCertificateRenderer *self, GcrDisplayView *view, - gconstpointer data, gsize n_data) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - GArray *general_names; - GcrGeneralName *general; - guint i; - - general_names = _gcr_certificate_extension_subject_alt_name (data, n_data); - if (general_names == NULL) - return FALSE; - - _gcr_display_view_append_heading (view, renderer, _("Subject Alternative Names")); - - for (i = 0; i < general_names->len; i++) { - general = &g_array_index (general_names, GcrGeneralName, i); - if (general->display == NULL) - _gcr_display_view_append_hex (view, renderer, general->description, - general->raw, general->n_raw); - else - _gcr_display_view_append_value (view, renderer, general->description, - general->display, FALSE); - } - - _gcr_general_names_free (general_names); - - return TRUE; -} - - -static gboolean -append_extension_hex (GcrCertificateRenderer *self, GcrDisplayView *view, - GQuark oid, gconstpointer data, gsize n_data) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - const gchar *text; - - _gcr_display_view_append_heading (view, renderer, _("Extension")); - - /* Extension type */ - text = egg_oid_get_description (oid); - _gcr_display_view_append_value (view, renderer, _("Identifier"), text, FALSE); - _gcr_display_view_append_hex (view, renderer, _("Value"), data, n_data); - - return TRUE; -} - -static gboolean -append_extension (GcrCertificateRenderer *self, GcrDisplayView *view, - GNode *asn, const guchar *data, gsize n_data, gint index) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - GNode *node; - GQuark oid; - gsize n_value; - const guchar *value; - gboolean critical; - gboolean ret = FALSE; - - /* Make sure it is present */ - node = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL); - if (node == NULL) - return FALSE; - - /* Dig out the OID */ - oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (node, "extnID", NULL)); - g_return_val_if_fail (oid, FALSE); - - /* Extension value */ - value = egg_asn1x_get_raw_value (egg_asn1x_node (node, "extnValue", NULL), &n_value); - - /* The custom parsers */ - if (oid == GCR_OID_BASIC_CONSTRAINTS) - ret = append_extension_basic_constraints (self, view, value, n_value); - else if (oid == GCR_OID_EXTENDED_KEY_USAGE) - ret = append_extension_extended_key_usage (self, view, value, n_value); - else if (oid == GCR_OID_SUBJECT_KEY_IDENTIFIER) - ret = append_extension_subject_key_identifier (self, view, value, n_value); - else if (oid == GCR_OID_KEY_USAGE) - ret = append_extension_key_usage (self, view, value, n_value); - else if (oid == GCR_OID_SUBJECT_ALT_NAME) - ret = append_extension_subject_alt_name (self, view, value, n_value); - - /* Otherwise the default raw display */ - if (ret == FALSE) - ret = append_extension_hex (self, view, oid, value, n_value); - - /* Critical */ - if (ret == TRUE && egg_asn1x_get_boolean (egg_asn1x_node (node, "critical", NULL), &critical)) { - _gcr_display_view_append_value (view, renderer, _("Critical"), - critical ? _("Yes") : _("No"), FALSE); - } - - return ret; -} - -typedef struct _on_parsed_dn_args { - GcrCertificateRenderer *renderer; - GcrDisplayView *view; -} on_parsed_dn_args; - -static void -on_parsed_dn_part (guint index, GQuark oid, const guchar *value, - gsize n_value, gpointer user_data) -{ - GcrCertificateRenderer *self = ((on_parsed_dn_args*)user_data)->renderer; - GcrDisplayView *view = ((on_parsed_dn_args*)user_data)->view; - const gchar *attr; - const gchar *desc; - gchar *field = NULL; - gchar *display; - - g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self)); - - attr = egg_oid_get_name (oid); - desc = egg_oid_get_description (oid); - - /* Combine them into something sane */ - if (attr && desc) { - if (strcmp (attr, desc) == 0) - field = g_strdup (attr); - else - field = g_strdup_printf ("%s (%s)", attr, desc); - } else if (!attr && !desc) { - field = g_strdup (""); - } else if (attr) { - field = g_strdup (attr); - } else if (desc) { - field = g_strdup (desc); - } else { - g_assert_not_reached (); - } - - display = egg_dn_print_value (oid, value, n_value); - if (display == NULL) - display = g_strdup (""); - - _gcr_display_view_append_value (view, GCR_RENDERER (self), field, display, FALSE); - g_free (field); - g_free (display); -} - -static gboolean -on_delete_unref_dialog (GtkWidget *widget, GdkEvent *event, gpointer data) -{ - g_object_unref (widget); - return FALSE; -} - -static void -on_export_completed (GObject *source, GAsyncResult *result, gpointer user_data) -{ - GtkWindow *parent = GTK_WINDOW (user_data); - GcrCertificateExporter *exporter = GCR_CERTIFICATE_EXPORTER (source); - GError *error = NULL; - GtkWidget *dialog; - - if (!_gcr_certificate_exporter_export_finish (exporter, result, &error)) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - dialog = gtk_message_dialog_new_with_markup (parent, - GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, "<big>%s</big>\n\n%s", - _("Couldn't export the certificate."), - error->message); - gtk_widget_show (dialog); - g_signal_connect (dialog, "delete-event", - G_CALLBACK (on_delete_unref_dialog), NULL); - } - } - - /* Matches ref in on_certificate_export */ - if (parent) - g_object_unref (parent); -} - -static void -on_certificate_export (GtkMenuItem *menuitem, gpointer user_data) -{ - GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (user_data); - GcrCertificateExporter *exporter; - gchar *label; - GtkWidget *parent; - - label = calculate_label (self); - - parent = gtk_widget_get_toplevel (GTK_WIDGET (menuitem)); - if (parent && !GTK_IS_WINDOW (parent)) - parent = NULL; - - exporter = _gcr_certificate_exporter_new (GCR_CERTIFICATE (self), label, - GTK_WINDOW (parent)); - - g_free (label); - - _gcr_certificate_exporter_export_async (exporter, NULL, on_export_completed, - parent ? g_object_ref (parent) : NULL); -} - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static void -gcr_certificate_renderer_init (GcrCertificateRenderer *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRendererPrivate)); -} - -static void -gcr_certificate_renderer_dispose (GObject *obj) -{ - GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj); - - if (self->pv->opt_cert) - g_object_unref (self->pv->opt_cert); - self->pv->opt_cert = NULL; - - G_OBJECT_CLASS (gcr_certificate_renderer_parent_class)->dispose (obj); -} - -static void -gcr_certificate_renderer_finalize (GObject *obj) -{ - GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj); - - g_assert (!self->pv->opt_cert); - - if (self->pv->opt_attrs) - gck_attributes_unref (self->pv->opt_attrs); - self->pv->opt_attrs = NULL; - - g_free (self->pv->label); - self->pv->label = NULL; - - G_OBJECT_CLASS (gcr_certificate_renderer_parent_class)->finalize (obj); -} - -static void -gcr_certificate_renderer_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj); - - switch (prop_id) { - case PROP_CERTIFICATE: - gcr_certificate_renderer_set_certificate (self, g_value_get_object (value)); - break; - case PROP_LABEL: - g_free (self->pv->label); - self->pv->label = g_value_dup_string (value); - g_object_notify (obj, "label"); - gcr_renderer_emit_data_changed (GCR_RENDERER (self)); - break; - case PROP_ATTRIBUTES: - gcr_certificate_renderer_set_attributes (self, g_value_get_boxed (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_certificate_renderer_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (obj); - - switch (prop_id) { - case PROP_CERTIFICATE: - g_value_set_object (value, self->pv->opt_cert); - break; - case PROP_LABEL: - g_value_take_string (value, calculate_label (self)); - break; - case PROP_ATTRIBUTES: - g_value_set_boxed (value, self->pv->opt_attrs); - break; - default: - gcr_certificate_mixin_get_property (obj, prop_id, value, pspec); - break; - } -} - -static void -gcr_certificate_renderer_class_init (GcrCertificateRendererClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GckAttributes *registered; - - _gcr_oids_init (); - - gcr_certificate_renderer_parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private (klass, sizeof (GcrCertificateRendererPrivate)); - - gobject_class->dispose = gcr_certificate_renderer_dispose; - gobject_class->finalize = gcr_certificate_renderer_finalize; - gobject_class->set_property = gcr_certificate_renderer_set_property; - gobject_class->get_property = gcr_certificate_renderer_get_property; - - /** - * GcrCertificateRenderer:certificate: - * - * The certificate to display. May be %NULL. - */ - g_object_class_install_property (gobject_class, PROP_CERTIFICATE, - g_param_spec_object ("certificate", "Certificate", "Certificate to display.", - GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE)); - - /** - * GcrCertificateRenderer:attributes: - * - * The certificate attributes to display. One of the attributes must be - * a CKA_VALUE type attribute which contains a DER encoded certificate. - */ - g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, - g_param_spec_boxed ("attributes", "Attributes", "Certificate pkcs11 attributes", - GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE)); - - /** - * GcrCertificateRenderer:label: - * - * The label to display. - */ - g_object_class_install_property (gobject_class, PROP_LABEL, - g_param_spec_string ("label", "Label", "Certificate Label", - "", G_PARAM_READWRITE)); - - gcr_certificate_mixin_class_init (gobject_class); - - /* Register this as a renderer which can be loaded */ - registered = gck_attributes_new (); - gck_attributes_add_ulong (registered, CKA_CLASS, CKO_CERTIFICATE); - gcr_renderer_register (GCR_TYPE_CERTIFICATE_RENDERER, registered); - gck_attributes_unref (registered); -} - -static void -gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer) -{ - GcrCertificateRenderer *self; - gconstpointer data, value; - gsize n_data, n_value, n_raw; - GcrDisplayView *view; - on_parsed_dn_args args; - const gchar *text; - GcrCertificate *cert; - gpointer raw; - gconstpointer number; - gulong version; - guint bits, index; - gchar *display; - GNode *asn; - GQuark oid; - GDate date; - GIcon *icon; - - self = GCR_CERTIFICATE_RENDERER (renderer); - - if (GCR_IS_DISPLAY_VIEW (viewer)) { - view = GCR_DISPLAY_VIEW (viewer); - - } else { - g_warning ("GcrCertificateRenderer only works with internal specific " - "GcrViewer returned by gcr_viewer_new()."); - return; - } - - _gcr_display_view_begin (view, renderer); - cert = GCR_CERTIFICATE (self); - - data = gcr_certificate_get_der_data (cert, &n_data); - if (!data) { - _gcr_display_view_end (view, renderer); - return; - } - - icon = gcr_certificate_get_icon (cert); - _gcr_display_view_set_icon (view, GCR_RENDERER (self), icon); - g_object_unref (icon); - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data); - g_return_if_fail (asn); - - display = calculate_label (self); - _gcr_display_view_append_title (view, renderer, display); - g_free (display); - - display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), "CN"); - _gcr_display_view_append_content (view, renderer, _("Identity"), display); - g_free (display); - - display = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), "CN"); - _gcr_display_view_append_content (view, renderer, _("Verified by"), display); - g_free (display); - - if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) { - display = g_malloc0 (128); - if (!g_date_strftime (display, 128, "%x", &date)) - g_return_if_reached (); - _gcr_display_view_append_content (view, renderer, _("Expires"), display); - g_free (display); - } - - _gcr_display_view_start_details (view, renderer); - - args.renderer = self; - args.view = view; - - /* The subject */ - _gcr_display_view_append_heading (view, renderer, _("Subject Name")); - egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), on_parsed_dn_part, &args); - - /* The Issuer */ - _gcr_display_view_append_heading (view, renderer, _("Issuer Name")); - egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), on_parsed_dn_part, &args); - - /* The Issued Parameters */ - _gcr_display_view_append_heading (view, renderer, _("Issued Certificate")); - - if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "tbsCertificate", "version", NULL), &version)) - g_return_if_reached (); - display = g_strdup_printf ("%lu", version + 1); - _gcr_display_view_append_value (view, renderer, _("Version"), display, FALSE); - g_free (display); - - number = egg_asn1x_get_integer_as_raw (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL), &n_raw); - g_return_if_fail (number != NULL); - _gcr_display_view_append_hex (view, renderer, _("Serial Number"), number, n_raw); - - display = g_malloc0 (128); - if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notBefore", NULL), &date)) { - if (!g_date_strftime (display, 128, "%Y-%m-%d", &date)) - g_return_if_reached (); - _gcr_display_view_append_value (view, renderer, _("Not Valid Before"), display, FALSE); - } - if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) { - if (!g_date_strftime (display, 128, "%Y-%m-%d", &date)) - g_return_if_reached (); - _gcr_display_view_append_value (view, renderer, _("Not Valid After"), display, FALSE); - } - g_free (display); - - /* Fingerprints */ - _gcr_display_view_append_heading (view, renderer, _("Certificate Fingerprints")); - - _gcr_display_view_append_fingerprint (view, renderer, data, n_data, "SHA1", G_CHECKSUM_SHA1); - _gcr_display_view_append_fingerprint (view, renderer, data, n_data, "MD5", G_CHECKSUM_MD5); - - /* Signature */ - _gcr_display_view_append_heading (view, renderer, _("Signature")); - - oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL)); - text = egg_oid_get_description (oid); - _gcr_display_view_append_value (view, renderer, _("Signature Algorithm"), text, FALSE); - - value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL), &n_value); - if (value && n_value) - _gcr_display_view_append_hex (view, renderer, _("Signature Parameters"), value, n_value); - - raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "signature", NULL), NULL, &bits); - g_return_if_fail (raw); - _gcr_display_view_append_hex (view, renderer, _("Signature"), raw, bits / 8); - g_free (raw); - - /* Public Key Info */ - _gcr_display_view_append_heading (view, renderer, _("Public Key Info")); - - oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", - "algorithm", "algorithm", NULL)); - text = egg_oid_get_description (oid); - _gcr_display_view_append_value (view, renderer, _("Key Algorithm"), text, FALSE); - - value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", - "algorithm", "parameters", NULL), &n_value); - if (value && n_value) - _gcr_display_view_append_hex (view, renderer, _("Key Parameters"), value, n_value); - - bits = gcr_certificate_get_key_size (cert); - if (bits > 0) { - display = g_strdup_printf ("%u", bits); - _gcr_display_view_append_value (view, renderer, _("Key Size"), display, FALSE); - g_free (display); - } - - value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate", - "subjectPublicKeyInfo", NULL), &n_value); - raw = gcr_fingerprint_from_subject_public_key_info (value, n_value, G_CHECKSUM_SHA1, &n_raw); - _gcr_display_view_append_hex (view, renderer, _("Key SHA1 Fingerprint"), raw, n_raw); - g_free (raw); - - raw = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", - "subjectPublicKey", NULL), NULL, &bits); - g_return_if_fail (raw); - _gcr_display_view_append_hex (view, renderer, _("Public Key"), raw, bits / 8); - g_free (raw); - - /* Extensions */ - for (index = 1; TRUE; ++index) { - if (!append_extension (self, view, asn, data, n_data, index)) - break; - } - - egg_asn1x_destroy (asn); - _gcr_display_view_end (view, renderer); -} - -static void -gcr_certificate_renderer_populate_popup (GcrRenderer *self, GcrViewer *viewer, - GtkMenu *menu) -{ - GtkWidget *item; - - item = gtk_separator_menu_item_new (); - gtk_widget_show (item); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); - - item = gtk_menu_item_new_with_label ("Export Certificate..."); - gtk_widget_show (item); - g_signal_connect_data (item, "activate", G_CALLBACK (on_certificate_export), - g_object_ref (self), (GClosureNotify)g_object_unref, 0); - gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), item); -} - -static void -gcr_renderer_iface_init (GcrRendererIface *iface) -{ - iface->populate_popup = gcr_certificate_renderer_populate_popup; - iface->render_view = gcr_certificate_renderer_render; -} - -static const guchar * -gcr_certificate_renderer_get_der_data (GcrCertificate *cert, - gsize *n_data) -{ - GcrCertificateRenderer *self = GCR_CERTIFICATE_RENDERER (cert); - GckAttribute *attr; - - g_assert (n_data); - - if (self->pv->opt_cert) - return gcr_certificate_get_der_data (self->pv->opt_cert, n_data); - - if (self->pv->opt_attrs) { - attr = gck_attributes_find (self->pv->opt_attrs, CKA_VALUE); - g_return_val_if_fail (attr, NULL); - *n_data = attr->length; - return attr->value; - } - - return NULL; -} - -static void -gcr_renderer_certificate_iface_init (GcrCertificateIface *iface) -{ - iface->get_der_data = gcr_certificate_renderer_get_der_data; -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_certificate_renderer_new: - * @certificate: The certificate to display - * - * Create a new certificate renderer to display the certificate. - * - * Returns: (transfer full): a newly allocated #GcrCertificateRenderer, which - * should be released with g_object_unref() - */ -GcrCertificateRenderer * -gcr_certificate_renderer_new (GcrCertificate *certificate) -{ - return g_object_new (GCR_TYPE_CERTIFICATE_RENDERER, "certificate", certificate, NULL); -} - -/** - * gcr_certificate_renderer_new_for_attributes: - * @label: (allow-none): the label to display - * @attrs: The attributes to display - * - * Create a new certificate renderer to display the label and attributes. One - * of the attributes should be a CKA_VALUE type attribute containing a DER - * encoded certificate. - * - * Returns: (transfer full): a newly allocated #GcrCertificateRenderer, which - * should be released with g_object_unref() - */ -GcrCertificateRenderer * -gcr_certificate_renderer_new_for_attributes (const gchar *label, struct _GckAttributes *attrs) -{ - return g_object_new (GCR_TYPE_CERTIFICATE_RENDERER, "label", label, "attributes", attrs, NULL); -} - -/** - * gcr_certificate_renderer_get_certificate: - * @self: The renderer - * - * Get the certificate displayed in the renderer. If no certificate was - * explicitly set, then the renderer will return itself since it acts as - * a valid certificate. - * - * Returns: (transfer none): The certificate, owned by the renderer. - */ -GcrCertificate * -gcr_certificate_renderer_get_certificate (GcrCertificateRenderer *self) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE_RENDERER (self), NULL); - if (self->pv->opt_cert) - return self->pv->opt_cert; - return GCR_CERTIFICATE (self); -} - -/** - * gcr_certificate_renderer_set_certificate: - * @self: The renderer - * @certificate: (allow-none): the certificate to display - * - * Set a certificate to display in the renderer. - */ -void -gcr_certificate_renderer_set_certificate (GcrCertificateRenderer *self, GcrCertificate *certificate) -{ - g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self)); - - if (self->pv->opt_cert) - g_object_unref (self->pv->opt_cert); - self->pv->opt_cert = certificate; - if (self->pv->opt_cert) - g_object_ref (self->pv->opt_cert); - - if (self->pv->opt_attrs) { - gck_attributes_unref (self->pv->opt_attrs); - self->pv->opt_attrs = NULL; - } - - gcr_renderer_emit_data_changed (GCR_RENDERER (self)); - g_object_notify (G_OBJECT (self), "certificate"); -} - -/** - * gcr_certificate_renderer_get_attributes: - * @self: The renderer - * - * Get the PKCS\#11 attributes, if any, set for this renderer to display. - * - * Returns: (allow-none) (transfer none): the attributes, owned by the renderer - */ -GckAttributes * -gcr_certificate_renderer_get_attributes (GcrCertificateRenderer *self) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE_RENDERER (self), NULL); - return self->pv->opt_attrs; -} - -/** - * gcr_certificate_renderer_set_attributes: - * @self: The renderer - * @attrs: (allow-none): attributes to set - * - * Set the PKCS\#11 attributes for this renderer to display. One of the attributes - * should be a CKA_VALUE type attribute containing a DER encoded certificate. - */ -void -gcr_certificate_renderer_set_attributes (GcrCertificateRenderer *self, GckAttributes *attrs) -{ - g_return_if_fail (GCR_IS_CERTIFICATE_RENDERER (self)); - - gck_attributes_unref (self->pv->opt_attrs); - self->pv->opt_attrs = attrs; - - if (self->pv->opt_attrs) - gck_attributes_ref (self->pv->opt_attrs); - - if (self->pv->opt_cert) { - g_object_unref (self->pv->opt_cert); - g_object_notify (G_OBJECT (self), "certificate"); - self->pv->opt_cert = NULL; - } - - gcr_renderer_emit_data_changed (GCR_RENDERER (self)); - g_object_notify (G_OBJECT (self), "attributes"); - -} diff --git a/gcr/gcr-certificate-renderer.h b/gcr/gcr-certificate-renderer.h deleted file mode 100644 index 6167dd5a..00000000 --- a/gcr/gcr-certificate-renderer.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_CERTIFICATE_RENDERER_H__ -#define __GCR_CERTIFICATE_RENDERER_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-certificate.h" -#include "gcr-renderer.h" -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_CERTIFICATE_RENDERER (gcr_certificate_renderer_get_type ()) -#define GCR_CERTIFICATE_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRenderer)) -#define GCR_CERTIFICATE_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRendererClass)) -#define GCR_IS_CERTIFICATE_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_RENDERER)) -#define GCR_IS_CERTIFICATE_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_RENDERER)) -#define GCR_CERTIFICATE_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_RENDERER, GcrCertificateRendererClass)) - -typedef struct _GcrCertificateRenderer GcrCertificateRenderer; -typedef struct _GcrCertificateRendererClass GcrCertificateRendererClass; -typedef struct _GcrCertificateRendererPrivate GcrCertificateRendererPrivate; - -struct _GcrCertificateRenderer { - GObject parent; - - /*< private >*/ - GcrCertificateRendererPrivate *pv; -}; - -struct _GcrCertificateRendererClass { - GObjectClass parent_class; -}; - -GType gcr_certificate_renderer_get_type (void); - -GcrCertificateRenderer* gcr_certificate_renderer_new (GcrCertificate *certificate); - -GcrCertificateRenderer* gcr_certificate_renderer_new_for_attributes (const gchar *label, - struct _GckAttributes *attrs); - -GcrCertificate* gcr_certificate_renderer_get_certificate (GcrCertificateRenderer *self); - -void gcr_certificate_renderer_set_certificate (GcrCertificateRenderer *self, - GcrCertificate *certificate); - -GckAttributes* gcr_certificate_renderer_get_attributes (GcrCertificateRenderer *self); - -void gcr_certificate_renderer_set_attributes (GcrCertificateRenderer *self, - GckAttributes *attrs); - -G_END_DECLS - -#endif /* __GCR_CERTIFICATE_RENDERER_H__ */ diff --git a/gcr/gcr-certificate-widget.c b/gcr/gcr-certificate-widget.c deleted file mode 100644 index 6ffdd443..00000000 --- a/gcr/gcr-certificate-widget.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-certificate.h" -#include "gcr-certificate-renderer.h" -#include "gcr-certificate-widget.h" -#include "gcr-renderer.h" -#include "gcr-viewer.h" - -#include "gck/gck.h" - -#include <gdk/gdk.h> -#include <glib/gi18n-lib.h> - -/** - * SECTION:gcr-certificate-widget - * @title: GcrCertificateWidget - * @short_description: Certificate widget and renderer - * - * A #GcrCertificateWidget can be used to display a certificate. The widget - * is normally in a collapsed state showing only details, but can be expanded - * by the user. - * - * Use gcr_certificate_widget_new() to create a new certificate widget. Only - * one certificate can be displayed. A #GcrCertificateWidget contains a - * #GcrViewer internally and #GcrCertificateRenderer is used to render the - * certificate to the viewer. To show more than one certificate in a view, - * create the viewer and add renderers to it. - */ - -/** - * GcrCertificateWidget: - * - * A widget that displays a certificate. - */ - -/** - * GcrCertificateWidgetClass: - * - * The class for #GcrCertificateWidget - */ - -enum { - PROP_0, - PROP_CERTIFICATE, - PROP_ATTRIBUTES -}; - -struct _GcrCertificateWidget { - /*< private >*/ - GtkAlignment parent; - GcrCertificateWidgetPrivate *pv; -}; - -struct _GcrCertificateWidgetClass { - /*< private >*/ - GtkAlignmentClass parent_class; -}; - -struct _GcrCertificateWidgetPrivate { - GcrViewer *viewer; - GcrCertificateRenderer *renderer; -}; - -G_DEFINE_TYPE (GcrCertificateWidget, gcr_certificate_widget, GTK_TYPE_ALIGNMENT); - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static GObject* -gcr_certificate_widget_constructor (GType type, guint n_props, GObjectConstructParam *props) -{ - GObject *obj = G_OBJECT_CLASS (gcr_certificate_widget_parent_class)->constructor (type, n_props, props); - GcrCertificateWidget *self = NULL; - - g_return_val_if_fail (obj, NULL); - - self = GCR_CERTIFICATE_WIDGET (obj); - - self->pv->viewer = gcr_viewer_new_scrolled (); - gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->pv->viewer)); - gtk_widget_show (GTK_WIDGET (self->pv->viewer)); - - gcr_viewer_add_renderer (self->pv->viewer, GCR_RENDERER (self->pv->renderer)); - return obj; -} - -static void -gcr_certificate_widget_init (GcrCertificateWidget *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_WIDGET, GcrCertificateWidgetPrivate)); - self->pv->renderer = gcr_certificate_renderer_new (NULL); -} - -static void -gcr_certificate_widget_finalize (GObject *obj) -{ - GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (obj); - - g_assert (self->pv->renderer); - g_object_unref (self->pv->renderer); - self->pv->renderer = NULL; - - g_assert (self->pv->viewer); - self->pv->viewer = NULL; - - G_OBJECT_CLASS (gcr_certificate_widget_parent_class)->finalize (obj); -} - -static void -gcr_certificate_widget_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (obj); - - switch (prop_id) { - case PROP_CERTIFICATE: - gcr_certificate_widget_set_certificate (self, g_value_get_object (value)); - break; - case PROP_ATTRIBUTES: - gcr_certificate_widget_set_attributes (self, g_value_get_boxed (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_certificate_widget_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrCertificateWidget *self = GCR_CERTIFICATE_WIDGET (obj); - - switch (prop_id) { - case PROP_CERTIFICATE: - g_value_set_object (value, gcr_certificate_widget_get_certificate (self)); - break; - case PROP_ATTRIBUTES: - g_value_set_boxed (value, gcr_certificate_widget_get_attributes (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_certificate_widget_class_init (GcrCertificateWidgetClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gcr_certificate_widget_parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private (klass, sizeof (GcrCertificateWidgetPrivate)); - - gobject_class->constructor = gcr_certificate_widget_constructor; - gobject_class->finalize = gcr_certificate_widget_finalize; - gobject_class->set_property = gcr_certificate_widget_set_property; - gobject_class->get_property = gcr_certificate_widget_get_property; - - g_object_class_install_property (gobject_class, PROP_CERTIFICATE, - g_param_spec_object("certificate", "Certificate", "Certificate to display.", - GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, - g_param_spec_boxed ("attributes", "Attributes", "Attributes which contain the certificate", - GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE)); -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_certificate_widget_new: - * @certificate: (allow-none): certificate to display, or %NULL - * - * Create a new certificate widget which displays a given certificate. - * - * Returns: (transfer full): a newly allocated #GcrCertificateWidget, which - * should be freed with g_object_unref() - */ -GcrCertificateWidget * -gcr_certificate_widget_new (GcrCertificate *certificate) -{ - return g_object_new (GCR_TYPE_CERTIFICATE_WIDGET, "certificate", certificate, NULL); -} - -/** - * gcr_certificate_widget_get_certificate: - * @self: The certificate widget - * - * Get the certificate displayed in the widget. - * - * Returns: (allow-none) (transfer none): the certificate - */ -GcrCertificate * -gcr_certificate_widget_get_certificate (GcrCertificateWidget *self) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE_WIDGET (self), NULL); - return gcr_certificate_renderer_get_certificate (self->pv->renderer); -} - -/** - * gcr_certificate_widget_set_certificate: - * @self: The certificate widget - * @certificate: (allow-none): the certificate to display - * - * Set the certificate displayed in the widget - */ -void -gcr_certificate_widget_set_certificate (GcrCertificateWidget *self, GcrCertificate *certificate) -{ - g_return_if_fail (GCR_IS_CERTIFICATE_WIDGET (self)); - gcr_certificate_renderer_set_certificate (self->pv->renderer, certificate); -} - -/** - * gcr_certificate_widget_get_attributes: - * @self: The certificate widget - * - * Get the attributes displayed in the widget. The attributes should contain - * a certificate. - * - * Returns: (allow-none) (transfer none): the attributes, owned by the widget - */ -GckAttributes * -gcr_certificate_widget_get_attributes (GcrCertificateWidget *self) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE_WIDGET (self), NULL); - return gcr_certificate_renderer_get_attributes (self->pv->renderer); -} - -/** - * gcr_certificate_widget_set_attributes: - * @self: The certificate widget - * @attrs: (allow-none): the attributes to display - * - * Set the attributes displayed in the widget. The attributes should contain - * a certificate. - */ -void -gcr_certificate_widget_set_attributes (GcrCertificateWidget *self, GckAttributes* attrs) -{ - g_return_if_fail (GCR_IS_CERTIFICATE_WIDGET (self)); - gcr_certificate_renderer_set_attributes (self->pv->renderer, attrs); -} diff --git a/gcr/gcr-certificate-widget.h b/gcr/gcr-certificate-widget.h deleted file mode 100644 index 3ad2f194..00000000 --- a/gcr/gcr-certificate-widget.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_CERTIFICATE_WIDGET_H__ -#define __GCR_CERTIFICATE_WIDGET_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-certificate.h" -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_CERTIFICATE_WIDGET (gcr_certificate_widget_get_type ()) -#define GCR_CERTIFICATE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_WIDGET, GcrCertificateWidget)) -#define GCR_CERTIFICATE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_WIDGET, GcrCertificateWidgetClass)) -#define GCR_IS_CERTIFICATE_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_WIDGET)) -#define GCR_IS_CERTIFICATE_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_WIDGET)) -#define GCR_CERTIFICATE_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_WIDGET, GcrCertificateWidgetClass)) - -typedef struct _GcrCertificateWidget GcrCertificateWidget; -typedef struct _GcrCertificateWidgetClass GcrCertificateWidgetClass; -typedef struct _GcrCertificateWidgetPrivate GcrCertificateWidgetPrivate; - -/* - * TODO: GcrCertificateWidget and GcrCertificateWidgetClass are hidden until - * we can figure out what they should be derived from. - */ - -GType gcr_certificate_widget_get_type (void); - -GcrCertificateWidget* gcr_certificate_widget_new (GcrCertificate *certificate); - -GcrCertificate* gcr_certificate_widget_get_certificate (GcrCertificateWidget *self); - -void gcr_certificate_widget_set_certificate (GcrCertificateWidget *self, - GcrCertificate *certificate); - -GckAttributes* gcr_certificate_widget_get_attributes (GcrCertificateWidget *self); - -void gcr_certificate_widget_set_attributes (GcrCertificateWidget *self, - GckAttributes* attrs); - -G_END_DECLS - -#endif /* __GCR_CERTIFICATE_WIDGET_H__ */ diff --git a/gcr/gcr-certificate.c b/gcr/gcr-certificate.c deleted file mode 100644 index 95b513c3..00000000 --- a/gcr/gcr-certificate.c +++ /dev/null @@ -1,1082 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-certificate.h" -#include "gcr-comparable.h" -#include "gcr-icons.h" -#include "gcr-internal.h" -#include "gcr-oids.h" - -#include "egg/egg-asn1x.h" -#include "egg/egg-asn1-defs.h" -#include "egg/egg-dn.h" -#include "egg/egg-hex.h" - -#include <string.h> -#include <glib/gi18n-lib.h> - -/** - * SECTION:gcr-certificate - * @title: GcrCertificate - * @short_description: Represents an X.509 certificate - * - * This is an interface that represents an X.509 certificate. Objects can - * implement this interface to make a certificate usable with the GCR - * library. - * - * Various methods are available to parse out relevant bits of the certificate. - * However no verification of the validity of a certificate is done here. Use - * your favorite crypto library to do this. - * - * You can use #GcrSimpleCertificate to simply load a certificate for which - * you already have the raw certificate data. - * - * The #GcrCertificate interface has several properties that must be implemented. - * You can use a mixin to implement these properties if desired. See the - * gcr_certificate_mixin_class_init() and gcr_certificate_mixin_get_property() - * functions. - * - * All certificates are comparable. If implementing a #GcrCertificate, you can - * use GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE() to implement the #GcrComparable - * interface. - */ - -/** - * GcrCertificate: - * - * An object which holds a certificate. - */ - -/** - * GcrCertificateIface: - * @parent: the parent interface type - * @get_der_data: a method which returns the RAW der data of the certificate - * - * The interface that implementors of #GcrCertificate must implement. - */ - -/** - * GCR_CERTIFICATE_COLUMNS: - * - * The columns that are valid for a certificate. This is to be used with - * the #GcrTreeSelector or #GcrCollectionModel. - * - * This is an array of #GcrColumn, owned by the gcr library. - */ - -/* - * The DER data in this structure is owned by the derived class. - * It is only valid for the duration of the current call stack - * after we call gcr_certificate_get_der_data(). We shouldn't - * save it anywhere else. - * - * We keep the pointer around and compare it so that if the derived - * class returns exactly the same pointer and size, then we can - * keep from parsing things over again. - */ - -typedef struct _GcrCertificateInfo { - gconstpointer der; - gsize n_der; - GNode *asn1; - guint key_size; -} GcrCertificateInfo; - -/* Forward declarations */ - -static gconstpointer _gcr_certificate_get_subject_const (GcrCertificate *self, gsize *n_data); -static gconstpointer _gcr_certificate_get_issuer_const (GcrCertificate *self, gsize *n_data); - -enum { - PROP_FIRST = 0x0007000, - PROP_LABEL, - PROP_MARKUP, - PROP_DESCRIPTION, - PROP_ICON, - PROP_SUBJECT, - PROP_ISSUER, - PROP_EXPIRY -}; - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -static GQuark CERTIFICATE_INFO = 0; - -static void -certificate_info_free (gpointer data) -{ - GcrCertificateInfo *info = data; - if (info) { - g_assert (info->asn1); - egg_asn1x_destroy (info->asn1); - g_free (info); - } -} - -static GcrCertificateInfo* -certificate_info_load (GcrCertificate *cert) -{ - GcrCertificateInfo *info; - GNode *asn1; - gconstpointer der; - gsize n_der; - - g_assert (GCR_IS_CERTIFICATE (cert)); - - der = gcr_certificate_get_der_data (cert, &n_der); - g_return_val_if_fail (der, NULL); - - info = g_object_get_qdata (G_OBJECT (cert), CERTIFICATE_INFO); - if (info != NULL) { - if (n_der == info->n_der && der == info->der) - return info; - } - - /* Cache is invalid or non existent */ - asn1 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", der, n_der); - if (asn1 == NULL) { - g_warning ("a derived class provided an invalid or unparseable X.509 DER certificate data."); - return NULL; - } - - info = g_new0 (GcrCertificateInfo, 1); - info->der = der; - info->n_der = n_der; - info->asn1 = asn1; - - g_object_set_qdata_full (G_OBJECT (cert), CERTIFICATE_INFO, info, certificate_info_free); - return info; -} - -static guint -calculate_rsa_key_size (gconstpointer data, gsize n_data) -{ - GNode *asn; - gsize n_content; - - asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data, n_data); - g_return_val_if_fail (asn, 0); - - if (!egg_asn1x_get_raw_value (egg_asn1x_node (asn, "modulus", NULL), &n_content)) - g_return_val_if_reached (0); - - egg_asn1x_destroy (asn); - - /* Removes the complement */ - return (n_content / 2) * 2 * 8; -} - -static guint -calculate_dsa_params_size (gconstpointer data, gsize n_data) -{ - GNode *asn; - gsize n_content; - - asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", data, n_data); - g_return_val_if_fail (asn, 0); - - if (!egg_asn1x_get_raw_value (egg_asn1x_node (asn, "p", NULL), &n_content)) - g_return_val_if_reached (0); - - egg_asn1x_destroy (asn); - - /* Removes the complement */ - return (n_content / 2) * 2 * 8; -} - -static guint -calculate_key_size (GcrCertificateInfo *info) -{ - GNode *asn; - gconstpointer data, params; - gsize n_data, n_params; - guint key_size = 0, n_bits; - guchar *key = NULL; - GQuark oid; - - data = egg_asn1x_get_raw_element (egg_asn1x_node (info->asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL), &n_data); - g_return_val_if_fail (data != NULL, 0); - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectPublicKeyInfo", data, n_data); - g_return_val_if_fail (asn, 0); - - /* Figure out the algorithm */ - oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "algorithm", "algorithm", NULL)); - g_return_val_if_fail (oid, 0); - - /* RSA keys are stored in the main subjectPublicKey field */ - if (oid == GCR_OID_PKIX1_RSA) { - - /* A bit string so we cannot process in place */ - key = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "subjectPublicKey", NULL), NULL, &n_bits); - g_return_val_if_fail (key, 0); - key_size = calculate_rsa_key_size (key, n_bits / 8); - g_free (key); - - /* The DSA key size is discovered by the prime in params */ - } else if (oid == GCR_OID_PKIX1_DSA) { - params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "algorithm", "parameters", NULL), &n_params); - key_size = calculate_dsa_params_size (params, n_params); - - } else { - g_message ("unsupported key algorithm in certificate: %s", g_quark_to_string (oid)); - } - - egg_asn1x_destroy (asn); - - return key_size; -} - -static GChecksum* -digest_certificate (GcrCertificate *self, GChecksumType type) -{ - GChecksum *digest; - gconstpointer der; - gsize n_der; - - g_assert (GCR_IS_CERTIFICATE (self)); - - der = gcr_certificate_get_der_data (self, &n_der); - g_return_val_if_fail (der, NULL); - - digest = g_checksum_new (type); - g_return_val_if_fail (digest, NULL); - - g_checksum_update (digest, der, n_der); - return digest; -} - -static gchar* -calculate_markup (GcrCertificate *self) -{ - gchar *label = NULL; - gchar *issuer; - gchar *markup; - - g_object_get (self, "label", &label, NULL); - issuer = gcr_certificate_get_issuer_cn (self); - - if (issuer) - markup = g_markup_printf_escaped ("%s\n<small>Issued by: %s</small>", label, issuer); - else - markup = g_markup_printf_escaped ("%s\n<small>Issued by: <i>No name</i></small>", label); - - g_free (label); - g_free (issuer); - return markup; -} - -static void -on_transform_date_to_string (const GValue *src, GValue *dest) -{ - static const gsize len = 256; - GDate *date; - gchar *result; - - g_return_if_fail (G_VALUE_TYPE (src) == G_TYPE_DATE); - - date = g_value_get_boxed (src); - g_return_if_fail (date); - - result = g_malloc0 (len); - if (!g_date_strftime (result, len, "%x", date)) { - g_free (result); - result = NULL; - } - - g_value_take_string (dest, result); -} - -/* --------------------------------------------------------------------------------- - * INTERFACE - */ - -static void -gcr_certificate_default_init (GcrCertificateIface *iface) -{ - static volatile gsize initialized = 0; - - if (g_once_init_enter (&initialized)) { - _gcr_oids_init (); - - CERTIFICATE_INFO = g_quark_from_static_string ("_gcr_certificate_certificate_info"); - - g_object_interface_install_property (iface, - g_param_spec_string ("label", "Label", "Certificate label", - "", G_PARAM_READABLE)); - - g_object_interface_install_property (iface, - g_param_spec_string ("description", "Description", "Description of object being rendered", - "", G_PARAM_READABLE)); - - g_object_interface_install_property (iface, - g_param_spec_string ("markup", "Markup", "Markup which describes object being rendered", - "", G_PARAM_READABLE)); - - g_object_interface_install_property (iface, - g_param_spec_object ("icon", "Icon", "Icon for the object being rendered", - G_TYPE_ICON, G_PARAM_READABLE)); - - g_object_interface_install_property (iface, - g_param_spec_string ("subject", "Subject", "Common name of subject", - "", G_PARAM_READABLE)); - - g_object_interface_install_property (iface, - g_param_spec_string ("issuer", "Issuer", "Common name of issuer", - "", G_PARAM_READABLE)); - - g_object_interface_install_property (iface, - g_param_spec_boxed ("expiry", "Expiry", "Certificate expiry", - G_TYPE_DATE, G_PARAM_READABLE)); - - g_once_init_leave (&initialized, 1); - } -} - -typedef GcrCertificateIface GcrCertificateInterface; - -G_DEFINE_INTERFACE (GcrCertificate, gcr_certificate, GCR_TYPE_COMPARABLE); - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_certificate_get_columns: (skip) - * - * Get the columns appropriate for a certificate - * - * Returns: (transfer none): the columns - */ -const GcrColumn* -gcr_certificate_get_columns (void) -{ - static GcrColumn columns[] = { - { "icon", /* later */ 0, /* later */ 0, NULL, 0 }, - { "label", G_TYPE_STRING, G_TYPE_STRING, NC_("column", "Name"), - GCR_COLUMN_SORTABLE }, - { "issuer", G_TYPE_STRING, G_TYPE_STRING, NC_("column", "Issued By"), - GCR_COLUMN_SORTABLE }, - { "expiry", /* later */ 0, G_TYPE_STRING, NC_("column", "Expires"), - GCR_COLUMN_SORTABLE, on_transform_date_to_string }, - { NULL } - }; - - columns[0].property_type = columns[0].column_type = G_TYPE_ICON; - columns[3].property_type = G_TYPE_DATE; - return columns; -} - -/** - * gcr_certificate_compare: - * @first: (allow-none): the certificate to compare - * @other: (allow-none): the certificate to compare against - * - * Compare one certificate against another. If the certificates are equal - * then zero is returned. If one certificate is %NULL or not a certificate, - * then a non-zero value is returned. - * - * The return value is useful in a stable sort, but has no user logical - * meaning. - * - * Returns: zero if the certificates match, non-zero otherwise. - */ -gint -gcr_certificate_compare (GcrComparable *first, GcrComparable *other) -{ - gconstpointer data1, data2; - gsize size1, size2; - - if (!GCR_IS_CERTIFICATE (first)) - first = NULL; - if (!GCR_IS_CERTIFICATE (other)) - other = NULL; - - if (first == other) - return TRUE; - if (!first) - return 1; - if (!other) - return -1; - - data1 = gcr_certificate_get_der_data (GCR_CERTIFICATE (first), &size1); - data2 = gcr_certificate_get_der_data (GCR_CERTIFICATE (other), &size2); - - return gcr_comparable_memcmp (data1, size1, data2, size2); -} - - -/** - * gcr_certificate_get_der_data: - * @self: a #GcrCertificate - * @n_data: a pointer to a location to store the size of the resulting DER data. - * - * Gets the raw DER data for an X.509 certificate. - * - * Returns: (array length=n_data): raw DER data of the X.509 certificate - **/ -const guchar * -gcr_certificate_get_der_data (GcrCertificate *self, - gsize *n_data) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - g_return_val_if_fail (n_data != NULL, NULL); - g_return_val_if_fail (GCR_CERTIFICATE_GET_INTERFACE (self)->get_der_data, NULL); - return GCR_CERTIFICATE_GET_INTERFACE (self)->get_der_data (self, n_data); -} - -/** - * gcr_certificate_get_issuer_cn: - * @self: a #GcrCertificate - * - * Get the common name of the issuer of this certificate. - * - * The string returned should be freed by the caller when no longer - * required. - * - * Returns: The allocated issuer CN, or NULL if no issuer CN present. - */ -gchar* -gcr_certificate_get_issuer_cn (GcrCertificate *self) -{ - return gcr_certificate_get_issuer_part (self, "cn"); -} - -/** - * gcr_certificate_get_issuer_part: - * @self: a #GcrCertificate - * @part: a DN type string or OID. - * - * Get a part of the DN of the issuer of this certificate. - * - * Examples of a @part might be the 'OU' (organizational unit) - * or the 'CN' (common name). Only the value of that part - * of the DN is returned. - * - * The string returned should be freed by the caller when no longer - * required. - * - * Returns: (allow-none): the allocated part of the issuer DN, or %NULL if no - * such part is present - */ -gchar * -gcr_certificate_get_issuer_part (GcrCertificate *self, const char *part) -{ - GcrCertificateInfo *info; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - g_return_val_if_fail (part != NULL, NULL); - - info = certificate_info_load (self); - g_return_val_if_fail (info, NULL); - - return egg_dn_read_part (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL), part); -} - -static gconstpointer -_gcr_certificate_get_issuer_const (GcrCertificate *self, gsize *n_data) -{ - GcrCertificateInfo *info; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - g_return_val_if_fail (n_data != NULL, NULL); - - info = certificate_info_load (self); - g_return_val_if_fail (info, NULL); - - return egg_asn1x_get_raw_element (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", NULL), n_data); -} - -/** - * gcr_certificate_get_issuer_raw: - * @self: a #GcrCertificate - * @n_data: The length of the returned data. - * - * Get the raw DER data for the issuer DN of the certificate. - * - * The data should be freed by using g_free() when no longer required. - * - * Returns: (transfer full) (array length=n_data): allocated memory containing - * the raw issuer - */ -guchar * -gcr_certificate_get_issuer_raw (GcrCertificate *self, - gsize *n_data) -{ - gconstpointer data; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - g_return_val_if_fail (n_data != NULL, NULL); - - data = _gcr_certificate_get_issuer_const (self, n_data); - return g_memdup (data, data ? *n_data : 0); -} - -/** - * gcr_certificate_is_issuer: - * @self: a #GcrCertificate - * @issuer: a possible issuer #GcrCertificate - * - * Check if @issuer could be the issuer of this certificate. This is done by - * comparing the relevant subject and issuer fields. No signature check is - * done. Proper verification of certificates must be done via a crypto - * library. - * - * Returns: whether @issuer could be the issuer of the certificate. - */ -gboolean -gcr_certificate_is_issuer (GcrCertificate *self, GcrCertificate *issuer) -{ - gconstpointer subject_dn, issuer_dn; - gsize n_subject_dn, n_issuer_dn; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), FALSE); - g_return_val_if_fail (GCR_IS_CERTIFICATE (issuer), FALSE); - - subject_dn = _gcr_certificate_get_subject_const (issuer, &n_subject_dn); - g_return_val_if_fail (subject_dn, FALSE); - - issuer_dn = _gcr_certificate_get_issuer_const (self, &n_issuer_dn); - g_return_val_if_fail (issuer_dn, FALSE); - - return (n_issuer_dn == n_subject_dn && - memcmp (issuer_dn, subject_dn, n_issuer_dn) == 0); -} - -/** - * gcr_certificate_get_issuer_dn: - * @self: a #GcrCertificate - * - * Get the full issuer DN of the certificate as a (mostly) - * readable string. - * - * The string returned should be freed by the caller when no longer - * required. - * - * Returns: The allocated issuer DN of the certificate. - */ -gchar* -gcr_certificate_get_issuer_dn (GcrCertificate *self) -{ - GcrCertificateInfo *info; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - - info = certificate_info_load (self); - g_return_val_if_fail (info, NULL); - - return egg_dn_read (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL)); -} - -/** - * gcr_certificate_get_subject_cn: - * @self: a #GcrCertificate - * - * Get the common name of the subject of this certificate. - * - * The string returned should be freed by the caller when no longer - * required. - * - * Returns: The allocated subject CN, or NULL if no subject CN present. - */ -gchar* -gcr_certificate_get_subject_cn (GcrCertificate *self) -{ - return gcr_certificate_get_subject_part (self, "cn"); -} - -/** - * gcr_certificate_get_subject_part: - * @self: a #GcrCertificate - * @part: a DN type string or OID. - * - * Get a part of the DN of the subject of this certificate. - * - * Examples of a @part might be the 'OU' (organizational unit) - * or the 'CN' (common name). Only the value of that part - * of the DN is returned. - * - * The string returned should be freed by the caller when no longer - * required. - * - * Returns: (allow-none): the allocated part of the subject DN, or %NULL if no - * such part is present. - */ -gchar* -gcr_certificate_get_subject_part (GcrCertificate *self, const char *part) -{ - GcrCertificateInfo *info; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - g_return_val_if_fail (part != NULL, NULL); - - info = certificate_info_load (self); - g_return_val_if_fail (info, NULL); - - return egg_dn_read_part (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", "rdnSequence", NULL), part); -} - -/** - * gcr_certificate_get_subject_dn: - * @self: a #GcrCertificate - * - * Get the full subject DN of the certificate as a (mostly) - * readable string. - * - * The string returned should be freed by the caller when no longer - * required. - * - * Returns: The allocated subject DN of the certificate. - */ -gchar* -gcr_certificate_get_subject_dn (GcrCertificate *self) -{ - GcrCertificateInfo *info; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - - info = certificate_info_load (self); - g_return_val_if_fail (info, NULL); - - return egg_dn_read (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", "rdnSequence", NULL)); -} - -static gconstpointer -_gcr_certificate_get_subject_const (GcrCertificate *self, gsize *n_data) -{ - GcrCertificateInfo *info; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - g_return_val_if_fail (n_data != NULL, NULL); - - info = certificate_info_load (self); - g_return_val_if_fail (info, NULL); - - return egg_asn1x_get_raw_element (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", NULL), n_data); -} - -/** - * gcr_certificate_get_subject_raw: - * @self: a #GcrCertificate - * @n_data: The length of the returned data. - * - * Get the raw DER data for the subject DN of the certificate. - * - * The data should be freed by using g_free() when no longer required. - * - * Returns: (transfer full) (array length=n_data): allocated memory containing - * the raw subject - */ -guchar * -gcr_certificate_get_subject_raw (GcrCertificate *self, gsize *n_data) -{ - GcrCertificateInfo *info; - gconstpointer data; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - g_return_val_if_fail (n_data != NULL, NULL); - - info = certificate_info_load (self); - g_return_val_if_fail (info, NULL); - - data = _gcr_certificate_get_subject_const (self, n_data); - return g_memdup (data, data ? *n_data : 0); -} - -/** - * gcr_certificate_get_issued_date: - * @self: a #GcrCertificate - * - * Get the issued date of this certificate. - * - * The #GDate returned should be freed by the caller using - * g_date_free() when no longer required. - * - * Returns: An allocated issued date of this certificate. - */ -GDate* -gcr_certificate_get_issued_date (GcrCertificate *self) -{ - GcrCertificateInfo *info; - GDate *date; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - - info = certificate_info_load (self); - g_return_val_if_fail (info, NULL); - - date = g_date_new (); - if (!egg_asn1x_get_time_as_date (egg_asn1x_node (info->asn1, "tbsCertificate", "validity", "notBefore", NULL), date)) { - g_date_free (date); - return NULL; - } - - return date; -} - -/** - * gcr_certificate_get_expiry_date: - * @self: a #GcrCertificate - * - * Get the expiry date of this certificate. - * - * The #GDate returned should be freed by the caller using - * g_date_free() when no longer required. - * - * Returns: An allocated expiry date of this certificate. - */ -GDate* -gcr_certificate_get_expiry_date (GcrCertificate *self) -{ - GcrCertificateInfo *info; - GDate *date; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - - info = certificate_info_load (self); - g_return_val_if_fail (info, NULL); - - date = g_date_new (); - if (!egg_asn1x_get_time_as_date (egg_asn1x_node (info->asn1, "tbsCertificate", "validity", "notAfter", NULL), date)) { - g_date_free (date); - return NULL; - } - - return date; -} - -/** - * gcr_certificate_get_key_size: - * @self: a #GcrCertificate - * - * Get the key size in bits of the public key represented - * by this certificate. - * - * Returns: The key size of the certificate. - */ -guint -gcr_certificate_get_key_size (GcrCertificate *self) -{ - GcrCertificateInfo *info; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), 0); - - info = certificate_info_load (self); - g_return_val_if_fail (info, 0); - - if (!info->key_size) - info->key_size = calculate_key_size (info); - - return info->key_size; -} - -/** - * gcr_certificate_get_fingerprint: - * @self: a #GcrCertificate - * @type: the type of algorithm for the fingerprint. - * @n_length: The length of the resulting fingerprint. - * - * Calculate the fingerprint for this certificate. - * - * You can pass G_CHECKSUM_SHA1 or G_CHECKSUM_MD5 as the @type - * parameter. - * - * The caller should free the returned data using g_free() when - * it is no longer required. - * - * Returns: (array length=n_length): the raw binary fingerprint - **/ -guchar * -gcr_certificate_get_fingerprint (GcrCertificate *self, GChecksumType type, gsize *n_length) -{ - GChecksum *sum; - guchar *digest; - gssize length; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - g_return_val_if_fail (n_length != NULL, NULL); - - sum = digest_certificate (self, type); - g_return_val_if_fail (sum, NULL); - length = g_checksum_type_get_length (type); - g_return_val_if_fail (length > 0, NULL); - digest = g_malloc (length); - *n_length = length; - g_checksum_get_digest (sum, digest, n_length); - g_checksum_free (sum); - - return digest; -} - -/** - * gcr_certificate_get_fingerprint_hex: - * @self: a #GcrCertificate - * @type: the type of algorithm for the fingerprint. - * - * Calculate the fingerprint for this certificate, and return it - * as a hex string. - * - * You can pass G_CHECKSUM_SHA1 or G_CHECKSUM_MD5 as the @type - * parameter. - * - * The caller should free the returned data using g_free() when - * it is no longer required. - * - * Returns: an allocated hex string which contains the fingerprint. - */ -gchar* -gcr_certificate_get_fingerprint_hex (GcrCertificate *self, GChecksumType type) -{ - GChecksum *sum; - guchar *digest; - gsize n_digest; - gssize length; - gchar *hex; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - - sum = digest_certificate (self, type); - g_return_val_if_fail (sum, NULL); - length = g_checksum_type_get_length (type); - g_return_val_if_fail (length > 0, NULL); - digest = g_malloc (length); - n_digest = length; - g_checksum_get_digest (sum, digest, &n_digest); - hex = egg_hex_encode_full (digest, n_digest, TRUE, ' ', 1); - g_checksum_free (sum); - g_free (digest); - return hex; -} - -/** - * gcr_certificate_get_serial_number: - * @self: a #GcrCertificate - * @n_length: the length of the returned data. - * - * Get the raw binary serial number of the certificate. - * - * The caller should free the returned data using g_free() when - * it is no longer required. - * - * Returns: (array length=n_length): the raw binary serial number. - */ -guchar * -gcr_certificate_get_serial_number (GcrCertificate *self, gsize *n_length) -{ - GcrCertificateInfo *info; - const guchar *serial; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - g_return_val_if_fail (n_length != NULL, NULL); - - info = certificate_info_load (self); - g_return_val_if_fail (info, NULL); - - serial = egg_asn1x_get_integer_as_raw (egg_asn1x_node (info->asn1, "tbsCertificate", "serialNumber", NULL), n_length); - return g_memdup (serial, *n_length); -} - -/** - * gcr_certificate_get_serial_number_hex: - * @self: a #GcrCertificate - * - * Get the serial number of the certificate as a hex string. - * - * The caller should free the returned data using g_free() when - * it is no longer required. - * - * Returns: an allocated string containing the serial number as hex. - */ -gchar* -gcr_certificate_get_serial_number_hex (GcrCertificate *self) -{ - guchar *serial; - gsize n_serial; - gchar *hex; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - - serial = gcr_certificate_get_serial_number (self, &n_serial); - if (serial == NULL) - return NULL; - - hex = egg_hex_encode (serial, n_serial); - g_free (serial); - return hex; -} - -/** - * gcr_certificate_get_icon: - * @self: The certificate - * - * Get the icon for a certificate. - * - * Returns: (transfer full): the icon for this certificate, which should be - * released with g_object_unref() - */ -GIcon * -gcr_certificate_get_icon (GcrCertificate *self) -{ - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), FALSE); - return g_themed_icon_new (GCR_ICON_CERTIFICATE); -} - -/* ----------------------------------------------------------------------------- - * MIXIN - */ - -/** - * GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE: - * - * Implement the GcrComparable interface. Use this macro like this: - * - * <informalexample><programlisting> - * G_DEFINE_TYPE_WITH_CODE (MyCertificate, my_certificate, G_TYPE_OBJECT, - * GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE (); - * G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, my_certificate_iface_init); - * ); - * </programlisting></informalexample> - */ - -/** - * gcr_certificate_mixin_comparable_init: (skip) - * @iface: The interface - * - * Initialize a #GcrComparableIface to compare the current certificate. - * In general it's easier to use the GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE() - * macro instead of this function. - */ -void -gcr_certificate_mixin_comparable_init (GcrComparableIface *iface) -{ - iface->compare = gcr_certificate_compare; -} - -/** - * gcr_certificate_mixin_class_init: (skip) - * @object_class: The GObjectClass for this class - * - * Initialize the certificate mixin for the class. This mixin implements the - * various required properties for the certificate. - * - * Call this function near the end of your derived class_init function. The - * derived class must implement the #GcrCertificate interface. - */ -void -gcr_certificate_mixin_class_init (GObjectClass *object_class) -{ - if (!g_object_class_find_property (object_class, "description")) - g_object_class_override_property (object_class, PROP_DESCRIPTION, "description"); - if (!g_object_class_find_property (object_class, "markup")) - g_object_class_override_property (object_class, PROP_MARKUP, "markup"); - if (!g_object_class_find_property (object_class, "label")) - g_object_class_override_property (object_class, PROP_LABEL, "label"); - if (!g_object_class_find_property (object_class, "icon")) - g_object_class_override_property (object_class, PROP_ICON, "icon"); - if (!g_object_class_find_property (object_class, "subject")) - g_object_class_override_property (object_class, PROP_SUBJECT, "subject"); - if (!g_object_class_find_property (object_class, "issuer")) - g_object_class_override_property (object_class, PROP_ISSUER, "issuer"); - if (!g_object_class_find_property (object_class, "expiry")) - g_object_class_override_property (object_class, PROP_EXPIRY, "expiry"); - - _gcr_initialize_library (); -} - -/** - * gcr_certificate_mixin_get_property: (skip) - * @obj: The object - * @prop_id: The property id - * @value: The value to fill in. - * @pspec: The param specification. - * - * Implementation to get various required certificate properties. This should - * be called from your derived class get_property function, or used as a - * get_property virtual function. - * - * Example of use as called from derived class get_property function: - * - * <informalexample><programlisting> - * static void - * my_get_property (GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) - * { - * switch (prop_id) { - * - * ... - * - * default: - * gcr_certificate_mixin_get_property (obj, prop_id, value, pspec); - * break; - * } - *} - * </programlisting></informalexample> - * - * Example of use as get_property function: - * - * <informalexample><programlisting> - * static void - * my_class_init (MyClass *klass) - * { - * GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - * gobject_class->get_property = gcr_certificate_mixin_get_property; - * - * ... - * } - * </programlisting></informalexample> - - */ -void -gcr_certificate_mixin_get_property (GObject *obj, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - GcrCertificate *cert = GCR_CERTIFICATE (obj); - - switch (prop_id) { - case PROP_LABEL: - g_value_take_string (value, gcr_certificate_get_subject_cn (cert)); - break; - case PROP_SUBJECT: - g_value_take_string (value, gcr_certificate_get_subject_cn (cert)); - break; - case PROP_ICON: - g_value_set_object (value, gcr_certificate_get_icon (cert)); - break; - case PROP_DESCRIPTION: - g_value_set_string (value, _("Certificate")); - break; - case PROP_MARKUP: - g_value_take_string (value, calculate_markup (cert)); - break; - case PROP_ISSUER: - g_value_take_string (value, gcr_certificate_get_issuer_cn (cert)); - break; - case PROP_EXPIRY: - g_value_take_boxed (value, gcr_certificate_get_expiry_date (cert)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} diff --git a/gcr/gcr-certificate.h b/gcr/gcr-certificate.h deleted file mode 100644 index d60be227..00000000 --- a/gcr/gcr-certificate.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_CERTIFICATE_H__ -#define __GCR_CERTIFICATE_H__ - -#include "gcr-types.h" -#include "gcr-column.h" -#include "gcr-comparable.h" - -#include <glib-object.h> -#include <gio/gio.h> - -G_BEGIN_DECLS - -#define GCR_CERTIFICATE_COLUMNS (gcr_certificate_get_columns ()) -#define GCR_TYPE_CERTIFICATE (gcr_certificate_get_type ()) -#define GCR_CERTIFICATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE, GcrCertificate)) -#define GCR_IS_CERTIFICATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE)) -#define GCR_CERTIFICATE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_CERTIFICATE, GcrCertificateIface)) - -typedef struct _GcrCertificate GcrCertificate; -typedef struct _GcrCertificateIface GcrCertificateIface; - -struct _GcrCertificateIface { - GTypeInterface parent; - - const guchar * (*get_der_data) (GcrCertificate *self, - gsize *n_data); - - /*< private >*/ - gpointer dummy1; - gpointer dummy2; - gpointer dummy3; - gpointer dummy5; - gpointer dummy6; - gpointer dummy7; - gpointer dummy8; -}; - -GType gcr_certificate_get_type (void); - -const guchar * gcr_certificate_get_der_data (GcrCertificate *self, - gsize *n_data); - -const GcrColumn* gcr_certificate_get_columns (void); - -gint gcr_certificate_compare (GcrComparable *first, - GcrComparable *other); - -gchar* gcr_certificate_get_issuer_cn (GcrCertificate *self); - -gchar* gcr_certificate_get_issuer_dn (GcrCertificate *self); - -gchar* gcr_certificate_get_issuer_part (GcrCertificate *self, - const gchar *part); - -guchar * gcr_certificate_get_issuer_raw (GcrCertificate *self, - gsize *n_data); - -gboolean gcr_certificate_is_issuer (GcrCertificate *self, - GcrCertificate *issuer); - -gchar* gcr_certificate_get_subject_cn (GcrCertificate *self); - -gchar* gcr_certificate_get_subject_dn (GcrCertificate *self); - -gchar* gcr_certificate_get_subject_part (GcrCertificate *self, - const gchar *part); - -guchar * gcr_certificate_get_subject_raw (GcrCertificate *self, - gsize *n_data); - -GDate* gcr_certificate_get_issued_date (GcrCertificate *self); - -GDate* gcr_certificate_get_expiry_date (GcrCertificate *self); - -guchar* gcr_certificate_get_serial_number (GcrCertificate *self, - gsize *n_length); - -gchar* gcr_certificate_get_serial_number_hex (GcrCertificate *self); - -guint gcr_certificate_get_key_size (GcrCertificate *self); - -guchar* gcr_certificate_get_fingerprint (GcrCertificate *self, - GChecksumType type, - gsize *n_length); - -gchar* gcr_certificate_get_fingerprint_hex (GcrCertificate *self, - GChecksumType type); - -GIcon* gcr_certificate_get_icon (GcrCertificate *self); - -#define GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE() \ - G_IMPLEMENT_INTERFACE (GCR_TYPE_COMPARABLE, gcr_certificate_mixin_comparable_init) - -void gcr_certificate_mixin_comparable_init (GcrComparableIface *iface); - -void gcr_certificate_mixin_class_init (GObjectClass *object_class); - -void gcr_certificate_mixin_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec); - -G_END_DECLS - -#endif /* __GCR_CERTIFICATE_H__ */ diff --git a/gcr/gcr-collection-model.c b/gcr/gcr-collection-model.c deleted file mode 100644 index 79493e08..00000000 --- a/gcr/gcr-collection-model.c +++ /dev/null @@ -1,1575 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * 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., - * 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-collection-model.h" - -#include <gtk/gtk.h> - -#include <string.h> -#include <unistd.h> - -/** - * SECTION:gcr-collection-model - * @title: GcrCollectionModel - * @short_description: A GtkTreeModel that represents a collection - * - * This is an implementation of #GtkTreeModel which represents the objects in - * the a #GcrCollection. As objects are added or removed from the collection, - * rows are added and removed from this model. - * - * The row values come from the properties of the objects in the collection. Use - * gcr_collection_model_new() to create a new collection model. To have more - * control over the values use a set of #GcrColumn structures to define the - * columns. This can be done with gcr_collection_model_new_full() or - * gcr_collection_model_set_columns(). - * - * Each row can have a selected state, which is represented by a boolean column. - * The selected state can be toggled with gcr_collection_model_toggle_selected() - * or set with gcr_collection_model_set_selected_objects() and retrieved with - * gcr_collection_model_get_selected_objects(). - * - * To determine which object a row represents and vice versa, use the - * gcr_collection_model_iter_for_object() or gcr_collection_model_object_for_iter() - * functions. - */ - -/** - * GcrCollectionModel: - * - * A #GtkTreeModel which contains a row for each object in a #GcrCollection. - */ - -/** - * GcrCollectionModelClass: - * @parent_class: The parent class - * - * The class for #GcrCollectionModel. - */ - -#define COLLECTION_MODEL_STAMP 0xAABBCCDD - -enum { - PROP_0, - PROP_COLLECTION, - PROP_COLUMNS -}; - -typedef struct { - GObject *object; - GSequenceIter *parent; - GSequence *children; -} GcrCollectionRow; - -typedef struct { - GtkTreeIterCompareFunc sort_func; - gpointer user_data; - GDestroyNotify destroy_func; -} GcrCollectionSortClosure; - -typedef struct _GcrCollectionColumn { - gchar *property; - GType *type; - GtkTreeIterCompareFunc sort_func; - gpointer sort_data; - GDestroyNotify sort_destroy; -} GcrCollectionColumn; - -struct _GcrCollectionModelPrivate { - GcrCollection *collection; - GHashTable *selected; - GSequence *root_sequence; - GHashTable *object_to_seq; - - const GcrColumn *columns; - guint n_columns; - - /* Sort information */ - gint sort_column_id; - GtkSortType sort_order_type; - GcrCollectionSortClosure *column_sort_closures; - GcrCollectionSortClosure default_sort_closure; - - /* Sequence ordering information */ - GCompareDataFunc order_current; - gpointer order_argument; -}; - -/* Forward declarations */ -static void gcr_collection_model_tree_model_init (GtkTreeModelIface *iface); -static void gcr_collection_model_tree_sortable_init (GtkTreeSortableIface *iface); - -G_DEFINE_TYPE_EXTENDED (GcrCollectionModel, gcr_collection_model, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, gcr_collection_model_tree_model_init) - G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_SORTABLE, gcr_collection_model_tree_sortable_init) -); - -typedef gint (*CompareValueFunc) (const GValue *va, - const GValue *vb); - -static gint -compare_int_value (const GValue *va, - const GValue *vb) -{ - gint a = g_value_get_int (va); - gint b = g_value_get_int (vb); - if (a > b) return 1; - else if (a < b) return -1; - return 0; -} - -static gint -compare_uint_value (const GValue *va, - const GValue *vb) -{ - guint a = g_value_get_uint (va); - guint b = g_value_get_uint (vb); - if (a > b) return 1; - else if (a < b) return -1; - return 0; -} - -static gint -compare_long_value (const GValue *va, - const GValue *vb) -{ - glong a = g_value_get_long (va); - glong b = g_value_get_long (vb); - if (a > b) return 1; - else if (a < b) return -1; - return 0; -} - -static gint -compare_ulong_value (const GValue *va, - const GValue *vb) -{ - gulong a = g_value_get_ulong (va); - gulong b = g_value_get_ulong (vb); - if (a > b) return 1; - else if (a < b) return -1; - return 0; -} - -static gint -compare_string_value (const GValue *va, - const GValue *vb) -{ - const gchar *a = g_value_get_string (va); - const gchar *b = g_value_get_string (vb); - gchar *case_a; - gchar *case_b; - gboolean ret; - - if (a == b) - return 0; - else if (!a) - return -1; - else if (!b) - return 1; - - case_a = g_utf8_casefold (a, -1); - case_b = g_utf8_casefold (b, -1); - ret = g_utf8_collate (case_a, case_b); - g_free (case_a); - g_free (case_b); - - return ret; -} - -static gint -compare_date_value (const GValue *va, - const GValue *vb) -{ - GDate *a = g_value_get_boxed (va); - GDate *b = g_value_get_boxed (vb); - - if (a == b) - return 0; - else if (!a) - return -1; - else if (!b) - return 1; - else - return g_date_compare (a, b); -} - -static CompareValueFunc -lookup_compare_func (GType type) -{ - switch (type) { - case G_TYPE_INT: - return compare_int_value; - case G_TYPE_UINT: - return compare_uint_value; - case G_TYPE_LONG: - return compare_long_value; - case G_TYPE_ULONG: - return compare_ulong_value; - case G_TYPE_STRING: - return compare_string_value; - } - - if (type == G_TYPE_DATE) - return compare_date_value; - - return NULL; -} - -static gint -order_sequence_by_closure (gconstpointer a, - gconstpointer b, - gpointer user_data) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (user_data); - GcrCollectionSortClosure *closure = self->pv->order_argument; - const GcrCollectionRow *row_a = a; - const GcrCollectionRow *row_b = b; - GtkTreeIter iter_a; - GtkTreeIter iter_b; - - g_assert (closure); - g_assert (closure->sort_func); - - if (!gcr_collection_model_iter_for_object (self, row_a->object, &iter_a)) - g_return_val_if_reached (0); - if (!gcr_collection_model_iter_for_object (self, row_b->object, &iter_b)) - g_return_val_if_reached (0); - - return (closure->sort_func) (GTK_TREE_MODEL (self), - &iter_a, &iter_b, closure->user_data); -} - -static gint -order_sequence_by_closure_reverse (gconstpointer a, - gconstpointer b, - gpointer user_data) -{ - return 0 - order_sequence_by_closure (a, b, user_data); -} - -static gint -order_sequence_as_unsorted (gconstpointer a, - gconstpointer b, - gpointer user_data) -{ - const GcrCollectionRow *row_a = a; - const GcrCollectionRow *row_b = b; - return GPOINTER_TO_INT (row_a->object) - GPOINTER_TO_INT (row_b->object); -} - -static gint -order_sequence_as_unsorted_reverse (gconstpointer a, - gconstpointer b, - gpointer user_data) -{ - const GcrCollectionRow *row_a = a; - const GcrCollectionRow *row_b = b; - return GPOINTER_TO_INT (row_b->object) - GPOINTER_TO_INT (row_a->object); -} - -static void -lookup_object_property (GObject *object, - const gchar *property_name, - GValue *value) -{ - if (g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name)) - g_object_get_property (object, property_name, value); - - /* Other types have sane defaults */ - else if (G_VALUE_TYPE (value) == G_TYPE_STRING) - g_value_set_string (value, ""); -} - -static gint -order_sequence_by_property (gconstpointer a, - gconstpointer b, - gpointer user_data) -{ - const GcrCollectionRow *row_a = a; - const GcrCollectionRow *row_b = b; - GcrCollectionModel *self = GCR_COLLECTION_MODEL (user_data); - const GcrColumn *column = self->pv->order_argument; - GValue value_a = { 0, }; - GValue value_b = { 0, }; - CompareValueFunc compare; - gint ret; - - g_assert (column); - - /* Sort according to property values */ - column = &self->pv->columns[self->pv->sort_column_id]; - g_value_init (&value_a, column->property_type); - lookup_object_property (row_a->object, column->property_name, &value_a); - g_value_init (&value_b, column->property_type); - lookup_object_property (row_b->object, column->property_name, &value_b); - - compare = lookup_compare_func (column->property_type); - g_assert (compare != NULL); - - ret = (compare) (&value_a, &value_b); - - g_value_unset (&value_a); - g_value_unset (&value_b); - - return ret; -} - -static gint -order_sequence_by_property_reverse (gconstpointer a, - gconstpointer b, - gpointer user_data) -{ - return 0 - order_sequence_by_property (a, b, user_data); -} - -static GHashTable* -selected_hash_table_new (void) -{ - return g_hash_table_new (g_direct_hash, g_direct_equal); -} - -static gboolean -sequence_iter_to_tree (GcrCollectionModel *self, - GSequenceIter *seq, - GtkTreeIter *iter) -{ - GcrCollectionRow *row; - - g_return_val_if_fail (seq != NULL, FALSE); - - if (g_sequence_iter_is_end (seq)) - return FALSE; - - row = g_sequence_get (seq); - g_return_val_if_fail (row != NULL && G_IS_OBJECT (row->object), FALSE); - - memset (iter, 0, sizeof (*iter)); - iter->stamp = COLLECTION_MODEL_STAMP; - iter->user_data = row->object; - iter->user_data2 = seq; - return TRUE; -} - -static GSequenceIter * -sequence_iter_for_tree (GcrCollectionModel *self, - GtkTreeIter *iter) -{ - g_return_val_if_fail (iter != NULL, NULL); - g_return_val_if_fail (iter->stamp == COLLECTION_MODEL_STAMP, NULL); - return iter->user_data2; -} - -static GtkTreePath * -sequence_iter_to_path (GcrCollectionModel *self, - GSequenceIter *seq) -{ - GcrCollectionRow *row; - GtkTreePath *path; - - path = gtk_tree_path_new (); - while (seq) { - gtk_tree_path_prepend_index (path, g_sequence_iter_get_position (seq)); - row = g_sequence_get (seq); - seq = row->parent; - } - return path; -} - -static GSequence * -child_sequence_for_tree (GcrCollectionModel *self, - GtkTreeIter *iter) -{ - GcrCollectionRow *row; - GSequenceIter *seq; - - if (iter == NULL) { - return self->pv->root_sequence; - } else { - seq = sequence_iter_for_tree (self, iter); - g_return_val_if_fail (seq != NULL, NULL); - row = g_sequence_get (seq); - return row->children; - } -} - -static void -on_object_notify (GObject *object, GParamSpec *spec, GcrCollectionModel *self) -{ - GtkTreeIter iter; - GtkTreePath *path; - gboolean found = FALSE; - guint i; - - g_return_if_fail (spec->name); - - for (i = 0; i < self->pv->n_columns - 1; ++i) { - g_assert (self->pv->columns[i].property_name); - if (g_str_equal (self->pv->columns[i].property_name, spec->name)) { - found = TRUE; - break; - } - } - - /* Tell the tree view that this row changed */ - if (found) { - if (!gcr_collection_model_iter_for_object (self, object, &iter)) - g_return_if_reached (); - path = gtk_tree_model_get_path (GTK_TREE_MODEL (self), &iter); - g_return_if_fail (path); - gtk_tree_model_row_changed (GTK_TREE_MODEL (self), path, &iter); - gtk_tree_path_free (path); - } -} - -static void -on_object_gone (gpointer unused, GObject *was_object) -{ - g_warning ("object contained in GcrCollection and included in GcrCollectionModel " - "was destroyed before it was removed from the collection"); -} - -static void on_collection_added (GcrCollection *collection, - GObject *object, - gpointer user_data); - -static void on_collection_removed (GcrCollection *collection, - GObject *object, - gpointer user_data); - -static void add_object_to_sequence (GcrCollectionModel *self, - GSequence *sequence, - GSequenceIter *parent, - GObject *object, - gboolean emit); - -static void remove_object_from_sequence (GcrCollectionModel *self, - GSequence *sequence, - GSequenceIter *seq, - GObject *object, - gboolean emit); - -static void -add_children_to_sequence (GcrCollectionModel *self, - GSequence *sequence, - GSequenceIter *parent, - GcrCollection *collection, - gboolean emit) -{ - GList *children, *l; - - children = gcr_collection_get_objects (collection); - for (l = children; l; l = g_list_next (l)) - add_object_to_sequence (self, sequence, parent, l->data, emit); - g_list_free (children); - - /* Now listen in for any changes */ - g_signal_connect_after (collection, "added", G_CALLBACK (on_collection_added), self); - g_signal_connect_after (collection, "removed", G_CALLBACK (on_collection_removed), self); -} - -static void -add_object_to_sequence (GcrCollectionModel *self, - GSequence *sequence, - GSequenceIter *parent, - GObject *object, - gboolean emit) -{ - GcrCollectionRow *row; - GSequenceIter *seq; - GtkTreeIter iter; - GtkTreePath *path; - - g_assert (GCR_IS_COLLECTION_MODEL (self)); - g_assert (G_IS_OBJECT (object)); - g_assert (self->pv->order_current); - - if (g_hash_table_lookup (self->pv->object_to_seq, object)) { - g_warning ("object was already added to the GcrCollectionModel. Perhaps " - "a loop exists in a tree structure?"); - return; - } - - row = g_slice_new0 (GcrCollectionRow); - row->object = object; - row->parent = parent; - row->children = NULL; - - seq = g_sequence_insert_sorted (sequence, row, self->pv->order_current, self); - g_hash_table_insert (self->pv->object_to_seq, object, seq); - g_object_weak_ref (G_OBJECT (object), (GWeakNotify)on_object_gone, self); - g_signal_connect (object, "notify", G_CALLBACK (on_object_notify), self); - - if (emit) { - if (!sequence_iter_to_tree (self, seq, &iter)) - g_assert_not_reached (); - path = sequence_iter_to_path (self, seq); - g_assert (path != NULL); - gtk_tree_model_row_inserted (GTK_TREE_MODEL (self), path, &iter); - gtk_tree_path_free (path); - } - - if (GCR_IS_COLLECTION (object)) { - row->children = g_sequence_new (NULL); - add_children_to_sequence (self, row->children, seq, - GCR_COLLECTION (object), emit); - } -} - -static void -on_collection_added (GcrCollection *collection, - GObject *object, - gpointer user_data) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (user_data); - GSequence *sequence; - GSequenceIter *parent; - GcrCollectionRow *row; - - if (collection == self->pv->collection) { - sequence = self->pv->root_sequence; - parent = NULL; - } else { - parent = g_hash_table_lookup (self->pv->object_to_seq, G_OBJECT (collection)); - row = g_sequence_get (parent); - g_assert (row->children); - sequence = row->children; - } - - add_object_to_sequence (self, sequence, parent, object, TRUE); -} - -static void -remove_children_from_sequence (GcrCollectionModel *self, - GSequence *sequence, - GcrCollection *collection, - gboolean emit) -{ - GSequenceIter *seq, *next; - GcrCollectionRow *row; - - g_signal_handlers_disconnect_by_func (collection, on_collection_added, self); - g_signal_handlers_disconnect_by_func (collection, on_collection_removed, self); - - for (seq = g_sequence_get_begin_iter (sequence); - !g_sequence_iter_is_end (seq); seq = next) { - next = g_sequence_iter_next (seq); - row = g_sequence_get (seq); - remove_object_from_sequence (self, sequence, seq, row->object, emit); - } -} - -static void -remove_object_from_sequence (GcrCollectionModel *self, - GSequence *sequence, - GSequenceIter *seq, - GObject *object, - gboolean emit) -{ - GcrCollectionRow *row; - GtkTreePath *path = NULL; - - if (emit) { - path = sequence_iter_to_path (self, seq); - g_assert (path != NULL); - } - - row = g_sequence_get (seq); - g_assert (row->object == object); - - g_object_weak_unref (object, on_object_gone, self); - g_signal_handlers_disconnect_by_func (object, on_object_notify, self); - - if (row->children) { - g_assert (GCR_IS_COLLECTION (object)); - remove_children_from_sequence (self, row->children, GCR_COLLECTION (object), emit); - g_assert (g_sequence_get_length (row->children) == 0); - g_sequence_free (row->children); - row->children = NULL; - } - - if (self->pv->selected) - g_hash_table_remove (self->pv->selected, object); - if (!g_hash_table_remove (self->pv->object_to_seq, object)) - g_assert_not_reached (); - - g_sequence_remove (seq); - g_slice_free (GcrCollectionRow, row); - - /* Fire signal for this removed row */ - if (path != NULL) { - gtk_tree_model_row_deleted (GTK_TREE_MODEL (self), path); - gtk_tree_path_free (path); - } - -} - -static void -on_collection_removed (GcrCollection *collection, - GObject *object, - gpointer user_data) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (user_data); - GSequenceIter *seq; - GSequence *sequence; - - seq = g_hash_table_lookup (self->pv->object_to_seq, object); - g_return_if_fail (seq != NULL); - - sequence = g_sequence_iter_get_sequence (seq); - g_assert (sequence != NULL); - - remove_object_from_sequence (self, sequence, seq, object, TRUE); -} - -static void -free_owned_columns (gpointer data) -{ - GcrColumn *columns; - g_assert (data); - - /* Only the property column is in use */ - for (columns = data; columns->property_name; ++columns) - g_free ((gchar*)columns->property_name); - g_free (data); -} - -static GtkTreeModelFlags -gcr_collection_model_real_get_flags (GtkTreeModel *model) -{ - return GTK_TREE_MODEL_ITERS_PERSIST; -} - -static gint -gcr_collection_model_real_get_n_columns (GtkTreeModel *model) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (model); - return self->pv->n_columns; -} - -static GType -gcr_collection_model_real_get_column_type (GtkTreeModel *model, - gint column_id) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (model); - g_return_val_if_fail (column_id >= 0 && column_id <= self->pv->n_columns, 0); - - /* The last is the selected column */ - if (column_id == self->pv->n_columns) - return G_TYPE_BOOLEAN; - - return self->pv->columns[column_id].column_type; -} - -static gboolean -gcr_collection_model_real_get_iter (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreePath *path) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (model); - const gint *indices; - GSequence *sequence; - GSequenceIter *seq; - GcrCollectionRow *row; - gint count; - gint i; - - sequence = self->pv->root_sequence; - seq = NULL; - - indices = gtk_tree_path_get_indices_with_depth (path, &count); - if (count == 0) - return FALSE; - - for (i = 0; i < count; i++) { - if (!sequence) - return FALSE; - seq = g_sequence_get_iter_at_pos (sequence, indices[i]); - if (g_sequence_iter_is_end (seq)) - return FALSE; - row = g_sequence_get (seq); - sequence = row->children; - } - - return sequence_iter_to_tree (self, seq, iter); -} - -static GtkTreePath* -gcr_collection_model_real_get_path (GtkTreeModel *model, - GtkTreeIter *iter) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (model); - GSequenceIter *seq; - - if (iter == NULL) - return gtk_tree_path_new (); - - seq = sequence_iter_for_tree (self, iter); - g_return_val_if_fail (seq != NULL, NULL); - return sequence_iter_to_path (self, seq); -} - -static void -gcr_collection_model_real_get_value (GtkTreeModel *model, - GtkTreeIter *iter, - gint column_id, - GValue *value) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (model); - GObject *object; - GValue original; - const GcrColumn *column; - GParamSpec *spec; - - object = gcr_collection_model_object_for_iter (self, iter); - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (column_id >= 0 && column_id < self->pv->n_columns); - - /* The selected column? Last one */ - if (column_id == self->pv->n_columns - 1) { - g_value_init (value, G_TYPE_BOOLEAN); - g_value_set_boolean (value, gcr_collection_model_is_selected (self, iter)); - return; - } - - /* Figure out which property */ - column = &self->pv->columns[column_id]; - g_assert (column->property_name); - g_value_init (value, column->column_type); - - /* Lookup the property on the object */ - spec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), column->property_name); - if (spec != NULL) { - /* A transformer is specified, or mismatched types */ - if (column->transformer || column->column_type != column->property_type) { - memset (&original, 0, sizeof (original)); - g_value_init (&original, column->property_type); - g_object_get_property (object, column->property_name, &original); - - if (column->transformer) { - (column->transformer) (&original, value); - } else { - g_warning ("%s property of %s class was of type %s instead of type %s" - " and cannot be converted due to lack of transformer", - column->property_name, G_OBJECT_TYPE_NAME (object), - g_type_name (column->property_type), - g_type_name (column->column_type)); - spec = NULL; - } - - /* Simple, no transformation necessary */ - } else { - g_object_get_property (object, column->property_name, value); - } - } - - if (spec == NULL) { - - /* All the number types have sane defaults */ - if (column->column_type == G_TYPE_STRING) - g_value_set_string (value, ""); - } -} - -static gboolean -gcr_collection_model_real_iter_next (GtkTreeModel *model, - GtkTreeIter *iter) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (model); - GSequenceIter *seq = sequence_iter_for_tree (self, iter); - g_return_val_if_fail (seq != NULL, FALSE); - return sequence_iter_to_tree (self, g_sequence_iter_next (seq), iter); -} - -static gboolean -gcr_collection_model_real_iter_children (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreeIter *parent) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (model); - GSequence *sequence = child_sequence_for_tree (self, parent); - return sequence && sequence_iter_to_tree (self, g_sequence_get_begin_iter (sequence), iter); -} - -static gboolean -gcr_collection_model_real_iter_has_child (GtkTreeModel *model, - GtkTreeIter *iter) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (model); - GSequence *sequence = child_sequence_for_tree (self, iter); - return sequence && !g_sequence_iter_is_end (g_sequence_get_begin_iter (sequence)); -} - -static gint -gcr_collection_model_real_iter_n_children (GtkTreeModel *model, - GtkTreeIter *iter) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (model); - GSequence *sequence = child_sequence_for_tree (self, iter); - return sequence ? g_sequence_get_length (sequence) : 0; -} - -static gboolean -gcr_collection_model_real_iter_nth_child (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreeIter *parent, - gint n) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (model); - GSequence *sequence; - GSequenceIter *seq; - - sequence = child_sequence_for_tree (self, parent); - if (sequence == NULL) - return FALSE; - seq = g_sequence_get_iter_at_pos (sequence, n); - return sequence_iter_to_tree (self, seq, iter); -} - -static gboolean -gcr_collection_model_real_iter_parent (GtkTreeModel *model, - GtkTreeIter *iter, - GtkTreeIter *child) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (model); - GSequenceIter *seq; - GcrCollectionRow *row; - - seq = sequence_iter_for_tree (self, child); - g_return_val_if_fail (seq != NULL, FALSE); - row = g_sequence_get (seq); - if (row->parent == NULL) - return FALSE; - return sequence_iter_to_tree (self, row->parent, iter); -} - -static void -gcr_collection_model_real_ref_node (GtkTreeModel *model, - GtkTreeIter *iter) -{ - /* Nothing to do */ -} - -static void -gcr_collection_model_real_unref_node (GtkTreeModel *model, - GtkTreeIter *iter) -{ - /* Nothing to do */ -} - -static void -gcr_collection_model_tree_model_init (GtkTreeModelIface *iface) -{ - iface->get_flags = gcr_collection_model_real_get_flags; - iface->get_n_columns = gcr_collection_model_real_get_n_columns; - iface->get_column_type = gcr_collection_model_real_get_column_type; - iface->get_iter = gcr_collection_model_real_get_iter; - iface->get_path = gcr_collection_model_real_get_path; - iface->get_value = gcr_collection_model_real_get_value; - iface->iter_next = gcr_collection_model_real_iter_next; - iface->iter_children = gcr_collection_model_real_iter_children; - iface->iter_has_child = gcr_collection_model_real_iter_has_child; - iface->iter_n_children = gcr_collection_model_real_iter_n_children; - iface->iter_nth_child = gcr_collection_model_real_iter_nth_child; - iface->iter_parent = gcr_collection_model_real_iter_parent; - iface->ref_node = gcr_collection_model_real_ref_node; - iface->unref_node = gcr_collection_model_real_unref_node; -} - -static void -collection_resort_sequence (GcrCollectionModel *self, - GSequenceIter *parent, - GSequence *sequence) -{ - GPtrArray *previous; - GSequenceIter *seq, *next; - gint *new_order; - GtkTreePath *path; - GtkTreeIter iter; - GcrCollectionRow *row; - gint index; - gint i; - - /* Make note of how things stand, and at same time resort all kids */ - previous = g_ptr_array_new (); - for (seq = g_sequence_get_begin_iter (sequence); - !g_sequence_iter_is_end (seq); seq = next) { - next = g_sequence_iter_next (seq); - row = g_sequence_get (seq); - if (row->children) - collection_resort_sequence (self, seq, row->children); - g_ptr_array_add (previous, row->object); - } - - if (previous->len == 0) { - g_ptr_array_free (previous, TRUE); - return; - } - - /* Actually perform the sort */ - g_sequence_sort (sequence, self->pv->order_current, self); - - /* Now go through and map out how things changed */ - new_order = g_new0 (gint, previous->len); - for (i = 0; i < previous->len; i++) { - seq = g_hash_table_lookup (self->pv->object_to_seq, previous->pdata[i]); - g_assert (seq != NULL); - index = g_sequence_iter_get_position (seq); - g_assert (index >= 0 && index < previous->len); - new_order[index] = i; - } - - g_ptr_array_free (previous, TRUE); - - path = sequence_iter_to_path (self, parent); - if (parent == NULL) { - gtk_tree_model_rows_reordered (GTK_TREE_MODEL (self), path, NULL, new_order); - } else { - if (!sequence_iter_to_tree (self, parent, &iter)) - g_assert_not_reached (); - gtk_tree_model_rows_reordered (GTK_TREE_MODEL (self), path, &iter, new_order); - } - gtk_tree_path_free (path); - g_free (new_order); -} - -static gboolean -gcr_collection_model_get_sort_column_id (GtkTreeSortable *sortable, - gint *sort_column_id, - GtkSortType *order) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (sortable); - - if (order) - *order = self->pv->sort_order_type; - if (sort_column_id) - *sort_column_id = self->pv->sort_column_id; - return (self->pv->sort_column_id != GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID && - self->pv->sort_column_id != GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID); -} - -static void -gcr_collection_model_set_sort_column_id (GtkTreeSortable *sortable, - gint sort_column_id, - GtkSortType order) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (sortable); - GCompareDataFunc func; - gpointer argument; - const GcrColumn *column; - gboolean reverse; - - reverse = (order == GTK_SORT_DESCENDING); - - if (sort_column_id == GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID) { - func = reverse ? order_sequence_as_unsorted_reverse : order_sequence_as_unsorted; - argument = NULL; - - } else if (sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) { - func = reverse ? order_sequence_by_closure_reverse : order_sequence_by_closure; - argument = &self->pv->default_sort_closure; - - } else if (sort_column_id >= 0 && sort_column_id < self->pv->n_columns) { - if (self->pv->column_sort_closures[sort_column_id].sort_func) { - func = reverse ? order_sequence_by_closure_reverse : order_sequence_by_closure; - argument = &self->pv->column_sort_closures[sort_column_id]; - } else { - column = &self->pv->columns[sort_column_id]; - if (!(column->flags & GCR_COLUMN_SORTABLE)) - return; - if (!lookup_compare_func (column->property_type)) { - g_warning ("no sort implementation defined for type '%s' on column '%s'", - g_type_name (column->property_type), column->property_name); - return; - } - - func = reverse ? order_sequence_by_property_reverse : order_sequence_by_property; - argument = (gpointer)column; - } - } else { - g_warning ("invalid sort_column_id passed to gtk_tree_sortable_set_sort_column_id(): %d", - sort_column_id); - return; - } - - if (sort_column_id != self->pv->sort_column_id || - order != self->pv->sort_order_type) { - self->pv->sort_column_id = sort_column_id; - self->pv->sort_order_type = order; - gtk_tree_sortable_sort_column_changed (sortable); - } - - if (func != self->pv->order_current || - argument != self->pv->order_argument) { - self->pv->order_current = func; - self->pv->order_argument = (gpointer)argument; - collection_resort_sequence (self, NULL, self->pv->root_sequence); - } -} - -static void -clear_sort_closure (GcrCollectionSortClosure *closure) -{ - if (closure->destroy_func) - (closure->destroy_func) (closure->user_data); - closure->sort_func = NULL; - closure->destroy_func = NULL; - closure->user_data = NULL; -} - -static void -set_sort_closure (GcrCollectionSortClosure *closure, - GtkTreeIterCompareFunc func, - gpointer data, - GDestroyNotify destroy) -{ - clear_sort_closure (closure); - closure->sort_func = func; - closure->user_data = data; - closure->destroy_func = destroy; -} - -static void -gcr_collection_model_set_sort_func (GtkTreeSortable *sortable, - gint sort_column_id, - GtkTreeIterCompareFunc func, - gpointer data, - GDestroyNotify destroy) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (sortable); - - g_return_if_fail (sort_column_id >= 0 && sort_column_id < self->pv->n_columns); - - set_sort_closure (&self->pv->column_sort_closures[sort_column_id], - func, data, destroy); - - /* Resorts if necessary */ - if (self->pv->sort_column_id == sort_column_id) { - gcr_collection_model_set_sort_column_id (sortable, - self->pv->sort_column_id, - self->pv->sort_order_type); - } -} - -static void -gcr_collection_model_set_default_sort_func (GtkTreeSortable *sortable, - GtkTreeIterCompareFunc func, - gpointer data, GDestroyNotify destroy) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (sortable); - - set_sort_closure (&self->pv->default_sort_closure, - func, data, destroy); - - /* Resorts if necessary */ - if (self->pv->sort_column_id == GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID) { - gcr_collection_model_set_sort_column_id (sortable, - self->pv->sort_column_id, - self->pv->sort_order_type); - } -} - -static gboolean -gcr_collection_model_has_default_sort_func (GtkTreeSortable *sortable) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (sortable); - - return (self->pv->default_sort_closure.sort_func != NULL); -} - -static void -gcr_collection_model_tree_sortable_init (GtkTreeSortableIface *iface) -{ - iface->get_sort_column_id = gcr_collection_model_get_sort_column_id; - iface->set_sort_column_id = gcr_collection_model_set_sort_column_id; - iface->set_sort_func = gcr_collection_model_set_sort_func; - iface->set_default_sort_func = gcr_collection_model_set_default_sort_func; - iface->has_default_sort_func = gcr_collection_model_has_default_sort_func; -} - -static void -gcr_collection_model_init (GcrCollectionModel *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_COLLECTION_MODEL, GcrCollectionModelPrivate); - - self->pv->root_sequence = g_sequence_new (NULL); - self->pv->object_to_seq = g_hash_table_new (g_direct_hash, g_direct_equal); - self->pv->sort_column_id = GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID; - self->pv->sort_order_type = GTK_SORT_ASCENDING; - self->pv->order_current = order_sequence_as_unsorted; -} - -static void -gcr_collection_model_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (object); - GcrColumn *columns; - - switch (prop_id) { - case PROP_COLLECTION: - g_return_if_fail (self->pv->collection == NULL); - self->pv->collection = g_value_dup_object (value); - - /* During construction, so we don't emit anything */ - if (self->pv->collection) { - add_children_to_sequence (self, self->pv->root_sequence, - NULL, self->pv->collection, FALSE); - } - break; - - case PROP_COLUMNS: - columns = g_value_get_pointer (value); - if (columns) - gcr_collection_model_set_columns (self, columns); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gcr_collection_model_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (object); - - switch (prop_id) { - case PROP_COLLECTION: - g_value_set_object (value, self->pv->collection); - break; - - case PROP_COLUMNS: - g_value_set_pointer (value, (gpointer)self->pv->columns); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gcr_collection_model_dispose (GObject *object) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (object); - - /* Disconnect from all rows */ - if (self->pv->collection) { - remove_children_from_sequence (self, self->pv->root_sequence, - self->pv->collection, FALSE); - g_object_unref (self->pv->collection); - self->pv->collection = NULL; - } - - G_OBJECT_CLASS (gcr_collection_model_parent_class)->dispose (object); -} - -static void -gcr_collection_model_finalize (GObject *object) -{ - GcrCollectionModel *self = GCR_COLLECTION_MODEL (object); - guint i; - - g_assert (!self->pv->collection); - - g_assert (g_sequence_get_length (self->pv->root_sequence) == 0); - g_sequence_free (self->pv->root_sequence); - g_assert (g_hash_table_size (self->pv->object_to_seq) == 0); - g_hash_table_destroy (self->pv->object_to_seq); - - if (self->pv->selected) { - g_assert (g_hash_table_size (self->pv->selected) == 0); - g_hash_table_destroy (self->pv->selected); - self->pv->selected = NULL; - } - - self->pv->columns = NULL; - for (i = 0; i < self->pv->n_columns; i++) - clear_sort_closure (&self->pv->column_sort_closures[i]); - g_free (self->pv->column_sort_closures); - clear_sort_closure (&self->pv->default_sort_closure); - - G_OBJECT_CLASS (gcr_collection_model_parent_class)->finalize (object); -} - -static void -gcr_collection_model_class_init (GcrCollectionModelClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gcr_collection_model_parent_class = g_type_class_peek_parent (klass); - - gobject_class->dispose = gcr_collection_model_dispose; - gobject_class->finalize = gcr_collection_model_finalize; - gobject_class->set_property = gcr_collection_model_set_property; - gobject_class->get_property = gcr_collection_model_get_property; - - g_object_class_install_property (gobject_class, PROP_COLLECTION, - g_param_spec_object ("collection", "Object Collection", "Collection to get objects from", - GCR_TYPE_COLLECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (gobject_class, PROP_COLUMNS, - g_param_spec_pointer ("columns", "Columns", "Columns for the model", - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_type_class_add_private (klass, sizeof (GcrCollectionModelPrivate)); -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_collection_model_new: (skip) - * @collection: The collection to represent - * @...: The column names and types. - * - * Create a new #GcrCollectionModel. The variable argument list should contain - * pairs of property names, and #GType values. The variable argument list should - * be terminated with %NULL. - * - * Returns: (transfer full): a newly allocated model, which should be released - * with g_object_unref(). - */ -GcrCollectionModel* -gcr_collection_model_new (GcrCollection *collection, ...) -{ - GcrColumn column; - GcrCollectionModel *self; - const gchar *arg; - GArray *array; - va_list va; - - /* With a null terminator */ - array = g_array_new (TRUE, TRUE, sizeof (GcrColumn)); - - va_start (va, collection); - while ((arg = va_arg (va, const gchar*)) != NULL) { - memset (&column, 0, sizeof (column)); - column.property_name = g_strdup (arg); - column.property_type = va_arg (va, GType); - column.column_type = column.property_type; - g_array_append_val (array, column); - } - va_end (va); - - self = gcr_collection_model_new_full (collection, (GcrColumn*)array->data); - g_object_set_data_full (G_OBJECT (self), "gcr_collection_model_new", - g_array_free (array, FALSE), free_owned_columns); - return self; -} - -/** - * gcr_collection_model_new_full: (skip) - * @collection: The collection to represent - * @columns: The columns the model should contain - * - * Create a new #GcrCollectionModel. - * - * Returns: (transfer full): a newly allocated model, which should be released - * with g_object_unref() - */ -GcrCollectionModel* -gcr_collection_model_new_full (GcrCollection *collection, const GcrColumn *columns) -{ - GcrCollectionModel *self = g_object_new (GCR_TYPE_COLLECTION_MODEL, "collection", collection, NULL); - gcr_collection_model_set_columns (self, columns); - return self; -} - -/** - * gcr_collection_model_set_columns: (skip) - * @self: The model - * @columns: The columns the model should contain - * - * Set the columns that the model should contain. @columns is an array of - * #GcrColumn structures, with the last one containing %NULL for all values. - * - * This function can only be called once, and only if the model was not created - * without a set of columns. This function cannot be called after the model - * has been added to a view. - * - * The columns are accessed as static data. They should continue to remain - * in memory for longer than the GcrCollectionModel object. - * - * Returns: The number of columns - */ -guint -gcr_collection_model_set_columns (GcrCollectionModel *self, - const GcrColumn *columns) -{ - const GcrColumn *col; - guint n_columns; - - g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), 0); - g_return_val_if_fail (columns, 0); - g_return_val_if_fail (self->pv->n_columns == 0, 0); - - /* Count the number of columns, extra column for selected */ - for (col = columns, n_columns = 1; col->property_name; ++col) - ++n_columns; - - /* We expect the columns to stay around */ - self->pv->columns = columns; - self->pv->n_columns = n_columns; - self->pv->column_sort_closures = g_new0 (GcrCollectionSortClosure, self->pv->n_columns); - - return n_columns - 1; -} - -/** - * gcr_collection_model_get_collection: - * @self: a collection model - * - * Get the collection which this model represents - * - * Returns: (transfer none): the collection, owned by the model - */ -GcrCollection * -gcr_collection_model_get_collection (GcrCollectionModel *self) -{ - g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), NULL); - return self->pv->collection; -} - -/** - * gcr_collection_model_object_for_iter: - * @self: The model - * @iter: The row - * - * Get the object that is represented by the given row in the model. - * - * Returns: (transfer none): The object, owned by the model. - */ -GObject * -gcr_collection_model_object_for_iter (GcrCollectionModel *self, const GtkTreeIter *iter) -{ - g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), NULL); - g_return_val_if_fail (iter != NULL, NULL); - g_return_val_if_fail (iter->stamp == COLLECTION_MODEL_STAMP, NULL); - g_return_val_if_fail (G_IS_OBJECT (iter->user_data), NULL); - - return G_OBJECT (iter->user_data); -} - -/** - * gcr_collection_model_iter_for_object: - * @self: The model - * @object: The object - * @iter: The row for the object - * - * Set @iter to the row for the given object. If the object is not in this - * model, then %FALSE will be returned. - * - * Returns: %TRUE if the object was present. - */ -gboolean -gcr_collection_model_iter_for_object (GcrCollectionModel *self, GObject *object, - GtkTreeIter *iter) -{ - GSequenceIter *seq; - - g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), FALSE); - g_return_val_if_fail (G_IS_OBJECT (object), FALSE); - g_return_val_if_fail (iter != NULL, FALSE); - - seq = g_hash_table_lookup (self->pv->object_to_seq, object); - if (seq == NULL) - return FALSE; - - return sequence_iter_to_tree (self, seq, iter); -} - -/** - * gcr_collection_model_column_for_selected: - * @self: The model - * - * Get the column identifier for the column that contains the values - * of the selected state. - * - * Returns: The column identifier. - */ -gint -gcr_collection_model_column_for_selected (GcrCollectionModel *self) -{ - g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), 0); - g_assert (self->pv->n_columns > 0); - return self->pv->n_columns - 1; -} - -/** - * gcr_collection_model_toggle_selected: - * @self: The model - * @iter: The row - * - * Toggle the selected state of a given row. - */ -void -gcr_collection_model_toggle_selected (GcrCollectionModel *self, GtkTreeIter *iter) -{ - GObject *object; - - g_return_if_fail (GCR_IS_COLLECTION_MODEL (self)); - - object = gcr_collection_model_object_for_iter (self, iter); - g_return_if_fail (G_IS_OBJECT (object)); - - if (!self->pv->selected) - self->pv->selected = selected_hash_table_new (); - - if (g_hash_table_lookup (self->pv->selected, object)) - g_hash_table_remove (self->pv->selected, object); - else - g_hash_table_insert (self->pv->selected, object, object); -} - -/** - * gcr_collection_model_change_selected: - * @self: The model - * @iter: The row - * @selected: Whether the row should be selected or not. - * - * Set whether a given row is toggled selected or not. - */ -void -gcr_collection_model_change_selected (GcrCollectionModel *self, GtkTreeIter *iter, gboolean selected) -{ - GtkTreePath *path; - GObject *object; - - g_return_if_fail (GCR_IS_COLLECTION_MODEL (self)); - - object = gcr_collection_model_object_for_iter (self, iter); - g_return_if_fail (G_IS_OBJECT (object)); - - if (!self->pv->selected) - self->pv->selected = g_hash_table_new (g_direct_hash, g_direct_equal); - - if (selected) - g_hash_table_insert (self->pv->selected, object, object); - else - g_hash_table_remove (self->pv->selected, object); - - /* Tell the view that this row changed */ - path = gtk_tree_model_get_path (GTK_TREE_MODEL (self), iter); - g_return_if_fail (path); - gtk_tree_model_row_changed (GTK_TREE_MODEL (self), path, iter); - gtk_tree_path_free (path); -} - -/** - * gcr_collection_model_is_selected: - * @self: The model - * @iter: The row - * - * Check whether a given row has been toggled as selected. - * - * Returns: Whether the row has been selected. - */ -gboolean -gcr_collection_model_is_selected (GcrCollectionModel *self, GtkTreeIter *iter) -{ - GObject *object; - - g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), FALSE); - - object = gcr_collection_model_object_for_iter (self, iter); - g_return_val_if_fail (G_IS_OBJECT (object), FALSE); - - if (!self->pv->selected) - return FALSE; - - return g_hash_table_lookup (self->pv->selected, object) ? TRUE : FALSE; -} - -/** - * gcr_collection_model_get_selected_objects: - * @self: the collection model - * - * Get a list of checked/selected objects. - * - * Returns: (transfer container) (element-type GLib.Object): a list of selected - * objects, which should be freed with g_list_free() - */ -GList * -gcr_collection_model_get_selected_objects (GcrCollectionModel *self) -{ - GHashTableIter iter; - GList *result = NULL; - gpointer key; - - g_return_val_if_fail (GCR_IS_COLLECTION_MODEL (self), NULL); - - if (!self->pv->selected) - return NULL; - - g_hash_table_iter_init (&iter, self->pv->selected); - while (g_hash_table_iter_next (&iter, &key, NULL)) - result = g_list_prepend (result, key); - return result; -} - -/** - * gcr_collection_model_set_selected_objects: - * @self: the collection model - * @selected: (element-type GLib.Object): a list of objects to select - * - * Set the checked/selected objects. - */ -void -gcr_collection_model_set_selected_objects (GcrCollectionModel *self, - GList *selected) -{ - GHashTable *newly_selected; - GList *old_selection; - GtkTreeIter iter; - GList *l; - - old_selection = gcr_collection_model_get_selected_objects (self); - newly_selected = selected_hash_table_new (); - - /* Select all the objects in selected which aren't already selected */ - for (l = selected; l; l = g_list_next (l)) { - if (!self->pv->selected || !g_hash_table_lookup (self->pv->selected, l->data)) { - if (!gcr_collection_model_iter_for_object (self, l->data, &iter)) - g_return_if_reached (); - gcr_collection_model_change_selected (self, &iter, TRUE); - } - - /* Note that we've seen this one */ - g_hash_table_insert (newly_selected, l->data, l->data); - } - - /* Unselect all the objects which aren't supposed to be selected */ - for (l = old_selection; l; l = g_list_next (l)) { - if (!g_hash_table_lookup (newly_selected, l->data)) { - if (!gcr_collection_model_iter_for_object (self, l->data, &iter)) - g_return_if_reached (); - gcr_collection_model_change_selected (self, &iter, FALSE); - } - } - - g_list_free (old_selection); - g_hash_table_destroy (newly_selected); -} diff --git a/gcr/gcr-collection-model.h b/gcr/gcr-collection-model.h deleted file mode 100644 index fcd98e1b..00000000 --- a/gcr/gcr-collection-model.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * 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., - * 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __GCR_COLLECTION_MODEL_H__ -#define __GCR_COLLECTION_MODEL_H__ - -#include <gtk/gtk.h> - -#include "gcr-collection.h" -#include "gcr-column.h" - -#define GCR_TYPE_COLLECTION_MODEL (gcr_collection_model_get_type ()) -#define GCR_COLLECTION_MODEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_COLLECTION_MODEL, GcrCollectionModel)) -#define GCR_COLLECTION_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_COLLECTION_MODEL, GcrCollectionModelClass)) -#define GCR_IS_COLLECTION_MODEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_COLLECTION_MODEL)) -#define GCR_IS_COLLECTION_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_COLLECTION_MODEL)) -#define GCR_COLLECTION_MODEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_COLLECTION_MODEL, GcrCollectionModelClass)) - -typedef struct _GcrCollectionModel GcrCollectionModel; -typedef struct _GcrCollectionModelClass GcrCollectionModelClass; -typedef struct _GcrCollectionModelPrivate GcrCollectionModelPrivate; - -struct _GcrCollectionModel { - GObject parent; - - /*< private >*/ - GcrCollectionModelPrivate *pv; -}; - -struct _GcrCollectionModelClass { - GObjectClass parent_class; -}; - -GType gcr_collection_model_get_type (void); - -GcrCollectionModel* gcr_collection_model_new (GcrCollection *collection, - ...) G_GNUC_NULL_TERMINATED; - -GcrCollectionModel* gcr_collection_model_new_full (GcrCollection *collection, - const GcrColumn *columns); - -guint gcr_collection_model_set_columns (GcrCollectionModel *self, - const GcrColumn *columns); - -GcrCollection * gcr_collection_model_get_collection (GcrCollectionModel *self); - -GObject* gcr_collection_model_object_for_iter (GcrCollectionModel *self, - const GtkTreeIter *iter); - -gboolean gcr_collection_model_iter_for_object (GcrCollectionModel *self, - GObject *object, - GtkTreeIter *iter); - -gint gcr_collection_model_column_for_selected (GcrCollectionModel *self); - -void gcr_collection_model_toggle_selected (GcrCollectionModel *self, - GtkTreeIter *iter); - -void gcr_collection_model_change_selected (GcrCollectionModel *self, - GtkTreeIter *iter, - gboolean selected); - -gboolean gcr_collection_model_is_selected (GcrCollectionModel *self, - GtkTreeIter *iter); - -GList* gcr_collection_model_get_selected_objects (GcrCollectionModel *self); - -void gcr_collection_model_set_selected_objects (GcrCollectionModel *self, - GList *selected); - -#endif /* __GCR_COLLECTION_MODEL_H__ */ diff --git a/gcr/gcr-collection.c b/gcr/gcr-collection.c deleted file mode 100644 index 08bbedbb..00000000 --- a/gcr/gcr-collection.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-collection.h" - -/** - * SECTION:gcr-collection - * @title: GcrCollection - * @short_description: A collection of objects. - * - * A #GcrCollection is used to group a set of objects. This is an abstract - * interface which can be used to determine which objects show up in a selector - * or other user interface element. - * - * Use gcr_simple_collection_new() to create a concrete implementation of this - * interface which you can add objects to. - */ - -/** - * GcrCollection: - * - * A #GcrCollection is used to group a set of objects. - */ - -enum { - ADDED, - REMOVED, - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - - -typedef GcrCollectionIface GcrCollectionInterface; - -G_DEFINE_INTERFACE (GcrCollection, gcr_collection, G_TYPE_OBJECT); - -static void -gcr_collection_default_init (GcrCollectionIface *iface) -{ - static volatile gsize initialized = 0; - - if (g_once_init_enter (&initialized)) { - - /** - * GcrCollection::added: - * @self: the collection - * @object: (type GLib.Object): object that was added - * - * This signal is emitted when an object is added to the collection. - */ - signals[ADDED] = g_signal_new ("added", GCR_TYPE_COLLECTION, - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrCollectionIface, added), - NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - /** - * GcrCollection::removed: - * @self: the collection - * @object: (type GLib.Object): object that was removed - * - * This signal is emitted when an object is removed from the collection. - */ - signals[REMOVED] = g_signal_new ("removed", GCR_TYPE_COLLECTION, - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrCollectionIface, removed), - NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - g_once_init_leave (&initialized, 1); - } -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - - -/** - * gcr_collection_get_length: - * @self: The collection - * - * Get the number of objects in this collection. - * - * Returns: The number of objects. - */ -guint -gcr_collection_get_length (GcrCollection *self) -{ - g_return_val_if_fail (GCR_IS_COLLECTION (self), 0); - g_return_val_if_fail (GCR_COLLECTION_GET_INTERFACE (self)->get_length, 0); - return GCR_COLLECTION_GET_INTERFACE (self)->get_length (self); -} - -/** - * gcr_collection_get_objects: - * @self: The collection - * - * Get a list of the objects in this collection. - * - * Returns: (transfer container) (element-type GLib.Object): a list of the objects - * in this collection, which should be freed with g_list_free() - */ -GList* -gcr_collection_get_objects (GcrCollection *self) -{ - g_return_val_if_fail (GCR_IS_COLLECTION (self), 0); - g_return_val_if_fail (GCR_COLLECTION_GET_INTERFACE (self)->get_objects, 0); - return GCR_COLLECTION_GET_INTERFACE (self)->get_objects (self); -} - -/** - * gcr_collection_contains: - * @self: the collection - * @object: object to check - * - * Check whether the collection contains an object or not. - * - * Returns: whether the collection contains this object - */ -gboolean -gcr_collection_contains (GcrCollection *self, - GObject *object) -{ - g_return_val_if_fail (GCR_IS_COLLECTION (self), FALSE); - g_return_val_if_fail (G_IS_OBJECT (object), FALSE); - g_return_val_if_fail (GCR_COLLECTION_GET_INTERFACE (self)->contains, FALSE); - return GCR_COLLECTION_GET_INTERFACE (self)->contains (self, object); -} - -/** - * gcr_collection_emit_added: - * @self: The collection - * @object: The object that was added - * - * Emit the GcrCollection::added signal for the given object. This function - * is used by implementors of this interface. - */ -void -gcr_collection_emit_added (GcrCollection *self, GObject *object) -{ - g_return_if_fail (GCR_IS_COLLECTION (self)); - g_signal_emit (self, signals[ADDED], 0, object); -} - -/** - * gcr_collection_emit_removed: - * @self: The collection - * @object: The object that was removed - * - * Emit the GcrCollection::removed signal for the given object. This function - * is used by implementors of this interface. - */ -void -gcr_collection_emit_removed (GcrCollection *self, GObject *object) -{ - g_return_if_fail (GCR_IS_COLLECTION (self)); - g_signal_emit (self, signals[REMOVED], 0, object); -} diff --git a/gcr/gcr-collection.h b/gcr/gcr-collection.h deleted file mode 100644 index 2616394c..00000000 --- a/gcr/gcr-collection.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_COLLECTION_H__ -#define __GCR_COLLECTION_H__ - -#include "gcr-types.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_COLLECTION (gcr_collection_get_type()) -#define GCR_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_COLLECTION, GcrCollection)) -#define GCR_IS_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_COLLECTION)) -#define GCR_COLLECTION_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_COLLECTION, GcrCollectionIface)) - -typedef struct _GcrCollection GcrCollection; -typedef struct _GcrCollectionIface GcrCollectionIface; - -struct _GcrCollectionIface { - GTypeInterface parent; - - /* signals */ - void (*added) (GcrCollection *self, GObject *object); - - void (*removed) (GcrCollection *self, GObject *object); - - /* virtual */ - guint (*get_length) (GcrCollection *self); - - GList* (*get_objects) (GcrCollection *self); - - gboolean (*contains) (GcrCollection *self, - GObject *object); - - /*< private >*/ - gpointer dummy1; - gpointer dummy2; - gpointer dummy3; - gpointer dummy5; - gpointer dummy6; - gpointer dummy7; - gpointer dummy8; -}; - -GType gcr_collection_get_type (void); - -guint gcr_collection_get_length (GcrCollection *self); - -GList* gcr_collection_get_objects (GcrCollection *self); - -gboolean gcr_collection_contains (GcrCollection *self, - GObject *object); - -void gcr_collection_emit_added (GcrCollection *self, - GObject *object); - -void gcr_collection_emit_removed (GcrCollection *self, - GObject *object); - -G_END_DECLS - -#endif /* __GCR_COLLECTION_H__ */ diff --git a/gcr/gcr-column.c b/gcr/gcr-column.c deleted file mode 100644 index 254f55ce..00000000 --- a/gcr/gcr-column.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-column.h" - -/** - * SECTION:gcr-column - * @title: GcrColumn - * @short_description: Column information for selector or model. - * - * A #GcrColumn is used with #GcrTreeSelector or #GcrCollectionModel to define - * the columns to display. - */ - -/** - * GcrColumnFlags: - * @GCR_COLUMN_NONE: No column flags - * @GCR_COLUMN_HIDDEN: Don't display this column. - * @GCR_COLUMN_SORTABLE: This column is sortable. - * - * Flags to be used with #GcrColumn - */ - -/** - * GcrColumn: - * @property_name: The name of the property this column will display - * @property_type: The type of the property - * @column_type: The eventual type of the column - * @label: The display label for the column - * @flags: Flags from #GcrColumnFlags - * @transformer: A transformer function used to convert the value from - * the property type to the column type. Can be %NULL if the types - * are the same. - * @user_data: User data associated with the column - * - * Represents a column to display in a #GcrCollectionModel or #GcrTreeSelector. - * - * The label should be set as a translatable string with a context of - * <code>"column"</code>. This should be done with with this macro: - * - * <informalexample><programlisting> - * NC_("column", "My Column Name") - * </programlisting></informalexample> - */ diff --git a/gcr/gcr-column.h b/gcr/gcr-column.h deleted file mode 100644 index 65ee6a60..00000000 --- a/gcr/gcr-column.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_COLUMN_H__ -#define __GCR_COLUMN_H__ - -#include "gcr-types.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -typedef enum { - GCR_COLUMN_NONE = 0, - GCR_COLUMN_HIDDEN = 1 << 1, - GCR_COLUMN_SORTABLE = 1 << 2, -} GcrColumnFlags; - -typedef struct _GcrColumn { - const gchar *property_name; /* The property to retrieve */ - GType property_type; /* The property type */ - GType column_type; /* The resulting property type for this column */ - - const gchar *label; /* The label for this column, or NULL */ - GcrColumnFlags flags; /* Column flags */ - - GValueTransform transformer; /* The way to transform to this type or NULL */ - - gpointer user_data; - - /*< private >*/ - gpointer reserved; -} GcrColumn; - -G_END_DECLS - -#endif /* __GCR_COLUMN_H__ */ diff --git a/gcr/gcr-combo-selector.c b/gcr/gcr-combo-selector.c deleted file mode 100644 index 56e06fe9..00000000 --- a/gcr/gcr-combo-selector.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-collection-model.h" -#include "gcr-internal.h" -#include "gcr-combo-selector.h" - -#include <glib/gi18n-lib.h> - -#include <string.h> - -/** - * SECTION:gcr-combo-selector - * @title: GcrComboSelector - * @short_description: A selector widget to select a single certificate or key. - * - * The #GcrComboSelector can be used to select a certificate or key. It allows - * the user to select one object from the selector at a time. - */ - -/** - * GcrComboSelector: - * - * A combo selector widget. - */ - -/** - * GcrComboSelectorClass: - * - * The class for #GcrComboSelector. - */ - -enum { - PROP_0, - PROP_COLLECTION -}; - -struct _GcrComboSelectorPrivate { - GcrCollection *collection; - GcrCollectionModel *model; -}; - -G_DEFINE_TYPE (GcrComboSelector, gcr_combo_selector, GTK_TYPE_COMBO_BOX); - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static GObject* -gcr_combo_selector_constructor (GType type, guint n_props, GObjectConstructParam *props) -{ - GcrComboSelector *self = GCR_COMBO_SELECTOR (G_OBJECT_CLASS (gcr_combo_selector_parent_class)->constructor(type, n_props, props)); - GtkCellRenderer *cell; - - g_return_val_if_fail (self, NULL); - - self->pv->model = gcr_collection_model_new (self->pv->collection, - "icon", G_TYPE_ICON, - "markup", G_TYPE_STRING, - NULL); - - gtk_combo_box_set_model (GTK_COMBO_BOX (self), GTK_TREE_MODEL (self->pv->model)); - - /* The icon */ - cell = gtk_cell_renderer_pixbuf_new (); - g_object_set (cell, "stock-size", GTK_ICON_SIZE_DND, NULL); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self), cell, FALSE); - gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self), cell, "gicon", 0); - - /* The markup */ - cell = gtk_cell_renderer_text_new (); - gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self), cell, TRUE); - gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (self), cell, "markup", 1); - - return G_OBJECT (self); -} - -static void -gcr_combo_selector_init (GcrComboSelector *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_COMBO_SELECTOR, GcrComboSelectorPrivate); -} - -static void -gcr_combo_selector_dispose (GObject *obj) -{ - GcrComboSelector *self = GCR_COMBO_SELECTOR (obj); - - if (self->pv->model) - g_object_unref (self->pv->model); - self->pv->model = NULL; - - if (self->pv->collection) - g_object_unref (self->pv->collection); - self->pv->collection = NULL; - - G_OBJECT_CLASS (gcr_combo_selector_parent_class)->dispose (obj); -} - -static void -gcr_combo_selector_finalize (GObject *obj) -{ - GcrComboSelector *self = GCR_COMBO_SELECTOR (obj); - - g_assert (!self->pv->collection); - g_assert (!self->pv->model); - - G_OBJECT_CLASS (gcr_combo_selector_parent_class)->finalize (obj); -} - -static void -gcr_combo_selector_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrComboSelector *self = GCR_COMBO_SELECTOR (obj); - - switch (prop_id) { - case PROP_COLLECTION: - g_return_if_fail (!self->pv->collection); - self->pv->collection = g_value_dup_object (value); - g_return_if_fail (self->pv->collection); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_combo_selector_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrComboSelector *self = GCR_COMBO_SELECTOR (obj); - - switch (prop_id) { - case PROP_COLLECTION: - g_value_set_object (value, gcr_combo_selector_get_collection (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_combo_selector_class_init (GcrComboSelectorClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->constructor = gcr_combo_selector_constructor; - gobject_class->dispose = gcr_combo_selector_dispose; - gobject_class->finalize = gcr_combo_selector_finalize; - gobject_class->set_property = gcr_combo_selector_set_property; - gobject_class->get_property = gcr_combo_selector_get_property; - - g_type_class_add_private (gobject_class, sizeof (GcrComboSelectorPrivate)); - - /** - * GcrComboSelector:collection: - * - * The collection which contains the objects to display in the selector. - */ - g_object_class_install_property (gobject_class, PROP_COLLECTION, - g_param_spec_object ("collection", "Collection", "Collection to select from", - GCR_TYPE_COLLECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_combo_selector_new: - * @collection: The collection that contains the objects to display - * - * Create a new #GcrTreeSelector. - * - * Returns: A newly allocated selector, which should be released with - * g_object_unref(). - */ -GcrComboSelector* -gcr_combo_selector_new (GcrCollection *collection) -{ - return g_object_new (GCR_TYPE_COMBO_SELECTOR, - "collection", collection, - NULL); -} - -/** - * gcr_combo_selector_get_collection: - * @self: The selector - * - * Get the collection that this selector is displaying objects from. - * - * Returns: (transfer none): The collection, owned by the selector. - */ -GcrCollection * -gcr_combo_selector_get_collection (GcrComboSelector *self) -{ - g_return_val_if_fail (GCR_IS_COMBO_SELECTOR (self), NULL); - return self->pv->collection; -} - -/** - * gcr_combo_selector_get_selected: - * @self: The selector - * - * Get the selected object in the selector, or %NULL if nothing selected. - * - * Returns: (transfer none): the selected object, owned by the selector, or %NULL - */ -GObject * -gcr_combo_selector_get_selected (GcrComboSelector *self) -{ - GtkTreeIter iter; - - g_return_val_if_fail (GCR_IS_COMBO_SELECTOR (self), NULL); - gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self), &iter); - - return gcr_collection_model_object_for_iter (self->pv->model, &iter); -} - -/** - * gcr_combo_selector_set_selected: - * @self: The selector - * @selected: (allow-none): the object to select or %NULL - * - * Set the currently selected object in the selector, or clear the selection - * if selected is set to %NULL. - */ -void -gcr_combo_selector_set_selected (GcrComboSelector *self, GObject *selected) -{ - GtkTreeIter iter; - - g_return_if_fail (GCR_IS_COMBO_SELECTOR (self)); - - if (selected) { - if (!gcr_collection_model_iter_for_object (self->pv->model, selected, &iter)) - g_return_if_reached (); - gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self), &iter); - } else { - gtk_combo_box_set_active_iter (GTK_COMBO_BOX (self), NULL); - } -} diff --git a/gcr/gcr-combo-selector.h b/gcr/gcr-combo-selector.h deleted file mode 100644 index 2e519a08..00000000 --- a/gcr/gcr-combo-selector.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_COMBO_SELECTOR_H__ -#define __GCR_COMBO_SELECTOR_H__ - -#include "gcr-types.h" - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_COMBO_SELECTOR (gcr_combo_selector_get_type ()) -#define GCR_COMBO_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_COMBO_SELECTOR, GcrComboSelector)) -#define GCR_COMBO_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_COMBO_SELECTOR, GcrComboSelectorClass)) -#define GCR_IS_COMBO_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_COMBO_SELECTOR)) -#define GCR_IS_COMBO_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_COMBO_SELECTOR)) -#define GCR_COMBO_SELECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_COMBO_SELECTOR, GcrComboSelectorClass)) - -typedef struct _GcrComboSelector GcrComboSelector; -typedef struct _GcrComboSelectorClass GcrComboSelectorClass; -typedef struct _GcrComboSelectorPrivate GcrComboSelectorPrivate; - -struct _GcrComboSelector { - GtkComboBox parent; - - /*< private >*/ - GcrComboSelectorPrivate *pv; -}; - -struct _GcrComboSelectorClass { - /*< private >*/ - GtkComboBoxClass parent_class; -}; - -GType gcr_combo_selector_get_type (void); - -GcrComboSelector* gcr_combo_selector_new (GcrCollection *collection); - -GcrCollection* gcr_combo_selector_get_collection (GcrComboSelector *self); - -GObject* gcr_combo_selector_get_selected (GcrComboSelector *self); - -void gcr_combo_selector_set_selected (GcrComboSelector *self, - GObject *selected); - -G_END_DECLS - -#endif /* __GCR_COMBO_SELECTOR_H__ */ diff --git a/gcr/gcr-comparable.c b/gcr/gcr-comparable.c deleted file mode 100644 index fddbdd1f..00000000 --- a/gcr/gcr-comparable.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-comparable.h" - -#include <string.h> - -/** - * SECTION:gcr-comparable - * @title: GcrComparable - * @short_description: Interface for comparing objects - * - * The #GcrComparable interface is implemented by objects when they should be - * comparable against one another. - */ - -/** - * GcrComparable: - * - * The #GcrComparable interface is implemented by comparable objects. - */ - -/** - * GcrComparableIface: - * - * The interface to implement for #GcrComparable - */ - -/* --------------------------------------------------------------------------------- - * INTERFACE - */ - -static void -gcr_comparable_base_init (gpointer g_class) -{ - static volatile gsize initialized = 0; - - if (g_once_init_enter (&initialized)) { - /* Add properties and signals to the interface */ - g_once_init_leave (&initialized, 1); - } -} - -GType -gcr_comparable_get_type (void) -{ - static GType type = 0; - if (!type) { - static const GTypeInfo info = { - sizeof (GcrComparableIface), - gcr_comparable_base_init, /* base init */ - NULL, /* base finalize */ - NULL, /* class_init */ - NULL, /* class finalize */ - NULL, /* class data */ - 0, - 0, /* n_preallocs */ - NULL, /* instance init */ - }; - type = g_type_register_static (G_TYPE_INTERFACE, "GcrComparableIface", &info, 0); - g_type_interface_add_prerequisite (type, G_TYPE_OBJECT); - } - - return type; -} - - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_comparable_compare: - * @self: The comparable object - * @other: Another comparable object - * - * Compare whether two objects represent the same thing. The return value can - * also be used to sort the objects. - * - * Returns: Zero if the two objects represent the same thing, non-zero if not. - */ -gint -gcr_comparable_compare (GcrComparable *self, GcrComparable *other) -{ - g_return_val_if_fail (GCR_IS_COMPARABLE (self), -1); - g_return_val_if_fail (GCR_COMPARABLE_GET_INTERFACE (self)->compare, -1); - g_return_val_if_fail (G_IS_OBJECT (self), -1); - return GCR_COMPARABLE_GET_INTERFACE (self)->compare (self, other); -} - -/** - * gcr_comparable_memcmp: (skip) - * @mem1: First block of memory - * @size1: Length of first block - * @mem2: Second lock of memory - * @size2: Length of second block - * - * Compare two blocks of memory. The return value can be used to sort - * the blocks of memory. - * - * Returns: Zero if the blocks are identical, non-zero if not. - */ -gint -gcr_comparable_memcmp (gconstpointer mem1, gsize size1, - gconstpointer mem2, gsize size2) -{ - gint result; - - if (mem1 == mem2 && size1 == size2) - return 0; - - if (!mem1) - return 1; - if (!mem2) - return -1; - - result = memcmp (mem1, mem2, MIN (size1, size2)); - if (result != 0) - return result; - - if (size1 == size2) - return 0; - if (size1 < size2) - return -1; - return 1; -} diff --git a/gcr/gcr-comparable.h b/gcr/gcr-comparable.h deleted file mode 100644 index 39f1d8ad..00000000 --- a/gcr/gcr-comparable.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_COMPARABLE_H__ -#define __GCR_COMPARABLE_H__ - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_COMPARABLE (gcr_comparable_get_type()) -#define GCR_COMPARABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_COMPARABLE, GcrComparable)) -#define GCR_IS_COMPARABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_COMPARABLE)) -#define GCR_COMPARABLE_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_COMPARABLE, GcrComparableIface)) - -typedef struct _GcrComparable GcrComparable; -typedef struct _GcrComparableIface GcrComparableIface; - -struct _GcrComparableIface { - GTypeInterface parent; - gint (*compare) (GcrComparable *self, GcrComparable *other); -}; - -GType gcr_comparable_get_type (void); - -gint gcr_comparable_compare (GcrComparable *self, - GcrComparable *other); - -gint gcr_comparable_memcmp (gconstpointer mem1, - gsize size1, - gconstpointer mem2, - gsize size2); - -G_END_DECLS - -#endif /* __GCR_COMPARABLE_H__ */ diff --git a/gcr/gcr-crypto-types.xml b/gcr/gcr-crypto-types.xml deleted file mode 100644 index b911ccd9..00000000 --- a/gcr/gcr-crypto-types.xml +++ /dev/null @@ -1,151 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info"> - - <!-- Non standard: Common practice --> - <mime-type type="application/x-pem-file"> - <comment>Openssl PEM format</comment> - <acronym>PEM</acronym> - <sub-class-of type="text/plain"/> - <glob weight="50" pattern="*.pem"/> - </mime-type> - - <!-- Defined in: http://www.ietf.org/rfc/rfc2585.txt --> - <mime-type type="application/pkix-cert"> - <comment>X.509 Certificate</comment> - <glob weight="75" pattern="*.cer"/> - - <!-- Non standard: Common practice --> - <glob weight="55" pattern="*.crt"/> - <glob weight="55" pattern="*.cert"/> - - <!-- Non standard: Common practice --> - <alias type="application/x-x509-ca-cert"/> - <alias type="application/x-x509-user-cert"/> - </mime-type> - - <!-- Non standard: OpenSSL PEM format --> - <mime-type type="application/pkix-cert+pem"> - <comment>X.509 Certificate in PEM format</comment> - <sub-class-of type="application/x-pem-file"/> - <magic priority="75"> - <match type="string" value="-----BEGIN CERTIFICATE-----" offset="0"/> - </magic> - </mime-type> - - <!-- Defined in: http://www.ietf.org/rfc/rfc2585.txt --> - <mime-type type="application/pkix-crl"> - <comment>Certificate Revocation List</comment> - <acronym>CRL</acronym> - <expanded-acronym>Certificate Revocation List</expanded-acronym> - <glob weight="75" pattern="*.crl"/> - </mime-type> - - <!-- Non standard: OpenSSL PEM format --> - <mime-type type="application/pkix-crl+pem"> - <comment>Certificate Revocation List in PEM format</comment> - <sub-class-of type="application/x-pem-file"/> - <magic priority="75"> - <match type="string" value="-----BEGIN X509 CRL-----" offset="0"/> - </magic> - </mime-type> - - <!-- Non standard: Common practice --> - <mime-type type="application/x-pkcs12"> - <comment>PKCS#12 Personal Key and Certificates</comment> - <acronym>PKCS#12</acronym> - <glob weight="75" pattern="*.p12"/> - - <!-- Non standard: Microsoft practice --> - <glob weight="55" pattern="*.pfx"/> - - <!-- Non standard: Rare practice, unclear this actually got into a spec --> - <alias type="application/pkcs12"/> - </mime-type> - - <!-- Non standard: OpenSSL PEM format --> - <mime-type type="application/pkcs12+pem"> - <comment>PKCS#12 Personal Key and Certificates in PEM format</comment> - <sub-class-of type="application/x-pem-file"/> - <magic priority="75"> - <match type="string" value="-----BEGIN PKCS12-----" offset="0"/> - </magic> - </mime-type> - - <!-- Defined in: http://www.ietf.org/rfc/rfc5958.txt --> - <mime-type type="application/pkcs8"> - <comment>PKCS#8 Personal Key</comment> - <acronym>PKCS#8</acronym> - <glob weight="75" pattern="*.p8"/> - - <!-- Non standard: Gnome keyring practice --> - <glob weight="55" pattern="*.pkcs8"/> - </mime-type> - - <!-- Non standard: OpenSSL PEM format --> - <mime-type type="application/pkcs8+pem"> - <comment>PKCS#8 Personal Key in PEM format</comment> - <sub-class-of type="application/x-pem-file"/> - <magic priority="75"> - <match type="string" value="-----BEGIN PRIVATE KEY-----" offset="0"/> - <match type="string" value="-----BEGIN ENCRYPTED PRIVATE KEY-----" offset="0"/> - </magic> - </mime-type> - - <!-- Defined in: http://www.ietf.org/rfc/rfc2311.txt --> - <mime-type type="application/pkcs7-mime"> - <comment>PKCS#7 Message and Certificates</comment> - <acronym>PKCS#7</acronym> - <glob pattern="*.p7c"/> - <glob pattern="*.p7m"/> - - <!-- Not standard: Microsoft practice --> - <glob pattern="*.spc"/> - <glob pattern="*.p7b"/> - - <!-- Non standard: Microsoft practice --> - <alias type="application/x-pkcs7-certificates"/> - </mime-type> - - <!-- Non standard: OpenSSL PEM format --> - <mime-type type="application/pkcs7-mime+pem"> - <comment>PKCS#7 Message and Certificates in PEM format</comment> - <sub-class-of type="application/x-pem-file"/> - <magic priority="75"> - <match type="string" value="-----BEGIN PKCS7-----" offset="0"/> - </magic> - </mime-type> - - <!-- Defined in http://www.ietf.org/rfc/rfc2311.txt --> - <mime-type type="application/pkcs7-signature"> - <comment>PKCS#7 Signature</comment> - <acronym>PKCS#7</acronym> - <glob pattern="*.p7s"/> - </mime-type> - - <!-- Defined in http://www.ietf.org/rfc/rfc2311.txt --> - <mime-type type="application/pkcs10"> - <comment>PKCS#10 Certificate Request</comment> - <acronym>PKCS#10</acronym> - <glob pattern="*.p10"/> - </mime-type> - - <!-- Non standard: OpenSSL PEM format --> - <mime-type type="application/pkcs10+pem"> - <comment>PKCS#10 Certificate Request in PEM format</comment> - <sub-class-of type="application/x-pem-file"/> - <magic priority="75"> - <match type="string" value="-----BEGIN CERTIFICATE REQUEST-----" offset="0"/> - <match type="string" value="-----BEGIN NEW CERTIFICATE REQUEST-----" offset="0"/> - </magic> - </mime-type> - - <!-- Non standard: OpenSSL PEM format --> - <mime-type type="application/x-pem-key"> - <comment>Private Key in PEM format</comment> - <sub-class-of type="application/x-pem-file"/> - <magic priority="75"> - <match type="string" value="-----BEGIN RSA PRIVATE KEY-----" offset="0"/> - <match type="string" value="-----BEGIN DSA PRIVATE KEY-----" offset="0"/> - </magic> - </mime-type> -</mime-info> diff --git a/gcr/gcr-debug.c b/gcr/gcr-debug.c deleted file mode 100644 index fea8fee8..00000000 --- a/gcr/gcr-debug.c +++ /dev/null @@ -1,111 +0,0 @@ -/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */ -/* - * Copyright (C) 2007 Collabora Ltd. - * Copyright (C) 2007 Nokia Corporation - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include "gcr-debug.h" - -#include <errno.h> -#include <fcntl.h> -#include <stdarg.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <glib.h> -#include <glib/gstdio.h> - -#ifdef WITH_DEBUG - -static GcrDebugFlags current_flags = 0; - -static GDebugKey keys[] = { - { "library", GCR_DEBUG_LIBRARY }, - { "certificate-chain", GCR_DEBUG_CERTIFICATE_CHAIN }, - { "parse", GCR_DEBUG_PARSE }, - { "gnupg", GCR_DEBUG_GNUPG }, - { "trust", GCR_DEBUG_TRUST }, - { "import", GCR_DEBUG_IMPORT }, - { 0, } -}; - -static void -debug_set_flags (GcrDebugFlags new_flags) -{ - current_flags |= new_flags; -} - -void -_gcr_debug_set_flags (const gchar *flags_string) -{ - guint nkeys; - - for (nkeys = 0; keys[nkeys].value; nkeys++); - - if (flags_string) - debug_set_flags (g_parse_debug_string (flags_string, keys, nkeys)); -} - -gboolean -_gcr_debug_flag_is_set (GcrDebugFlags flag) -{ - return (flag & current_flags) != 0; -} - -void -_gcr_debug_message (GcrDebugFlags flag, const gchar *format, ...) -{ - static gsize initialized_flags = 0; - gchar *message; - va_list args; - - if (g_once_init_enter (&initialized_flags)) { - _gcr_debug_set_flags (g_getenv ("GCR_DEBUG")); - g_once_init_leave (&initialized_flags, 1); - } - - va_start (args, format); - message = g_strdup_vprintf (format, args); - va_end (args); - - if (flag & current_flags) - g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "%s", message); - - g_free (message); -} - -#else /* !WITH_DEBUG */ - -gboolean -_gcr_debug_flag_is_set (GcrDebugFlags flag) -{ - return FALSE; -} - -void -_gcr_debug_message (GcrDebugFlags flag, const gchar *format, ...) -{ -} - -void -_gcr_debug_set_flags (const gchar *flags_string) -{ -} - -#endif /* !WITH_DEBUG */ diff --git a/gcr/gcr-debug.h b/gcr/gcr-debug.h deleted file mode 100644 index 20bc35f4..00000000 --- a/gcr/gcr-debug.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2007 Nokia Corporation - * Copyright (C) 2007-2011 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef GCR_DEBUG_H -#define GCR_DEBUG_H - -#include "config.h" - -#include <glib.h> - -G_BEGIN_DECLS - -/* Please keep this enum in sync with #keys in gcr-debug.c */ -typedef enum { - GCR_DEBUG_LIBRARY = 1 << 1, - GCR_DEBUG_CERTIFICATE_CHAIN = 1 << 2, - GCR_DEBUG_PARSE = 1 << 3, - GCR_DEBUG_GNUPG = 1 << 4, - GCR_DEBUG_TRUST = 1 << 5, - GCR_DEBUG_IMPORT = 1 << 6, -} GcrDebugFlags; - -gboolean _gcr_debug_flag_is_set (GcrDebugFlags flag); - -void _gcr_debug_set_flags (const gchar *flags_string); - -void _gcr_debug_message (GcrDebugFlags flag, - const gchar *format, - ...) G_GNUC_PRINTF (2, 3); - -G_END_DECLS - -#endif /* GCR_DEBUG_H */ - -/* ----------------------------------------------------------------------------- - * Below this point is outside the GCR_DEBUG_H guard - so it can take effect - * more than once. So you can do: - * - * #define DEBUG_FLAG GCR_DEBUG_ONE_THING - * #include "gcr-debug.h" - * ... - * DEBUG ("if we're debugging one thing"); - * ... - * #undef DEBUG_FLAG - * #define DEBUG_FLAG GCR_DEBUG_OTHER_THING - * #include "gcr-debug.h" - * ... - * DEBUG ("if we're debugging the other thing"); - * ... - */ - -#ifdef DEBUG_FLAG -#ifdef WITH_DEBUG - -#undef _gcr_debug -#define _gcr_debug(format, ...) \ - _gcr_debug_message (DEBUG_FLAG, "%s: " format, G_STRFUNC, ##__VA_ARGS__) - -#undef _gcr_debugging -#define _gcr_debugging \ - _gcr_debug_flag_is_set (DEBUG_FLAG) - -#else /* !defined (WITH_DEBUG) */ - -#undef _gcr_debug -#define _gcr_debug(format, ...) \ - do {} while (0) - -#undef _gcr_debugging -#define _gcr_debugging 0 - -#endif /* !defined (WITH_DEBUG) */ - -#endif /* defined (DEBUG_FLAG) */ diff --git a/gcr/gcr-deprecated-base.h b/gcr/gcr-deprecated-base.h deleted file mode 100644 index 6ecfd904..00000000 --- a/gcr/gcr-deprecated-base.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef GCR_BASE_DEPRECATED_H_ -#define GCR_BASE_DEPRECATED_H_ -#ifndef GCR_DISABLE_DEPRECATED -#ifndef __GI_SCANNER__ - -#include <glib.h> - -#include "gcr-importer.h" -#include "gcr-parser.h" -#include "gcr-simple-collection.h" - -G_BEGIN_DECLS - -#define GCR_ERROR (gcr_error_get_domain ()) - -GQuark gcr_error_get_domain (void) G_GNUC_CONST; - -gboolean gcr_simple_collection_contains (GcrSimpleCollection *self, - GObject *object); - -GcrParser * gcr_importer_get_parser (GcrImporter *self); - -void gcr_importer_set_parser (GcrImporter *self, - GcrParser *parser); - -GckSlot * gcr_importer_get_slot (GcrImporter *self); - -void gcr_importer_set_slot (GcrImporter *self, - GckSlot *slot); - -typedef enum { - GCR_IMPORTER_PROMPT_NEEDED, - GCR_IMPORTER_PROMPT_ALWAYS, - GCR_IMPORTER_PROMPT_NEVER -} GcrImporterPromptBehavior; - -GcrImporterPromptBehavior gcr_importer_get_prompt_behavior (GcrImporter *self); - -void gcr_importer_set_prompt_behavior (GcrImporter *self, - GcrImporterPromptBehavior behavior); - -G_END_DECLS - -#endif /* __GI_SCANNER__ */ -#endif /* GCR_DISABLE_DEPRECATED */ -#endif /* GCRTYPES_H_ */ diff --git a/gcr/gcr-deprecated.h b/gcr/gcr-deprecated.h deleted file mode 100644 index 3447c845..00000000 --- a/gcr/gcr-deprecated.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef GCR_DEPRECATED_H_ -#define GCR_DEPRECATED_H_ -#ifndef GCR_DISABLE_DEPRECATED -#ifndef __GI_SCANNER__ - -#include <glib.h> - -#include "gcr-certificate-basics-widget.h" -#include "gcr-certificate-details-widget.h" -#include "gcr-viewer.h" - -G_BEGIN_DECLS - -void gcr_renderer_render (GcrRenderer *self, - GcrViewer *viewer); - -G_END_DECLS - -#endif /* __GI_SCANNER__ */ -#endif /* GCR_DISABLE_DEPRECATED */ -#endif /* GCRTYPES_H_ */ diff --git a/gcr/gcr-dialog-util.c b/gcr/gcr-dialog-util.c deleted file mode 100644 index c142c351..00000000 --- a/gcr/gcr-dialog-util.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-dialog-util.h" - -#include <string.h> - -typedef struct { - GtkDialog *dialog; - gint response_id; - gboolean was_modal; - gboolean destroyed; - gulong response_sig; - gulong unmap_sig; - gulong delete_sig; - gulong destroy_sig; -} DialogRunClosure; - -static void -dialog_run_closure_free (gpointer data) -{ - DialogRunClosure *closure = data; - g_object_unref (closure->dialog); - g_assert (closure->response_sig == 0); - g_assert (closure->unmap_sig == 0); - g_assert (closure->delete_sig == 0); - g_assert (closure->destroy_sig == 0); - g_free (closure); -} - -static void -complete_async_result (GSimpleAsyncResult *res) -{ - DialogRunClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - - g_object_ref (res); - - if (!closure->destroyed) { - if (!closure->was_modal) - gtk_window_set_modal (GTK_WINDOW (closure->dialog), FALSE); - - g_signal_handler_disconnect (closure->dialog, closure->response_sig); - closure->response_sig = 0; - g_signal_handler_disconnect (closure->dialog, closure->unmap_sig); - closure->unmap_sig = 0; - g_signal_handler_disconnect (closure->dialog, closure->delete_sig); - closure->delete_sig = 0; - g_signal_handler_disconnect (closure->dialog, closure->destroy_sig); - closure->destroy_sig = 0; - } - - g_simple_async_result_complete (res); - g_object_unref (res); -} - -static void -on_dialog_unmap (GtkDialog *dialog, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - - complete_async_result (res); -} - -static void -on_dialog_response (GtkDialog *dialog, - gint response_id, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - DialogRunClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - - closure->response_id = response_id; - complete_async_result (res); -} - -static gint -on_dialog_delete (GtkDialog *dialog, - GdkEventAny *event, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - complete_async_result (res); - return TRUE; /* Do not destroy */ -} - -static void -on_dialog_destroy (GtkDialog *dialog, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - DialogRunClosure *closure = g_simple_async_result_get_op_res_gpointer (res); - - /* complete will be called by run_unmap_handler */ - closure->destroyed = TRUE; -} - -void -_gcr_dialog_util_run_async (GtkDialog *dialog, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *res; - DialogRunClosure *closure; - - g_return_if_fail (GTK_IS_DIALOG (dialog)); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - res = g_simple_async_result_new (G_OBJECT (dialog), callback, user_data, - _gcr_dialog_util_run_async); - closure = g_new0 (DialogRunClosure, 1); - - closure->dialog = g_object_ref (dialog); - closure->response_id = GTK_RESPONSE_NONE; - closure->was_modal = gtk_window_get_modal (GTK_WINDOW (dialog)); - if (!closure->was_modal) - gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); - - if (!gtk_widget_get_visible (GTK_WIDGET (dialog))) - gtk_widget_show (GTK_WIDGET (dialog)); - - g_simple_async_result_set_op_res_gpointer (res, closure, dialog_run_closure_free); - - closure->response_sig = g_signal_connect_data (dialog, "response", - G_CALLBACK (on_dialog_response), - g_object_ref (res), - (GClosureNotify)g_object_unref, 0); - - closure->unmap_sig = g_signal_connect_data (dialog, "unmap", - G_CALLBACK (on_dialog_unmap), - g_object_ref (res), - (GClosureNotify)g_object_unref, 0); - - closure->delete_sig = g_signal_connect_data (dialog, "delete-event", - G_CALLBACK (on_dialog_delete), - g_object_ref (res), - (GClosureNotify)g_object_unref, 0); - - closure->destroy_sig = g_signal_connect_data (dialog, "destroy", - G_CALLBACK (on_dialog_destroy), - g_object_ref (res), - (GClosureNotify)g_object_unref, 0); - - g_object_unref (res); -} - - -gint -_gcr_dialog_util_run_finish (GtkDialog *dialog, - GAsyncResult *result) -{ - DialogRunClosure *closure; - - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (dialog), - _gcr_dialog_util_run_async), GTK_RESPONSE_NONE); - - closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); - return closure->response_id; -} diff --git a/gcr/gcr-dialog-util.h b/gcr/gcr-dialog-util.h deleted file mode 100644 index 4be48fd6..00000000 --- a/gcr/gcr-dialog-util.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef GCR_DIALOG_UTIL_H -#define GCR_DIALOG_UTIL_H - -#include <gtk/gtk.h> -#include <gio/gio.h> - -G_BEGIN_DECLS - -void _gcr_dialog_util_run_async (GtkDialog *dialog, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gint _gcr_dialog_util_run_finish (GtkDialog *dialog, - GAsyncResult *result); - -G_END_DECLS - -#endif /* __GCR_TOKEN_MANAGER_H__ */ diff --git a/gcr/gcr-display-scrolled.c b/gcr/gcr-display-scrolled.c deleted file mode 100644 index 49d2dd98..00000000 --- a/gcr/gcr-display-scrolled.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - - -#include "config.h" - -#include "gcr-display-scrolled.h" -#include "gcr-viewer.h" - -static void _gcr_display_scrolled_viewer_iface (GcrViewerIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrDisplayScrolled, _gcr_display_scrolled, GTK_TYPE_SCROLLED_WINDOW, - G_IMPLEMENT_INTERFACE (GCR_TYPE_VIEWER, _gcr_display_scrolled_viewer_iface)); - -struct _GcrDisplayScrolledPrivate { - GcrViewer *internal; -}; - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static void -_gcr_display_scrolled_init (GcrDisplayScrolled *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_DISPLAY_SCROLLED, GcrDisplayScrolledPrivate)); - self->pv->internal = gcr_viewer_new (); -} - -static void -_gcr_display_scrolled_constructed (GObject *object) -{ - GcrDisplayScrolled *self = GCR_DISPLAY_SCROLLED (object); - - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self), GTK_SHADOW_ETCHED_IN); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); - gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->pv->internal)); - gtk_widget_show (GTK_WIDGET (self->pv->internal)); -} - -static void -_gcr_display_scrolled_get_preferred_height (GtkWidget *widget, gint *minimal_height, - gint *natural_height) -{ - GcrDisplayScrolled *self = GCR_DISPLAY_SCROLLED (widget); - gint minimal, natural; - - GTK_WIDGET_CLASS (_gcr_display_scrolled_parent_class)->get_preferred_height (widget, - minimal_height, - natural_height); - - minimal = 0; - natural = 0; - - gtk_widget_get_preferred_height (GTK_WIDGET (self->pv->internal), - &minimal, &natural); - - /* This is messy, we add a extra for the etching height */ - *minimal_height = MAX (minimal + 3, *minimal_height); - *natural_height = MAX (natural + 3, *natural_height); -} - -static void -_gcr_display_scrolled_get_preferred_width (GtkWidget *widget, gint *minimal_width, - gint *natural_width) -{ - GcrDisplayScrolled *self = GCR_DISPLAY_SCROLLED (widget); - gint minimal, natural; - - GTK_WIDGET_CLASS (_gcr_display_scrolled_parent_class)->get_preferred_width (widget, - minimal_width, - natural_width); - - minimal = 0; - natural = 0; - - gtk_widget_get_preferred_width (GTK_WIDGET (self->pv->internal), - &minimal, &natural); - - /* This is messy, we add a extra for the scrollbar width, etching */ - *minimal_width = MAX (minimal + 32, *minimal_width); - *natural_width = MAX (natural + 32, *natural_width); -} - -static void -_gcr_display_scrolled_class_init (GcrDisplayScrolledClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - widget_class->get_preferred_height = _gcr_display_scrolled_get_preferred_height; - widget_class->get_preferred_width = _gcr_display_scrolled_get_preferred_width; - - object_class->constructed = _gcr_display_scrolled_constructed; - - g_type_class_add_private (klass, sizeof (GcrDisplayScrolledPrivate)); -} - -static void -_gcr_display_scrolled_real_add_renderer (GcrViewer *viewer, GcrRenderer *renderer) -{ - GcrDisplayScrolled *self = GCR_DISPLAY_SCROLLED (viewer); - gcr_viewer_add_renderer (self->pv->internal, renderer); -} - -static void -_gcr_display_scrolled_real_insert_renderer (GcrViewer *viewer, - GcrRenderer *renderer, - GcrRenderer *before) -{ - GcrDisplayScrolled *self = GCR_DISPLAY_SCROLLED (viewer); - gcr_viewer_insert_renderer (self->pv->internal, renderer, before); -} - -static void -_gcr_display_scrolled_real_remove_renderer (GcrViewer *viewer, GcrRenderer *renderer) -{ - GcrDisplayScrolled *self = GCR_DISPLAY_SCROLLED (viewer); - gcr_viewer_remove_renderer (self->pv->internal, renderer); -} - -static guint -_gcr_display_scrolled_real_count_renderers (GcrViewer *viewer) -{ - GcrDisplayScrolled *self = GCR_DISPLAY_SCROLLED (viewer); - return gcr_viewer_count_renderers (self->pv->internal); -} - -static GcrRenderer* -_gcr_display_scrolled_real_get_renderer (GcrViewer *viewer, guint index_) -{ - GcrDisplayScrolled *self = GCR_DISPLAY_SCROLLED (viewer); - return gcr_viewer_get_renderer (self->pv->internal, index_); -} - -static void -_gcr_display_scrolled_viewer_iface (GcrViewerIface *iface) -{ - iface->add_renderer = _gcr_display_scrolled_real_add_renderer; - iface->insert_renderer = _gcr_display_scrolled_real_insert_renderer; - iface->remove_renderer = _gcr_display_scrolled_real_remove_renderer; - iface->count_renderers = _gcr_display_scrolled_real_count_renderers; - iface->get_renderer = _gcr_display_scrolled_real_get_renderer; -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -GcrDisplayScrolled* -_gcr_display_scrolled_new (void) -{ - return g_object_new (GCR_TYPE_DISPLAY_SCROLLED, NULL); -} diff --git a/gcr/gcr-display-scrolled.h b/gcr/gcr-display-scrolled.h deleted file mode 100644 index 8c4a4ae8..00000000 --- a/gcr/gcr-display-scrolled.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef __GCR_DISPLAY_SCROLLED_H__ -#define __GCR_DISPLAY_SCROLLED_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_DISPLAY_SCROLLED (_gcr_display_scrolled_get_type ()) -#define GCR_DISPLAY_SCROLLED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_DISPLAY_SCROLLED, GcrDisplayScrolled)) -#define GCR_DISPLAY_SCROLLED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_DISPLAY_SCROLLED, GcrDisplayScrolledClass)) -#define GCR_IS_DISPLAY_SCROLLED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_DISPLAY_SCROLLED)) -#define GCR_IS_DISPLAY_SCROLLED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_DISPLAY_SCROLLED)) -#define GCR_DISPLAY_SCROLLED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_DISPLAY_SCROLLED, GcrDisplayScrolledClass)) - -typedef struct _GcrDisplayScrolled GcrDisplayScrolled; -typedef struct _GcrDisplayScrolledClass GcrDisplayScrolledClass; -typedef struct _GcrDisplayScrolledPrivate GcrDisplayScrolledPrivate; - -struct _GcrDisplayScrolled { - /*< private >*/ - GtkScrolledWindow parent; - GcrDisplayScrolledPrivate *pv; -}; - -struct _GcrDisplayScrolledClass { - GtkScrolledWindowClass parent_class; -}; - -GType _gcr_display_scrolled_get_type (void); - -GcrDisplayScrolled* _gcr_display_scrolled_new (void); - -G_END_DECLS - -#endif /* __GCR_DISPLAY_SCROLLED_H__ */ diff --git a/gcr/gcr-display-view.c b/gcr/gcr-display-view.c deleted file mode 100644 index 8010a689..00000000 --- a/gcr/gcr-display-view.c +++ /dev/null @@ -1,1243 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-display-view.h" -#include "gcr-renderer.h" -#include "gcr-viewer.h" - -#include "egg/egg-oid.h" -#include "egg/egg-hex.h" - -#include <gdk/gdk.h> -#include <glib/gi18n-lib.h> - -static void _gcr_display_view_viewer_iface (GcrViewerIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrDisplayView, _gcr_display_view, GTK_TYPE_TEXT_VIEW, - G_IMPLEMENT_INTERFACE (GCR_TYPE_VIEWER, _gcr_display_view_viewer_iface)); - -#define ZWSP "\342\200\213" -#define NORMAL_MARGIN 10 -#define FIELD_MARGIN 17 -#define COLUMN_MARGIN 6 -#define ICON_MARGIN 8 -#define MESSAGE_PADDING 8 - -typedef struct _GcrDisplayItem { - GcrDisplayView *display_view; - GcrRenderer *renderer; - gboolean expanded; - gboolean details; - GtkTextMark *beginning; - GtkTextMark *ending; - GtkWidget *details_widget; - GtkTextChildAnchor *area_anchor; - GtkTextTag *extra_tag; - gint field_width; - GdkPixbuf *pixbuf; - GtkTextTag *field_tag; - GtkTextTag *details_tag; - gulong data_changed_id; -} GcrDisplayItem; - -struct _GcrDisplayViewPrivate { - GtkTextBuffer *buffer; - GPtrArray *renderers; - GHashTable *items; - GtkTextTag *title_tag; - GtkTextTag *content_tag; - GtkTextTag *heading_tag; - GtkTextTag *message_tag; - GtkTextTag *monospace_tag; - GtkTextTag *area_tag; - GcrDisplayItem *current_item; - gint text_height; - GdkCursor *cursor; - - gboolean have_measurements; - gint minimal_width; - gint natural_width; - gint minimal_height; - gint natural_height; -}; - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -static void -ensure_measurements (GcrDisplayView *self) -{ - PangoLayout *layout; - PangoRectangle extents; - gint icon_width; - gint icon_height; - GHashTableIter iter; - GcrDisplayItem *item; - gpointer value; - gboolean expanded; - - if (self->pv->have_measurements) - return; - - /* See if anything is expanded? */ - expanded = FALSE; - g_hash_table_iter_init (&iter, self->pv->items); - while (g_hash_table_iter_next (&iter, NULL, &value)) { - item = value; - if (item->expanded) { - expanded = TRUE; - break; - } - } - - /* - * We use a string in our widget font as the basis for our measurements. - * These are just estimates of what we need, and what looks goodish. - * There's room here for improvement. If this is causes problems for - * you or bothers you, scratch that itch: - */ - - layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), "0123456789"); - pango_layout_get_extents (layout, NULL, &extents); - pango_extents_to_pixels (&extents, NULL); - g_object_unref (layout); - - if (!gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &icon_width, &icon_height)) { - icon_width = 48; - icon_height = 48; - } - - if (expanded) { - /* If expanded, display more 10 lines at least */ - self->pv->minimal_height = extents.height * 14; - self->pv->natural_height = extents.height * 25; - } else { - /* If not expanded we can get by with 9 lines */ - self->pv->minimal_height = extents.height * 8; - self->pv->natural_height = extents.height * 9; - } - - self->pv->minimal_width = icon_width + (extents.width * 5); - self->pv->natural_width = icon_width + (extents.width * 8); - self->pv->have_measurements = TRUE; -} - -static void -ensure_text_height (GcrDisplayView *self) -{ - PangoRectangle extents; - PangoLayout *layout; - - if (self->pv->text_height > 0) - return; - - layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), "Wp"); - pango_layout_get_extents (layout, NULL, &extents); - pango_extents_to_pixels (&extents, NULL); - g_object_unref (layout); - - self->pv->text_height = extents.height; -} - -static void -recalculate_and_resize (GcrDisplayView *self) -{ - self->pv->have_measurements = FALSE; - gtk_widget_queue_resize (GTK_WIDGET (self)); -} - -static GtkTextTagTable* -create_tag_table (GcrDisplayView *self) -{ - GtkTextTagTable *tags; - gint width, height; - - g_assert (GCR_IS_DISPLAY_VIEW (self)); - - tags = gtk_text_tag_table_new (); - - if (!gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &width, &height)) - width = 48; - - self->pv->title_tag = g_object_new (GTK_TYPE_TEXT_TAG, - "name", "title", - "scale", PANGO_SCALE_LARGE, - "right-margin", (ICON_MARGIN * 2) + width, - "pixels-below-lines", 6, - "weight", PANGO_WEIGHT_BOLD, - NULL); - gtk_text_tag_table_add (tags, self->pv->title_tag); - - self->pv->content_tag = g_object_new (GTK_TYPE_TEXT_TAG, - "name", "content", - "right-margin", (ICON_MARGIN * 2) + width, - "left-margin", FIELD_MARGIN, - "pixels-below-lines", 3, - "wrap-mode", GTK_WRAP_WORD, - NULL); - gtk_text_tag_table_add (tags, self->pv->content_tag); - - self->pv->message_tag = g_object_new (GTK_TYPE_TEXT_TAG, - "name", "message", - "right-margin", (ICON_MARGIN * 2) + width, - "rise", 3 * PANGO_SCALE, - "pixels-below-lines", 3, - "wrap-mode", GTK_WRAP_WORD, - NULL); - gtk_text_tag_table_add (tags, self->pv->message_tag); - - self->pv->heading_tag = g_object_new (GTK_TYPE_TEXT_TAG, - "name", "heading", - "pixels-above-lines", 9, - "pixels-below-lines", 3, - "weight", PANGO_WEIGHT_BOLD, - NULL); - gtk_text_tag_table_add (tags, self->pv->heading_tag); - - self->pv->monospace_tag = g_object_new (GTK_TYPE_TEXT_TAG, - "name", "monospace", - "family", "monospace", - NULL); - gtk_text_tag_table_add (tags, self->pv->monospace_tag); - - self->pv->area_tag = g_object_new (GTK_TYPE_TEXT_TAG, - "name", "area", - "justification", GTK_JUSTIFY_CENTER, - NULL); - gtk_text_tag_table_add (tags, self->pv->area_tag); - - return tags; -} - -static void -on_expander_realize (GtkWidget *widget, gpointer user_data) -{ - GdkCursor *cursor = gdk_cursor_new (GDK_ARROW); - gdk_window_set_cursor (gtk_widget_get_window (widget), cursor); - g_object_unref (cursor); -} - -static void -on_expander_expanded (GObject *object, GParamSpec *param_spec, gpointer user_data) -{ - GtkExpander *expander = GTK_EXPANDER (object); - GcrDisplayItem *item = user_data; - item->expanded = gtk_expander_get_expanded (expander); - gcr_renderer_render_view (item->renderer, GCR_VIEWER (item->display_view)); - recalculate_and_resize (item->display_view); -} - -static void -style_display_item (GtkWidget *widget, GcrDisplayItem *item) -{ - GtkStyleContext *style; - GdkRGBA color; - - style = gtk_widget_get_style_context (GTK_WIDGET (widget)); - gtk_style_context_save (style); - - gtk_style_context_add_class (style, GTK_STYLE_CLASS_VIEW); - gtk_style_context_get_background_color (style, GTK_STATE_FLAG_NORMAL, &color); - - gtk_style_context_restore (style); - - color.red = 255; - color.green = 0; - color.blue = 0; - gtk_widget_override_background_color (item->details_widget, GTK_STATE_FLAG_NORMAL, &color); -} - -static GcrDisplayItem* -create_display_item (GcrDisplayView *self, GcrRenderer *renderer) -{ - GcrDisplayItem *item; - GtkTextTagTable *tags; - GtkTextIter iter; - GtkWidget *widget; - GtkWidget *label; - GtkWidget *alignment; - gchar *text; - - item = g_new0 (GcrDisplayItem, 1); - item->display_view = self; - item->renderer = renderer; - - tags = gtk_text_buffer_get_tag_table (self->pv->buffer); - - g_assert (!item->field_tag); - item->field_width = 0; - item->field_tag = g_object_new (GTK_TYPE_TEXT_TAG, - "left-margin", item->field_width + FIELD_MARGIN, - "indent", item->field_width, - "pixels-below-lines", 3, - "wrap-mode", GTK_WRAP_WORD_CHAR, - NULL); - gtk_text_tag_table_add (tags, item->field_tag); - - g_assert (!item->details_tag); - item->details_tag = g_object_new (GTK_TYPE_TEXT_TAG, NULL); - gtk_text_tag_table_add (tags, item->details_tag); - - /* - * Add two lines space that delimit this from later items. The - * item will live between the two zero width spaces. - */ - gtk_text_buffer_get_end_iter (self->pv->buffer, &iter); - gtk_text_buffer_insert (self->pv->buffer, &iter, "\n\n", -1); - if (!gtk_text_iter_backward_char (&iter)) - g_assert_not_reached (); - - /* The mark that determines the beginning of this item, with left gravity. */ - item->beginning = gtk_text_buffer_create_mark (self->pv->buffer, NULL, &iter, TRUE); - g_object_ref (item->beginning); - - /* The mark that determines the end of this item, with right gravity. */ - item->ending = gtk_text_buffer_create_mark (self->pv->buffer, NULL, &iter, FALSE); - g_object_ref (item->ending); - - widget = gtk_expander_new_with_mnemonic (""); - label = gtk_expander_get_label_widget (GTK_EXPANDER (widget)); - text = g_strdup_printf ("<b>%s</b>", _("_Details")); - gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), text); - g_signal_connect (widget, "notify::expanded", G_CALLBACK (on_expander_expanded), item); - g_signal_connect (widget, "realize", G_CALLBACK (on_expander_realize), NULL); - item->expanded = gtk_expander_get_expanded (GTK_EXPANDER (widget)); - g_free (text); - - alignment = gtk_alignment_new (0.5, 0.5, 0.5, 0.5); - gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 6, 9, 0, 0); - gtk_container_add (GTK_CONTAINER (alignment), widget); - gtk_widget_show_all (alignment); - - item->details_widget = gtk_event_box_new (); - gtk_event_box_set_visible_window (GTK_EVENT_BOX (item->details_widget), FALSE); - gtk_container_add (GTK_CONTAINER (item->details_widget), alignment); - g_signal_connect (item->details_widget, "realize", G_CALLBACK (on_expander_realize), NULL); - g_object_ref (item->details_widget); - - if (gtk_widget_get_realized (GTK_WIDGET (self))) - style_display_item (GTK_WIDGET (self), item); - - return item; -} - -static void -destroy_display_item (gpointer data) -{ - GcrDisplayItem *item = data; - GtkTextIter iter, end; - GtkTextTagTable *tags; - GcrDisplayView *self; - - g_assert (item); - - g_assert (GCR_IS_DISPLAY_VIEW (item->display_view)); - self = item->display_view; - - tags = gtk_text_buffer_get_tag_table (self->pv->buffer); - gtk_text_tag_table_remove (tags, item->field_tag); - gtk_text_tag_table_remove (tags, item->details_tag); - - g_object_unref (item->field_tag); - g_object_unref (item->details_tag); - - if (item->pixbuf) - g_object_unref (item->pixbuf); - item->pixbuf = NULL; - - g_assert (item->details_widget); - g_object_unref (item->details_widget); - item->details_widget = NULL; - - g_clear_object (&item->area_anchor); - - g_return_if_fail (!gtk_text_mark_get_deleted (item->beginning)); - g_return_if_fail (!gtk_text_mark_get_deleted (item->ending)); - - /* Setup iters to encompass our delemiter characters see create_display_item() */ - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->beginning); - gtk_text_iter_backward_char (&iter); - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &end, item->ending); - gtk_text_iter_forward_char (&end); - gtk_text_buffer_delete (self->pv->buffer, &iter, &end); - - gtk_text_buffer_delete_mark (self->pv->buffer, item->beginning); - gtk_text_buffer_delete_mark (self->pv->buffer, item->ending); - - g_object_unref (item->beginning); - g_object_unref (item->ending); - - g_free (item); -} - -static GcrDisplayItem* -lookup_display_item (GcrDisplayView *self, GcrRenderer *renderer) -{ - GcrDisplayItem *item = g_hash_table_lookup (self->pv->items, renderer); - g_return_val_if_fail (item, NULL); - g_assert (item->display_view == self); - return item; -} - -static GcrDisplayItem* -find_item_at_iter (GcrDisplayView *self, GtkTextIter *iter) -{ - GHashTableIter hi; - GcrDisplayItem *item; - gpointer value; - GtkTextIter start, end; - - g_hash_table_iter_init (&hi, self->pv->items); - while (g_hash_table_iter_next (&hi, NULL, &value)) { - item = value; - - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &start, item->beginning); - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &end, item->ending); - - if (gtk_text_iter_compare (iter, &start) >= 0 && - gtk_text_iter_compare (iter, &end) < 0) - return item; - } - - return NULL; -} - -static void -on_renderer_data_changed (GcrRenderer *renderer, - gpointer user_data) -{ - GcrDisplayView *self = GCR_DISPLAY_VIEW (user_data); - - /* Item may be removed, but not yet destroyed */ - if (!g_hash_table_lookup (self->pv->items, renderer)) - return; - - /* Just ask the renderer to render itself on us */ - gcr_renderer_render_view (renderer, GCR_VIEWER (self)); -} - -static void -paint_item_icon (GcrDisplayView *self, - GcrDisplayItem *item, - GdkRectangle *visible, - cairo_t *cr) -{ - GtkTextIter iter; - GdkRectangle location; - GtkTextView *view; - - if (item->pixbuf == NULL) - return; - - view = GTK_TEXT_VIEW (self); - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->beginning); - gtk_text_view_get_iter_location (view, &iter, &location); - - location.height = gdk_pixbuf_get_height (item->pixbuf); - location.width = gdk_pixbuf_get_width (item->pixbuf); - location.x = visible->width - location.width - ICON_MARGIN; - - if (!gdk_rectangle_intersect (visible, &location, NULL)) - return; - - gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_TEXT, - location.x, location.y, - &location.x, &location.y); - - cairo_save (cr); - gdk_cairo_set_source_pixbuf (cr, item->pixbuf, location.x, location.y); - cairo_rectangle (cr, location.x, location.y, location.width, location.height); - cairo_fill (cr); - cairo_restore (cr); -} - -static void -paint_item_border (GcrDisplayView *self, - GcrDisplayItem *item, - GtkStyleContext *context, - GdkRectangle *visible, - gint index, - cairo_t *cr) -{ - GdkRGBA color; - GtkTextView *view; - GtkTextIter iter, end; - GdkRectangle location; - - if (index == 0) - return; - - view = GTK_TEXT_VIEW (self); - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->beginning); - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &end, item->ending); - - /* Don't paint for non-visible items */ - if (gtk_text_iter_compare (&iter, &end) == 0) - return; - - ensure_text_height (self); - - gtk_style_context_get_background_color (context, - GTK_STATE_FLAG_SELECTED | GTK_STATE_FLAG_FOCUSED, - &color); - - gtk_text_view_get_iter_location (view, &iter, &location); - - location.height = 2; - location.width = visible->width - (NORMAL_MARGIN * 2); - location.x = NORMAL_MARGIN; - location.y -= self->pv->text_height / 2; - - if (!gdk_rectangle_intersect (visible, &location, NULL)) - return; - - gtk_text_view_buffer_to_window_coords (view, GTK_TEXT_WINDOW_TEXT, - location.x, location.y, - &location.x, &location.y); - - cairo_save (cr); - cairo_set_source_rgb (cr, color.red, color.green, color.blue); - cairo_set_line_width (cr, 0.5); - cairo_move_to (cr, location.x, location.y); - cairo_line_to (cr, location.x + location.width, location.y); - cairo_stroke (cr); - cairo_restore (cr); -} - -static void -paint_extras (GcrDisplayView *self, cairo_t *cr) -{ - GdkRectangle visible; - GcrDisplayItem *item; - GtkStyleContext *context; - guint i; - - gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (self), &visible); - context = gtk_widget_get_style_context (GTK_WIDGET (self)); - - for (i = 0; i < self->pv->renderers->len; i++) { - item = g_hash_table_lookup (self->pv->items, self->pv->renderers->pdata[i]); - g_assert (item != NULL); - paint_item_icon (self, item, &visible, cr); - paint_item_border (self, item, context, &visible, i, cr); - } -} - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static GObject* -_gcr_display_view_constructor (GType type, guint n_props, GObjectConstructParam *props) -{ - GObject *obj = G_OBJECT_CLASS (_gcr_display_view_parent_class)->constructor (type, n_props, props); - GcrDisplayView *self = NULL; - GtkTextView *view = NULL; - GtkTextTagTable *tags; - - g_return_val_if_fail (obj, NULL); - - self = GCR_DISPLAY_VIEW (obj); - view = GTK_TEXT_VIEW (obj); - - tags = create_tag_table (self); - self->pv->buffer = gtk_text_buffer_new (tags); - g_object_unref (tags); - - gtk_text_view_set_buffer (view, self->pv->buffer); - gtk_text_view_set_editable (view, FALSE); - gtk_text_view_set_left_margin (view, NORMAL_MARGIN); - gtk_text_view_set_right_margin (view, NORMAL_MARGIN); - gtk_text_view_set_cursor_visible (view, FALSE); - - return obj; -} - -static void -_gcr_display_view_init (GcrDisplayView *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_DISPLAY_VIEW, GcrDisplayViewPrivate)); - self->pv->items = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, destroy_display_item); - self->pv->renderers = g_ptr_array_new_with_free_func (g_object_unref); -} - -static void -_gcr_display_view_dispose (GObject *obj) -{ - GcrDisplayView *self = GCR_DISPLAY_VIEW (obj); - GcrRenderer *renderer; - GcrDisplayItem *item; - - while (self->pv->renderers->len) { - renderer = g_ptr_array_index (self->pv->renderers, 0); - item = g_hash_table_lookup (self->pv->items, renderer); - g_return_if_fail (item); - g_signal_handler_disconnect (renderer, item->data_changed_id); - if (!g_hash_table_remove (self->pv->items, renderer)) - g_return_if_reached (); - g_ptr_array_remove_index_fast (self->pv->renderers, 0); - } - - if (self->pv->buffer) - g_object_unref (self->pv->buffer); - self->pv->buffer = NULL; - - g_assert (g_hash_table_size (self->pv->items) == 0); - - G_OBJECT_CLASS (_gcr_display_view_parent_class)->dispose (obj); -} - -static void -_gcr_display_view_finalize (GObject *obj) -{ - GcrDisplayView *self = GCR_DISPLAY_VIEW (obj); - - if (self->pv->buffer) - g_object_unref (self->pv->buffer); - self->pv->buffer = NULL; - - g_assert (g_hash_table_size (self->pv->items) == 0); - g_hash_table_destroy (self->pv->items); - self->pv->items = NULL; - - g_assert (self->pv->renderers); - g_assert (self->pv->renderers->len == 0); - g_ptr_array_free (self->pv->renderers, TRUE); - self->pv->renderers = NULL; - - g_assert (self->pv->content_tag); - g_object_unref (self->pv->content_tag); - self->pv->content_tag = NULL; - - g_assert (self->pv->heading_tag); - g_object_unref (self->pv->heading_tag); - self->pv->heading_tag = NULL; - - g_assert (self->pv->monospace_tag); - g_object_unref (self->pv->monospace_tag); - self->pv->monospace_tag = NULL; - - g_assert (self->pv->title_tag); - g_object_unref (self->pv->title_tag); - self->pv->title_tag = NULL; - - g_clear_object (&self->pv->cursor); - - G_OBJECT_CLASS (_gcr_display_view_parent_class)->finalize (obj); -} - -static void -_gcr_display_view_realize (GtkWidget *widget) -{ - GcrDisplayView *self = GCR_DISPLAY_VIEW (widget); - GHashTableIter iter; - GdkDisplay *display; - gpointer value; - - if (GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->realize) - GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->realize (widget); - - /* Set style on all the items */ - g_hash_table_iter_init (&iter, self->pv->items); - while (g_hash_table_iter_next (&iter, NULL, &value)) - style_display_item (widget, value); - - if (!self->pv->cursor) { - display = gtk_widget_get_display (GTK_WIDGET (self)); - self->pv->cursor = gdk_cursor_new_for_display (display, GDK_ARROW); - } - - gdk_window_set_cursor (gtk_text_view_get_window (GTK_TEXT_VIEW (self), GTK_TEXT_WINDOW_WIDGET), - self->pv->cursor); -} - -static gboolean -_gcr_display_view_button_press_event (GtkWidget *widget, GdkEventButton *event) -{ - GtkTextView *text_view = GTK_TEXT_VIEW (widget); - GcrDisplayView *self = GCR_DISPLAY_VIEW (widget); - GcrDisplayItem *item; - gboolean handled = FALSE; - GtkTextIter iter; - gint x, y; - - if (GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->button_press_event) - handled = GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->button_press_event ( - widget, event); - - if (event->window == gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT)) { - gtk_text_view_window_to_buffer_coords (text_view, GTK_TEXT_WINDOW_TEXT, - event->x, event->y, &x, &y); - gtk_text_view_get_iter_at_location (text_view, &iter, x, y); - - item = find_item_at_iter (self, &iter); - self->pv->current_item = item; - } - - return handled; -} - -static gboolean -_gcr_display_view_draw (GtkWidget *widget, cairo_t *cr) -{ - GdkWindow *window; - gboolean handled = TRUE; - - /* Have GtkTextView draw the text first. */ - if (GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->draw) - handled = GTK_WIDGET_CLASS (_gcr_display_view_parent_class)->draw (widget, cr); - - window = gtk_text_view_get_window (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_TEXT); - if (gtk_cairo_should_draw_window (cr, window)) - paint_extras (GCR_DISPLAY_VIEW (widget), cr); - - return handled; -} - -static void -_gcr_display_get_preferred_height (GtkWidget *widget, gint *minimal_height, - gint *natural_height) -{ - GcrDisplayView *self = GCR_DISPLAY_VIEW (widget); - ensure_measurements (self); - *minimal_height = self->pv->minimal_height; - *natural_height = self->pv->natural_height; -} - -static void -_gcr_display_get_preferred_width (GtkWidget *widget, gint *minimal_width, - gint *natural_width) -{ - GcrDisplayView *self = GCR_DISPLAY_VIEW (widget); - ensure_measurements (self); - *minimal_width = self->pv->minimal_width; - *natural_width = self->pv->natural_width; -} - -static void -_gcr_display_view_populate_popup (GtkTextView *text_view, GtkMenu *menu) -{ - GcrDisplayView *self = GCR_DISPLAY_VIEW (text_view); - - if (GTK_TEXT_VIEW_CLASS (_gcr_display_view_parent_class)->populate_popup) - GTK_TEXT_VIEW_CLASS (_gcr_display_view_parent_class)->populate_popup (text_view, menu); - - /* Ask the current renderer to add menu items */ - if (self->pv->current_item) - gcr_renderer_popuplate_popup (self->pv->current_item->renderer, - GCR_VIEWER (self), menu); -} - -static void -_gcr_display_view_class_init (GcrDisplayViewClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - GtkTextViewClass *text_view_class = GTK_TEXT_VIEW_CLASS (klass); - - _gcr_display_view_parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private (klass, sizeof (GcrDisplayViewPrivate)); - - gobject_class->constructor = _gcr_display_view_constructor; - gobject_class->dispose = _gcr_display_view_dispose; - gobject_class->finalize = _gcr_display_view_finalize; - - widget_class->realize = _gcr_display_view_realize; - widget_class->button_press_event = _gcr_display_view_button_press_event; - widget_class->get_preferred_height = _gcr_display_get_preferred_height; - widget_class->get_preferred_width = _gcr_display_get_preferred_width; - widget_class->draw = _gcr_display_view_draw; - - text_view_class->populate_popup = _gcr_display_view_populate_popup; -} - -static void -_gcr_display_view_real_insert_renderer (GcrViewer *viewer, - GcrRenderer *renderer, - GcrRenderer *before) -{ - GcrDisplayView *self = GCR_DISPLAY_VIEW (viewer); - GcrDisplayItem *item; - guint i; - - if (before != NULL) - g_return_if_fail (g_hash_table_lookup (self->pv->items, before) != NULL); - - item = create_display_item (self, renderer); - g_object_ref (renderer); - - /* Insert it at the right place */ - if (before != NULL) { - g_ptr_array_add (self->pv->renderers, NULL); - for (i = self->pv->renderers->len; i > 0; i--) { - self->pv->renderers->pdata[i] = self->pv->renderers->pdata[i - 1]; - if (self->pv->renderers->pdata[i] == before) { - self->pv->renderers->pdata[i - 1] = renderer; - break; - } - } - - /* Must have been found */ - g_assert (i > 0); - - /* No before, just add to end */ - } else { - g_ptr_array_add (self->pv->renderers, renderer); - } - - g_hash_table_insert (self->pv->items, renderer, item); - - gcr_renderer_render_view (renderer, viewer); - item->data_changed_id = g_signal_connect (renderer, "data-changed", - G_CALLBACK (on_renderer_data_changed), self); -} - -static void -_gcr_display_view_real_add_renderer (GcrViewer *viewer, GcrRenderer *renderer) -{ - _gcr_display_view_real_insert_renderer (viewer, renderer, NULL); -} - -static void -_gcr_display_view_real_remove_renderer (GcrViewer *viewer, GcrRenderer *renderer) -{ - GcrDisplayView *self = GCR_DISPLAY_VIEW (viewer); - GcrDisplayItem *item; - - item = lookup_display_item (self, renderer); - g_return_if_fail (item); - - /* Unhook the callback */ - g_signal_handler_disconnect (renderer, item->data_changed_id); - - /* Destroys the display item */ - g_assert (item->display_view == self); - g_hash_table_remove (self->pv->items, renderer); - - /* Unrefs the renderer */ - if (!g_ptr_array_remove (self->pv->renderers, renderer)) - g_return_if_reached (); -} - -static guint -_gcr_display_view_real_count_renderers (GcrViewer *viewer) -{ - GcrDisplayView *self = GCR_DISPLAY_VIEW (viewer); - return self->pv->renderers->len; -} - -static GcrRenderer* -_gcr_display_view_real_get_renderer (GcrViewer *viewer, guint index_) -{ - GcrDisplayView *self = GCR_DISPLAY_VIEW (viewer); - g_return_val_if_fail (index_ < self->pv->renderers->len, NULL); - return g_ptr_array_index (self->pv->renderers, index_); -} - -static void -_gcr_display_view_viewer_iface (GcrViewerIface *iface) -{ - iface->add_renderer = (gpointer)_gcr_display_view_real_add_renderer; - iface->insert_renderer = (gpointer)_gcr_display_view_real_insert_renderer; - iface->remove_renderer = (gpointer)_gcr_display_view_real_remove_renderer; - iface->count_renderers = (gpointer)_gcr_display_view_real_count_renderers; - iface->get_renderer = (gpointer)_gcr_display_view_real_get_renderer; -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -GcrDisplayView* -_gcr_display_view_new (void) -{ - return g_object_new (GCR_TYPE_DISPLAY_VIEW, NULL); -} - -void -_gcr_display_view_begin (GcrDisplayView *self, - GcrRenderer *renderer) -{ - GtkTextIter start, iter; - GcrDisplayItem *item; - GList *widgets, *l; - - g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); - item = lookup_display_item (self, renderer); - g_return_if_fail (item); - - /* Remove the details widget so it doesn't get destroyed */ - if (gtk_widget_get_parent (item->details_widget)) - gtk_container_remove (GTK_CONTAINER (self), item->details_widget); - - /* Remove area widgets so they don't get destroyed unnecessarily */ - if (item->area_anchor) { - g_assert (!gtk_text_child_anchor_get_deleted (item->area_anchor)); - widgets = gtk_text_child_anchor_get_widgets (item->area_anchor); - for (l = widgets; l != NULL; l = g_list_next (l)) - gtk_container_remove (GTK_CONTAINER (self), l->data); - g_list_free (widgets); - g_object_unref (item->area_anchor); - item->area_anchor = NULL; - } - - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &start, item->beginning); - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending); - gtk_text_buffer_delete (self->pv->buffer, &start, &iter); - - item->extra_tag = NULL; - item->field_width = 0; - item->details = FALSE; -} - -void -_gcr_display_view_end (GcrDisplayView *self, - GcrRenderer *renderer) -{ - GcrDisplayItem *item; - - g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); - item = lookup_display_item (self, renderer); - g_return_if_fail (item); -} - -void -_gcr_display_view_start_details (GcrDisplayView *self, GcrRenderer *renderer) -{ - GtkTextChildAnchor *anchor; - GcrDisplayItem *item; - GtkTextIter iter; - - g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); - item = lookup_display_item (self, renderer); - g_return_if_fail (item); - - if (item->details) { - g_warning ("A GcrRenderer implementation has called %s twice in one render", - G_STRFUNC); - return; - } - - item->extra_tag = item->details_tag; - item->details = TRUE; - - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending); - anchor = gtk_text_buffer_create_child_anchor (self->pv->buffer, &iter); - gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (self), item->details_widget, anchor); - gtk_widget_show_all (item->details_widget); - gtk_text_buffer_insert (self->pv->buffer, &iter, "\n", 1); -} - -void -_gcr_display_view_append_content (GcrDisplayView *self, GcrRenderer *renderer, - const gchar *content, const gchar *details) -{ - GcrDisplayItem *item; - GtkTextIter iter; - gchar *memory = NULL; - - g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); - g_return_if_fail (content); - - item = lookup_display_item (self, renderer); - g_return_if_fail (item); - - if (item->details && !item->expanded) - return; - - if (details) - content = memory = g_strdup_printf ("%s: %s", content, details); - - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, content, -1, - self->pv->content_tag, item->extra_tag, NULL); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\n", 1, - item->extra_tag, NULL); - - g_free (memory); -} - -void -_gcr_display_view_append_value (GcrDisplayView *self, GcrRenderer *renderer, const gchar *field, - const gchar *value, gboolean monospace) -{ - GcrDisplayItem *item; - PangoRectangle extents; - PangoTabArray *tabs; - PangoLayout *layout; - GtkTextIter iter; - gchar *text; - - g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); - g_return_if_fail (field); - - item = lookup_display_item (self, renderer); - g_return_if_fail (item); - - if (item->details && !item->expanded) - return; - - text = g_strdup_printf ("%s:", field); - if (value == NULL) - value = ""; - - /* Measure the width of the field */ - layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), text); - pango_layout_get_extents (layout, NULL, &extents); - pango_extents_to_pixels (&extents, NULL); - g_object_unref (layout); - - /* An estimate of the text height */ - self->pv->text_height = extents.height; - - /* Make the tab wide enough to accomodate */ - if (extents.width > item->field_width) { - item->field_width = extents.width + COLUMN_MARGIN; - tabs = pango_tab_array_new (1, TRUE); - pango_tab_array_set_tab (tabs, 0, PANGO_TAB_LEFT, item->field_width); - g_object_set (item->field_tag, - "left-margin", FIELD_MARGIN, - "indent", 0 - item->field_width, - "tabs", tabs, - NULL); - pango_tab_array_free (tabs); - } - - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, text, -1, - item->field_tag, item->extra_tag, NULL); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\t", 1, - item->extra_tag, NULL); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, value, -1, item->field_tag, - monospace ? self->pv->monospace_tag : item->extra_tag, - monospace ? item->extra_tag : NULL, NULL); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\n", 1, - item->extra_tag, NULL); - - g_free (text); -} - -void -_gcr_display_view_append_hex (GcrDisplayView *self, GcrRenderer *renderer, - const gchar *field, gconstpointer value, gsize n_value) -{ - gchar *display; - - display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1); - _gcr_display_view_append_value (self, renderer, field, display, TRUE); - g_free (display); -} - -void -_gcr_display_view_append_title (GcrDisplayView *self, GcrRenderer *renderer, const gchar *title) -{ - GcrDisplayItem *item; - GtkTextIter iter; - - g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); - g_return_if_fail (title); - - item = lookup_display_item (self, renderer); - g_return_if_fail (item); - - if (item->details && !item->expanded) - return; - - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, title, -1, - self->pv->title_tag, item->extra_tag, NULL); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\n", 1, - item->extra_tag, NULL); -} - -void -_gcr_display_view_append_heading (GcrDisplayView *self, GcrRenderer *renderer, const gchar *heading) -{ - GcrDisplayItem *item; - GtkTextIter iter; - - g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); - g_return_if_fail (heading); - - item = lookup_display_item (self, renderer); - g_return_if_fail (item); - - if (item->details && !item->expanded) - return; - - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, heading, -1, - self->pv->heading_tag, item->extra_tag, NULL); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\n", 1, - item->extra_tag, NULL); -} - -void -_gcr_display_view_append_fingerprint (GcrDisplayView *self, GcrRenderer *renderer, const guchar *data, - gsize n_data, const gchar *name, GChecksumType type) -{ - GChecksum *checksum; - guint8 *buffer; - gsize n_buffer; - - g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); - - checksum = g_checksum_new (type); - g_return_if_fail (checksum); - g_checksum_update (checksum, data, n_data); - - n_buffer = g_checksum_type_get_length (type); - g_return_if_fail (n_buffer); - buffer = g_malloc0 (n_buffer); - - g_checksum_get_digest (checksum, buffer, &n_buffer); - g_checksum_free (checksum); - - _gcr_display_view_append_hex (self, renderer, name, buffer, n_buffer); - - g_free (buffer); -} - -void -_gcr_display_view_append_message (GcrDisplayView *self, - GcrRenderer *renderer, - GtkMessageType message_type, - const gchar *message) -{ - const gchar *stock_id = NULL; - GtkWidget *image = NULL; - GcrDisplayItem *item; - GtkTextChildAnchor *anchor; - GtkTextIter iter; - - g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); - g_return_if_fail (GCR_IS_RENDERER (renderer)); - - item = lookup_display_item (self, renderer); - g_return_if_fail (item); - - switch (message_type) { - case GTK_MESSAGE_INFO: - stock_id = GTK_STOCK_DIALOG_INFO; - break; - - case GTK_MESSAGE_QUESTION: - stock_id = GTK_STOCK_DIALOG_QUESTION; - break; - - case GTK_MESSAGE_WARNING: - stock_id = GTK_STOCK_DIALOG_WARNING; - break; - - case GTK_MESSAGE_ERROR: - stock_id = GTK_STOCK_DIALOG_ERROR; - break; - - case GTK_MESSAGE_OTHER: - break; - - default: - g_warning ("unknown GtkMessageType: %u", message_type); - break; - } - - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending); - - if (stock_id != NULL) { - image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU); - gtk_misc_set_padding (GTK_MISC (image), MESSAGE_PADDING, 0); - gtk_widget_show (image); - - anchor = gtk_text_buffer_create_child_anchor (self->pv->buffer, &iter); - gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (self), image, anchor); - } - - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, message, -1, - self->pv->message_tag, item->extra_tag, NULL); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\n", 1, - item->extra_tag, NULL); -} - -void -_gcr_display_view_set_icon (GcrDisplayView *self, GcrRenderer *renderer, GIcon *icon) -{ - GcrDisplayItem *item; - GdkScreen *screen; - GtkIconTheme *icon_theme; - GtkSettings *settings; - gint width, height; - GtkIconInfo *info; - - g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); - item = lookup_display_item (self, renderer); - g_return_if_fail (item); - - if (item->pixbuf) - g_object_unref (item->pixbuf); - item->pixbuf = NULL; - - if (!icon) - return; - - screen = gtk_widget_get_screen (GTK_WIDGET (self)); - icon_theme = gtk_icon_theme_get_for_screen (screen); - settings = gtk_settings_get_for_screen (screen); - - if (!gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_DIALOG, &width, &height)) - g_return_if_reached (); - - info = gtk_icon_theme_lookup_by_gicon (icon_theme, icon, MIN (width, height), - GTK_ICON_LOOKUP_USE_BUILTIN); - - if (info) { - GtkStyleContext *style = gtk_widget_get_style_context (GTK_WIDGET (self)); - item->pixbuf = gtk_icon_info_load_symbolic_for_context (info, style, FALSE, NULL); - gtk_icon_info_free (info); - } -} - -void -_gcr_display_view_add_widget_area (GcrDisplayView *self, - GcrRenderer *renderer, - GtkWidget *area) -{ - GtkTextIter iter, start; - GcrDisplayItem *item; - - g_return_if_fail (GCR_IS_DISPLAY_VIEW (self)); - g_return_if_fail (GTK_IS_WIDGET (area)); - - item = lookup_display_item (self, renderer); - g_return_if_fail (item != NULL); - g_return_if_fail (item->area_anchor == NULL); - - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &start, item->ending); - iter = start; - - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, "\n" ZWSP, -1, self->pv->area_tag, NULL); - gtk_text_buffer_get_iter_at_mark (self->pv->buffer, &iter, item->ending); - - item->area_anchor = gtk_text_buffer_create_child_anchor (self->pv->buffer, &iter); - g_object_ref (item->area_anchor); - gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (self), area, item->area_anchor); - gtk_text_buffer_insert_with_tags (self->pv->buffer, &iter, ZWSP "\n", -1, self->pv->area_tag, NULL); -} diff --git a/gcr/gcr-display-view.h b/gcr/gcr-display-view.h deleted file mode 100644 index 0882624f..00000000 --- a/gcr/gcr-display-view.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_DISPLAY_VIEW_H__ -#define __GCR_DISPLAY_VIEW_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-certificate.h" -#include "gcr-types.h" -#include "gcr-viewer.h" - -G_BEGIN_DECLS - -#define GCR_DISPLAY_VIEW_LINE_BREAK 0x2028 - -#define GCR_TYPE_DISPLAY_VIEW (_gcr_display_view_get_type ()) -#define GCR_DISPLAY_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_DISPLAY_VIEW, GcrDisplayView)) -#define GCR_DISPLAY_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_DISPLAY_VIEW, GcrDisplayViewClass)) -#define GCR_IS_DISPLAY_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_DISPLAY_VIEW)) -#define GCR_IS_DISPLAY_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_DISPLAY_VIEW)) -#define GCR_DISPLAY_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_DISPLAY_VIEW, GcrDisplayViewClass)) - -typedef struct _GcrDisplayView GcrDisplayView; -typedef struct _GcrDisplayViewClass GcrDisplayViewClass; -typedef struct _GcrDisplayViewPrivate GcrDisplayViewPrivate; - -struct _GcrDisplayView { - /*< private >*/ - GtkTextView parent; - GcrDisplayViewPrivate *pv; -}; - -struct _GcrDisplayViewClass { - GtkTextViewClass parent_class; -}; - -GType _gcr_display_view_get_type (void); - -GcrDisplayView* _gcr_display_view_new (void); - -void _gcr_display_view_begin (GcrDisplayView *self, - GcrRenderer *renderer); - -void _gcr_display_view_end (GcrDisplayView *self, - GcrRenderer *renderer); - -void _gcr_display_view_append_value (GcrDisplayView *self, - GcrRenderer *renderer, - const gchar *field, - const gchar *value, - gboolean monospace); - -void _gcr_display_view_append_hex (GcrDisplayView *self, - GcrRenderer *renderer, - const gchar *field, - gconstpointer value, - gsize n_value); - -void _gcr_display_view_append_title (GcrDisplayView *self, - GcrRenderer *renderer, - const gchar *title); - -void _gcr_display_view_append_content (GcrDisplayView *self, - GcrRenderer *renderer, - const gchar *content, - const gchar *details); - -void _gcr_display_view_start_details (GcrDisplayView *self, - GcrRenderer *renderer); - -void _gcr_display_view_append_heading (GcrDisplayView *self, - GcrRenderer *renderer, - const gchar *heading); - -void _gcr_display_view_append_fingerprint (GcrDisplayView *self, - GcrRenderer *renderer, - const guchar *data, - gsize n_data, - const gchar *name, - GChecksumType type); - -void _gcr_display_view_append_message (GcrDisplayView *self, - GcrRenderer *renderer, - GtkMessageType message_type, - const gchar *message); - -void _gcr_display_view_set_icon (GcrDisplayView *self, - GcrRenderer *renderer, - GIcon *icon); - -void _gcr_display_view_add_widget_area (GcrDisplayView *self, - GcrRenderer *render, - GtkWidget *area); - -G_END_DECLS - -#endif /* __GCR_DISPLAY_VIEW_H__ */ diff --git a/gcr/gcr-enum-types.c.template b/gcr/gcr-enum-types.c.template deleted file mode 100644 index d6095351..00000000 --- a/gcr/gcr-enum-types.c.template +++ /dev/null @@ -1,43 +0,0 @@ -/*** BEGIN file-header ***/ - -#include <glib-object.h> - -#ifndef GCR_COMPILATION -#define GCR_COMPILATION -#endif - -/*** END file-header ***/ - -/*** BEGIN file-production ***/ -#include "@filename@" -/* enumerations from "@filename@" */ -/*** END file-production ***/ - -/*** BEGIN value-header ***/ -GType @enum_name@_get_type (void) G_GNUC_CONST; - -GType -@enum_name@_get_type (void) -{ - static GType etype = 0; - if (G_UNLIKELY(etype == 0)) { - static const G@Type@Value values[] = { -/*** END value-header ***/ - -/*** BEGIN value-production ***/ - { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, -/*** END value-production ***/ - -/*** BEGIN value-tail ***/ - { 0, NULL, NULL } - }; - etype = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); - } - return etype; -} - -/*** END value-tail ***/ - -/*** BEGIN file-tail ***/ - /**/ -/*** END file-tail ***/ diff --git a/gcr/gcr-enum-types.h.template b/gcr/gcr-enum-types.h.template deleted file mode 100644 index 91d5a606..00000000 --- a/gcr/gcr-enum-types.h.template +++ /dev/null @@ -1,28 +0,0 @@ -/*** BEGIN file-header ***/ -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> can be included directly." -#endif - -#ifndef __GCR_ENUM_TYPES_H__ -#define __GCR_ENUM_TYPES_H__ - -#include <glib-object.h> - -G_BEGIN_DECLS -/*** END file-header ***/ - -/*** BEGIN file-production ***/ - -/* enumerations from "@filename@" */ -/*** END file-production ***/ - -/*** BEGIN value-header ***/ -GType @enum_name@_get_type (void) G_GNUC_CONST; -#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) -/*** END value-header ***/ - -/*** BEGIN file-tail ***/ -G_END_DECLS - -#endif /* __GCR_ENUM_TYPES_H__ */ -/*** END file-tail ***/ diff --git a/gcr/gcr-failure-renderer.c b/gcr/gcr-failure-renderer.c deleted file mode 100644 index 4cf84bd7..00000000 --- a/gcr/gcr-failure-renderer.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-display-view.h" -#include "gcr-icons.h" -#include "gcr-parser.h" -#include "gcr-failure-renderer.h" - -#include "egg/egg-entry-buffer.h" - -#include <gdk/gdk.h> -#include <glib/gi18n-lib.h> - -enum { - PROP_0, - PROP_LABEL, - PROP_ATTRIBUTES -}; - -struct _GcrFailureRendererPrivate { - gchar *label; - GError *error; -}; - -static void gcr_renderer_iface_init (GcrRendererIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrFailureRenderer, gcr_failure_renderer, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_renderer_iface_init); -); - -static void -gcr_failure_renderer_init (GcrFailureRenderer *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_FAILURE_RENDERER, - GcrFailureRendererPrivate)); -} - -static void -gcr_failure_renderer_finalize (GObject *obj) -{ - GcrFailureRenderer *self = GCR_FAILURE_RENDERER (obj); - - g_error_free (self->pv->error); - g_free (self->pv->label); - - G_OBJECT_CLASS (gcr_failure_renderer_parent_class)->finalize (obj); -} - -static void -gcr_failure_renderer_set_property (GObject *obj, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GcrFailureRenderer *self = GCR_FAILURE_RENDERER (obj); - - switch (prop_id) { - case PROP_LABEL: - g_free (self->pv->label); - self->pv->label = g_value_dup_string (value); - g_object_notify (obj, "label"); - gcr_renderer_emit_data_changed (GCR_RENDERER (self)); - break; - case PROP_ATTRIBUTES: - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_failure_renderer_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GcrFailureRenderer *self = GCR_FAILURE_RENDERER (obj); - - switch (prop_id) { - case PROP_LABEL: - g_value_take_string (value, self->pv->label); - break; - case PROP_ATTRIBUTES: - g_value_set_boxed (value, NULL); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_failure_renderer_class_init (GcrFailureRendererClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (GcrFailureRendererPrivate)); - - gobject_class->finalize = gcr_failure_renderer_finalize; - gobject_class->set_property = gcr_failure_renderer_set_property; - gobject_class->get_property = gcr_failure_renderer_get_property; - - g_object_class_install_property (gobject_class, PROP_LABEL, - g_param_spec_string ("label", "Label", "Failure Label", - "", G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, - g_param_spec_boxed ("attributes", "Attributes", "Renderer attributes", - GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE)); -} - -static void -gcr_failure_renderer_render (GcrRenderer *renderer, - GcrViewer *viewer) -{ - GcrFailureRenderer *self = GCR_FAILURE_RENDERER (renderer); - GcrDisplayView *view; - gchar *display; - GIcon *icon; - - if (GCR_IS_DISPLAY_VIEW (viewer)) { - view = GCR_DISPLAY_VIEW (viewer); - - } else { - g_warning ("GcrFailureRenderer only works with internal specific " - "GcrViewer returned by gcr_viewer_new()."); - return; - } - - _gcr_display_view_begin (view, renderer); - - if (g_error_matches (self->pv->error, GCR_DATA_ERROR, GCR_ERROR_UNRECOGNIZED)) - icon = g_themed_icon_new ("dialog-warning"); - else - icon = g_themed_icon_new ("dialog-error"); - _gcr_display_view_set_icon (view, renderer, icon); - g_object_unref (icon); - - _gcr_display_view_append_title (view, renderer, self->pv->label); - - if (self->pv->label) - display = g_strdup_printf (_("Could not display '%s'"), self->pv->label); - else - display = g_strdup (_("Could not display file")); - _gcr_display_view_append_content (view, renderer, display, NULL); - g_free (display); - - if (self->pv->error->message) - _gcr_display_view_append_value (view, renderer, _("Reason"), - self->pv->error->message, FALSE); - - _gcr_display_view_end (view, renderer); -} - -static void -gcr_renderer_iface_init (GcrRendererIface *iface) -{ - iface->render_view = gcr_failure_renderer_render; -} - -/** - * gcr_failure_renderer_new: - * @label: (allow-none): the label for the failure - * @error: the error to display - * - * Create a new renderer for an error. - * - * Returns: (transfer full) (type Gcr.FailureRenderer): the new renderer - */ -GcrRenderer * -gcr_failure_renderer_new (const gchar *label, - GError *error) -{ - GcrFailureRenderer *renderer; - - renderer = g_object_new (GCR_TYPE_FAILURE_RENDERER, - "label", label, - NULL); - - renderer->pv->error = g_error_copy (error); - return GCR_RENDERER (renderer); -} - -/** - * gcr_failure_renderer_new_unsupported: - * @label: the label for the failure - * - * Create a new renderer for unsupported data. - * - * Returns: (transfer full): the new renderer - */ -GcrRenderer * -gcr_failure_renderer_new_unsupported (const gchar *label) -{ - GcrRenderer *renderer; - GError *error; - - error = g_error_new (GCR_DATA_ERROR, GCR_ERROR_UNRECOGNIZED, - _("Cannot display a file of this type.")); - - renderer = gcr_failure_renderer_new (label, error); - - g_error_free (error); - return renderer; -} diff --git a/gcr/gcr-failure-renderer.h b/gcr/gcr-failure-renderer.h deleted file mode 100644 index 9b70f36f..00000000 --- a/gcr/gcr-failure-renderer.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_FAILURE_RENDERER_H__ -#define __GCR_FAILURE_RENDERER_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-renderer.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_FAILURE_RENDERER (gcr_failure_renderer_get_type ()) -#define GCR_FAILURE_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_FAILURE_RENDERER, GcrFailureRenderer)) -#define GCR_FAILURE_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_FAILURE_RENDERER, GcrFailureRendererClass)) -#define GCR_IS_FAILURE_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_FAILURE_RENDERER)) -#define GCR_IS_FAILURE_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_FAILURE_RENDERER)) -#define GCR_FAILURE_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_FAILURE_RENDERER, GcrFailureRendererClass)) - -typedef struct _GcrFailureRenderer GcrFailureRenderer; -typedef struct _GcrFailureRendererClass GcrFailureRendererClass; -typedef struct _GcrFailureRendererPrivate GcrFailureRendererPrivate; - -struct _GcrFailureRenderer { - /*< private >*/ - GObject parent; - GcrFailureRendererPrivate *pv; -}; - -struct _GcrFailureRendererClass { - /*< private >*/ - GObjectClass parent_class; -}; - -GType gcr_failure_renderer_get_type (void); - -GcrRenderer * gcr_failure_renderer_new (const gchar *label, - GError *error); - -GcrRenderer * gcr_failure_renderer_new_unsupported (const gchar *label); - -G_END_DECLS - -#endif /* __GCR_FAILURE_RENDERER_H__ */ diff --git a/gcr/gcr-fingerprint.c b/gcr/gcr-fingerprint.c deleted file mode 100644 index 39d93195..00000000 --- a/gcr/gcr-fingerprint.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General License for more details. - * - * You should have received a copy of the GNU Lesser General - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-fingerprint.h" -#include "gcr-oids.h" - -#include "egg/egg-asn1x.h" -#include "egg/egg-asn1-defs.h" - -#include <glib.h> -#include <gcrypt.h> - -/** - * SECTION:gcr-fingerprint - * @title: Key Fingerprints - * @short_description: Fingerprints for public and private keys - * - * These functions generate key fingerprints for public keys, certificates and - * key data. The fingerprints are created so that they they will be identical - * for a key and its corresponding certificate. - * - * Note that in the case of certificates these are not fingerprints of the - * actual certificate data, but rather of the public key contained in a - * certificate. - * - * These fingerprints are created using the subjectPublicKeyInfo ASN.1 structure. - */ - -/** - * gcr_fingerprint_from_subject_public_key_info: - * @key_info: (array length=n_key_info): DER encoded subjectPublicKeyInfo structure - * @n_key_info: length of DER encoded structure - * @checksum_type: the type of fingerprint to create - * @n_fingerprint: the length of fingerprint returned - * - * Create a key fingerprint for a DER encoded subjectPublicKeyInfo. - * - * Returns: (transfer full) (allow-none) (array length=n_fingerprint): the - * fingerprint or %NULL if the input was invalid. - */ -guchar * -gcr_fingerprint_from_subject_public_key_info (const guchar *key_info, - gsize n_key_info, - GChecksumType checksum_type, - gsize *n_fingerprint) -{ - GChecksum *check; - guint8 *fingerprint; - - g_return_val_if_fail (key_info, NULL); - g_return_val_if_fail (n_key_info, NULL); - g_return_val_if_fail (n_fingerprint, NULL); - - check = g_checksum_new (checksum_type); - g_return_val_if_fail (check, NULL); - - g_checksum_update (check, key_info, n_key_info); - - *n_fingerprint = g_checksum_type_get_length (checksum_type); - fingerprint = g_malloc (*n_fingerprint); - g_checksum_get_digest (check, fingerprint, n_fingerprint); - - g_checksum_free (check); - return fingerprint; -} - -static gboolean -rsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn) -{ - GckAttribute *modulus; - GckAttribute *exponent; - GNode *key_asn; - GNode *params_asn; - gpointer key, params; - gsize n_key, n_params; - - _gcr_oids_init (); - - modulus = gck_attributes_find (attrs, CKA_MODULUS); - exponent = gck_attributes_find (attrs, CKA_PUBLIC_EXPONENT); - if (modulus == NULL || exponent == NULL) - return FALSE; - - key_asn = egg_asn1x_create (pk_asn1_tab, "RSAPublicKey"); - g_return_val_if_fail (key_asn, FALSE); - - params_asn = egg_asn1x_create (pk_asn1_tab, "RSAParameters"); - g_return_val_if_fail (params_asn, FALSE); - - egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "modulus", NULL), - modulus->value, modulus->length, NULL); - - egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "publicExponent", NULL), - exponent->value, exponent->length, NULL); - - key = egg_asn1x_encode (key_asn, g_realloc, &n_key); - egg_asn1x_destroy (key_asn); - - egg_asn1x_set_null (params_asn); - - params = egg_asn1x_encode (params_asn, g_realloc, &n_params); - egg_asn1x_destroy (params_asn); - - egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL), - key, n_key * 8, g_free); - - egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_RSA); - egg_asn1x_set_raw_element (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), - params, n_params, g_free); - - return TRUE; -} - -static gboolean -dsa_subject_public_key_from_private (GNode *key_asn, GckAttribute *ap, - GckAttribute *aq, GckAttribute *ag, GckAttribute *ax) -{ - gcry_mpi_t mp, mq, mg, mx, my; - size_t n_buffer; - gcry_error_t gcry; - unsigned char *buffer; - - gcry = gcry_mpi_scan (&mp, GCRYMPI_FMT_USG, ap->value, ap->length, NULL); - g_return_val_if_fail (gcry == 0, FALSE); - - gcry = gcry_mpi_scan (&mq, GCRYMPI_FMT_USG, aq->value, aq->length, NULL); - g_return_val_if_fail (gcry == 0, FALSE); - - gcry = gcry_mpi_scan (&mg, GCRYMPI_FMT_USG, ag->value, ag->length, NULL); - g_return_val_if_fail (gcry == 0, FALSE); - - gcry = gcry_mpi_scan (&mx, GCRYMPI_FMT_USG, ax->value, ax->length, NULL); - g_return_val_if_fail (gcry == 0, FALSE); - - /* Calculate the public part from the private */ - my = gcry_mpi_snew (gcry_mpi_get_nbits (mx)); - g_return_val_if_fail (my, FALSE); - gcry_mpi_powm (my, mg, mx, mp); - - gcry = gcry_mpi_aprint (GCRYMPI_FMT_STD, &buffer, &n_buffer, my); - g_return_val_if_fail (gcry == 0, FALSE); - egg_asn1x_set_integer_as_raw (key_asn, buffer, n_buffer, gcry_free); - - gcry_mpi_release (mp); - gcry_mpi_release (mq); - gcry_mpi_release (mg); - gcry_mpi_release (mx); - gcry_mpi_release (my); - - return TRUE; -} - -static gboolean -dsa_subject_public_key_from_attributes (GckAttributes *attrs, - gulong klass, - GNode *info_asn) -{ - GckAttribute *value, *g, *q, *p; - GNode *key_asn, *params_asn; - gpointer key, params; - gsize n_key, n_params; - - _gcr_oids_init (); - - p = gck_attributes_find (attrs, CKA_PRIME); - q = gck_attributes_find (attrs, CKA_SUBPRIME); - g = gck_attributes_find (attrs, CKA_BASE); - value = gck_attributes_find (attrs, CKA_VALUE); - - if (p == NULL || q == NULL || g == NULL || value == NULL) - return FALSE; - - key_asn = egg_asn1x_create (pk_asn1_tab, "DSAPublicPart"); - g_return_val_if_fail (key_asn, FALSE); - - params_asn = egg_asn1x_create (pk_asn1_tab, "DSAParameters"); - g_return_val_if_fail (params_asn, FALSE); - - egg_asn1x_set_integer_as_usg (egg_asn1x_node (params_asn, "p", NULL), p->value, p->length, NULL); - egg_asn1x_set_integer_as_usg (egg_asn1x_node (params_asn, "q", NULL), q->value, q->length, NULL); - egg_asn1x_set_integer_as_usg (egg_asn1x_node (params_asn, "g", NULL), g->value, g->length, NULL); - - /* Are these attributes for a public or private key? */ - if (klass == CKO_PRIVATE_KEY) { - - /* We need to calculate the public from the private key */ - if (!dsa_subject_public_key_from_private (key_asn, p, q, g, value)) - g_return_val_if_reached (FALSE); - - } else if (klass == CKO_PUBLIC_KEY) { - egg_asn1x_set_integer_as_usg (key_asn, value->value, value->length, NULL); - - } else { - g_assert_not_reached (); - } - - key = egg_asn1x_encode (key_asn, g_realloc, &n_key); - egg_asn1x_destroy (key_asn); - - params = egg_asn1x_encode (params_asn, g_realloc, &n_params); - egg_asn1x_destroy (params_asn); - - egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL), - key, n_key * 8, g_free); - egg_asn1x_set_raw_element (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), - params, n_params, g_free); - - egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_DSA); - - return TRUE; -} - -static gpointer -fingerprint_from_key_attributes (GckAttributes *attrs, - gulong klass, - GChecksumType checksum_type, - gsize *n_fingerprint) -{ - gpointer fingerprint = NULL; - gboolean ret = FALSE; - GNode *info_asn; - gpointer info; - gulong key_type; - gsize n_info; - - if (!gck_attributes_find_ulong (attrs, CKA_KEY_TYPE, &key_type)) - return NULL; - - info_asn = egg_asn1x_create (pkix_asn1_tab, "SubjectPublicKeyInfo"); - g_return_val_if_fail (info_asn, NULL); - - if (key_type == CKK_RSA) - ret = rsa_subject_public_key_from_attributes (attrs, info_asn); - - else if (key_type == CKK_DSA) - ret = dsa_subject_public_key_from_attributes (attrs, klass, info_asn); - - else - ret = FALSE; - - if (ret) { - info = egg_asn1x_encode (info_asn, g_realloc, &n_info); - fingerprint = gcr_fingerprint_from_subject_public_key_info (info, n_info, - checksum_type, - n_fingerprint); - g_free (info); - } - - egg_asn1x_destroy (info_asn); - return fingerprint; -} - -static guchar * -fingerprint_from_cert_value (const guchar *der_data, - gsize n_der_data, - GChecksumType checksum_type, - gsize *n_fingerprint) -{ - guchar *fingerprint; - GNode *cert_asn; - gconstpointer info; - gsize n_info; - - cert_asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", - der_data, n_der_data); - if (cert_asn == NULL) - return NULL; - - info = egg_asn1x_get_raw_element (egg_asn1x_node (cert_asn, "tbsCertificate", "subjectPublicKeyInfo", NULL), &n_info); - g_return_val_if_fail (info != NULL, NULL); - - fingerprint = gcr_fingerprint_from_subject_public_key_info (info, n_info, - checksum_type, - n_fingerprint); - - egg_asn1x_destroy (cert_asn); - return fingerprint; -} - -static guchar * -fingerprint_from_cert_attributes (GckAttributes *attrs, - GChecksumType checksum_type, - gsize *n_fingerprint) -{ - GckAttribute *attr; - - attr = gck_attributes_find (attrs, CKA_VALUE); - if (attr == NULL) - return NULL; - - return fingerprint_from_cert_value (attr->value, attr->length, checksum_type, - n_fingerprint); -} - -/** - * gcr_fingerprint_from_attributes: - * @attrs: attributes for key or certificate - * @checksum_type: the type of fingerprint to create - * @n_fingerprint: the length of fingerprint returned - * - * Create a key fingerprint for a certificate, public key or private key. - * Note that this is not a fingerprint of certificate data, which you would - * use gcr_certificate_get_fingerprint() for. - * - * Returns: (transfer full) (allow-none) (array length=n_fingerprint): the - * fingerprint or %NULL if the input was invalid. - */ -guchar * -gcr_fingerprint_from_attributes (GckAttributes *attrs, - GChecksumType checksum_type, - gsize *n_fingerprint) -{ - gulong klass; - - g_return_val_if_fail (attrs, FALSE); - g_return_val_if_fail (n_fingerprint, FALSE); - - if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &klass)) - return NULL; - - if (klass == CKO_CERTIFICATE) - return fingerprint_from_cert_attributes (attrs, checksum_type, - n_fingerprint); - - else if (klass == CKO_PUBLIC_KEY || klass == CKO_PRIVATE_KEY) - return fingerprint_from_key_attributes (attrs, klass, - checksum_type, - n_fingerprint); - - else - return NULL; -} - -/** - * gcr_fingerprint_from_certificate_public_key: - * @certificate: the certificate - * @checksum_type: the type of fingerprint to create - * @n_fingerprint: the length of fingerprint returned - * - * Create a key fingerprint for a certificate's public key. Note that this is - * not a fingerprint of certificate data, which you would use - * gcr_certificate_get_fingerprint() for. - * - * Returns: (transfer full) (allow-none) (array length=n_fingerprint): the - * fingerprint or %NULL if the input was invalid. - */ -guchar * -gcr_fingerprint_from_certificate_public_key (GcrCertificate *certificate, - GChecksumType checksum_type, - gsize *n_fingerprint) -{ - const guchar *der_data; - gsize n_der_data; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), NULL); - - der_data = gcr_certificate_get_der_data (certificate, &n_der_data); - g_return_val_if_fail (der_data != NULL, NULL); - - return fingerprint_from_cert_value (der_data, n_der_data, checksum_type, - n_fingerprint); -} diff --git a/gcr/gcr-fingerprint.h b/gcr/gcr-fingerprint.h deleted file mode 100644 index 84cc41f9..00000000 --- a/gcr/gcr-fingerprint.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General License for more details. - * - * You should have received a copy of the GNU Lesser General - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef GCR_FINGERPRINT_H -#define GCR_FINGERPRINT_H - -#include <glib.h> - -#include "gcr-types.h" -#include "gcr-certificate.h" - -guchar * gcr_fingerprint_from_subject_public_key_info (const guchar *key_info, - gsize n_key_info, - GChecksumType checksum_type, - gsize *n_fingerprint); - -guchar * gcr_fingerprint_from_attributes (GckAttributes *attrs, - GChecksumType checksum_type, - gsize *n_fingerprint); - -guchar * gcr_fingerprint_from_certificate_public_key (GcrCertificate *certificate, - GChecksumType checksum_type, - gsize *n_fingerprint); - -#endif /* GCR_FINGERPRINT_H_ */ diff --git a/gcr/gcr-gnupg-collection.c b/gcr/gcr-gnupg-collection.c deleted file mode 100644 index fe730a20..00000000 --- a/gcr/gcr-gnupg-collection.c +++ /dev/null @@ -1,754 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-callback-output-stream.h" -#include "gcr-collection.h" -#define DEBUG_FLAG GCR_DEBUG_GNUPG -#include "gcr-debug.h" -#include "gcr-gnupg-collection.h" -#include "gcr-gnupg-key.h" -#include "gcr-gnupg-process.h" -#include "gcr-gnupg-records.h" -#include "gcr-gnupg-util.h" -#include "gcr-internal.h" -#include "gcr-record.h" -#include "gcr-util.h" - -#include <sys/wait.h> -#include <string.h> - -enum { - PROP_0, - PROP_DIRECTORY -}; - -struct _GcrGnupgCollectionPrivate { - GHashTable *items; /* char *keyid -> GcrGnupgKey* */ - gchar *directory; -}; - -/* Forward declarations */ -static void _gcr_collection_iface (GcrCollectionIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrGnupgCollection, _gcr_gnupg_collection, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_COLLECTION, _gcr_collection_iface) -); - - -static void -_gcr_gnupg_collection_init (GcrGnupgCollection *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_GNUPG_COLLECTION, - GcrGnupgCollectionPrivate); - - self->pv->items = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_object_unref); -} - -static void -_gcr_gnupg_collection_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrGnupgCollection *self = GCR_GNUPG_COLLECTION (obj); - - switch (prop_id) { - case PROP_DIRECTORY: - g_return_if_fail (!self->pv->directory); - self->pv->directory = g_value_dup_string (value); - if (self->pv->directory && !g_path_is_absolute (self->pv->directory)) { - g_warning ("gnupg collection directory path should be absolute: %s", - self->pv->directory); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_gnupg_collection_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrGnupgCollection *self = GCR_GNUPG_COLLECTION (obj); - - switch (prop_id) { - case PROP_DIRECTORY: - g_value_set_string (value, self->pv->directory); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_gnupg_collection_dispose (GObject *obj) -{ - GcrGnupgCollection *self = GCR_GNUPG_COLLECTION (obj); - - g_hash_table_remove_all (self->pv->items); - - G_OBJECT_CLASS (_gcr_gnupg_collection_parent_class)->dispose (obj); -} - -static void -_gcr_gnupg_collection_finalize (GObject *obj) -{ - GcrGnupgCollection *self = GCR_GNUPG_COLLECTION (obj); - - g_assert (self->pv->items); - g_assert (g_hash_table_size (self->pv->items) == 0); - g_hash_table_destroy (self->pv->items); - self->pv->items = NULL; - - g_free (self->pv->directory); - self->pv->directory = NULL; - - G_OBJECT_CLASS (_gcr_gnupg_collection_parent_class)->finalize (obj); -} - -static void -_gcr_gnupg_collection_class_init (GcrGnupgCollectionClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->get_property = _gcr_gnupg_collection_get_property; - gobject_class->set_property = _gcr_gnupg_collection_set_property; - gobject_class->dispose = _gcr_gnupg_collection_dispose; - gobject_class->finalize = _gcr_gnupg_collection_finalize; - - /** - * GcrGnupgCollection:directory: - * - * Directory to load the gnupg keys from, or %NULL for default - * ~/.gnupg/ directory. - */ - g_object_class_install_property (gobject_class, PROP_DIRECTORY, - g_param_spec_string ("directory", "Directory", "Gnupg Directory", - NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_type_class_add_private (gobject_class, sizeof (GcrGnupgCollectionPrivate)); - _gcr_initialize_library (); -} - -static guint -gcr_gnupg_collection_real_get_length (GcrCollection *coll) -{ - GcrGnupgCollection *self = GCR_GNUPG_COLLECTION (coll); - return g_hash_table_size (self->pv->items); -} - -static GList* -gcr_gnupg_collection_real_get_objects (GcrCollection *coll) -{ - GcrGnupgCollection *self = GCR_GNUPG_COLLECTION (coll); - return g_hash_table_get_values (self->pv->items); -} - -static gboolean -gcr_gnupg_collection_real_contains (GcrCollection *collection, - GObject *object) -{ - GcrGnupgCollection *self = GCR_GNUPG_COLLECTION (collection); - GcrGnupgKey *key; - - if (!GCR_IS_GNUPG_KEY (object)) - return FALSE; - key = g_hash_table_lookup (self->pv->items, - _gcr_gnupg_key_get_keyid (GCR_GNUPG_KEY (object))); - if (key != NULL && G_OBJECT (key) == object) - return TRUE; - return FALSE; -} - -static void -_gcr_collection_iface (GcrCollectionIface *iface) -{ - iface->get_length = gcr_gnupg_collection_real_get_length; - iface->get_objects = gcr_gnupg_collection_real_get_objects; - iface->contains = gcr_gnupg_collection_real_contains; -} - -/** - * _gcr_gnupg_collection_new: - * @directory: (allow-none): The gnupg home directory. - * - * Create a new GcrGnupgCollection. - * - * The gnupg home directory is where the keyring files live. If directory is - * %NULL then the default gnupg home directory is used. - * - * Returns: (transfer full) (type Gcr.GnupgCollection): A newly allocated collection. - */ -GcrCollection* -_gcr_gnupg_collection_new (const gchar *directory) -{ - return g_object_new (GCR_TYPE_GNUPG_COLLECTION, - "directory", directory, - NULL); -} - -/* - * We have to run the gnupg process twice to list the public and then the - * secret keys. These phases are tracked by GcrLoadingPhase. If the first - * phase completes successfully (using gpg --list-keys) then we move on to - * the second phase where the secret keys are loaded (using gpg --list-secret-keys) - * - * If a key is loaded as a public key by the public phase, it can be updated by - * the secret phase. A key discovered in the secret phase must have a public - * counterpart already loaded by the public phase. - */ - -typedef enum { - GCR_LOADING_PHASE_PUBLIC = 1, - GCR_LOADING_PHASE_SECRET = 2, -} GcrLoadingPhase; - -/* - * We use @difference to track the keys that were in the collection before - * the load process, and then remove any not found, at the end of the load - * process. Strings are directly used from collection->pv->items keys. - */ - -typedef struct { - GcrGnupgCollection *collection; /* reffed pointer back to collection */ - GcrLoadingPhase loading_phase; /* Whether loading public or private */ - GPtrArray *records; /* GcrRecord* not yet made into a key */ - GcrGnupgProcess *process; /* The gnupg process itself */ - GCancellable *cancel; /* Cancellation for process */ - GString *out_data; /* Pending output not yet parsed into colons */ - GHashTable *difference; /* Hashset gchar *keyid -> gchar *keyid */ - - guint error_sig; - guint status_sig; - GOutputStream *output; - GOutputStream *outattr; - - GQueue *attribute_queue; /* Queue of unprocessed GcrRecord* status records */ - GByteArray *attribute_buf; /* Buffer of unprocessed attribute data received */ - GHashTable *attributes; /* Processed attributes waiting for a matching key */ -} GcrGnupgCollectionLoad; - -/* Forward declarations */ -static void spawn_gnupg_list_process (GcrGnupgCollectionLoad *load, GSimpleAsyncResult *res); - -static void -_gcr_gnupg_collection_load_free (gpointer data) -{ - GcrGnupgCollectionLoad *load = data; - g_assert (load); - - g_ptr_array_unref (load->records); - g_string_free (load->out_data, TRUE); - g_hash_table_destroy (load->difference); - g_object_unref (load->collection); - - if (load->process) { - if (load->error_sig) - g_signal_handler_disconnect (load->process, load->error_sig); - if (load->status_sig) - g_signal_handler_disconnect (load->process, load->status_sig); - g_object_unref (load->process); - } - - g_output_stream_close (load->output, NULL, NULL); - g_object_unref (load->output); - g_output_stream_close (load->outattr, NULL, NULL); - g_object_unref (load->outattr); - - if (load->cancel) - g_object_unref (load->cancel); - - if (load->attribute_queue) { - while (!g_queue_is_empty (load->attribute_queue)) - _gcr_record_free (g_queue_pop_head (load->attribute_queue)); - g_queue_free (load->attribute_queue); - } - if (load->attribute_buf) - g_byte_array_unref (load->attribute_buf); - if (load->attributes) - g_hash_table_destroy (load->attributes); - - g_slice_free (GcrGnupgCollectionLoad, load); -} - -static void -process_records_as_public_key (GcrGnupgCollectionLoad *load, GPtrArray *records, - const gchar *keyid) -{ - GPtrArray *attr_records = NULL; - const gchar *fingerprint; - gchar *orig_fingerprint; - GcrGnupgKey *key; - guint i; - - /* Add in any attributes we have loaded */ - fingerprint = _gcr_gnupg_records_get_fingerprint (records); - if (fingerprint && load->attributes) - attr_records = g_hash_table_lookup (load->attributes, fingerprint); - if (attr_records) { - _gcr_debug ("adding %d user id attribute(s) to key/fingerprint: %s/%s", - (gint)attr_records->len, keyid, fingerprint); - - if (!g_hash_table_lookup_extended (load->attributes, fingerprint, - (gpointer*)&orig_fingerprint, NULL)) - g_assert_not_reached (); - if (!g_hash_table_steal (load->attributes, fingerprint)) - g_assert_not_reached (); - g_free (orig_fingerprint); - - /* Move all the attribute records over to main records set */ - for (i = 0; i < attr_records->len; i++) - g_ptr_array_add (records, attr_records->pdata[i]); - - /* Shallow free of attr_records array */ - g_free (g_ptr_array_free (attr_records, FALSE)); - } - - /* Note that we've seen this keyid */ - g_hash_table_remove (load->difference, keyid); - - key = g_hash_table_lookup (load->collection->pv->items, keyid); - - /* Already have this key, just update */ - if (key) { - _gcr_debug ("updating public key: %s", keyid); - _gcr_gnupg_key_set_public_records (key, records); - - /* Add a new key */ - } else { - key = _gcr_gnupg_key_new (records, NULL); - _gcr_debug ("creating public key: %s", keyid); - g_hash_table_insert (load->collection->pv->items, g_strdup (keyid), key); - gcr_collection_emit_added (GCR_COLLECTION (load->collection), G_OBJECT (key)); - } -} - -static void -process_records_as_secret_key (GcrGnupgCollectionLoad *load, GPtrArray *records, - const gchar *keyid) -{ - GcrGnupgKey *key; - - key = g_hash_table_lookup (load->collection->pv->items, keyid); - - /* Don't have this key */ - if (key == NULL) { - g_message ("Secret key seen but no public key for: %s", keyid); - - /* Tell the private key that it's a secret one */ - } else { - _gcr_debug ("adding secret records to key: %s", keyid); - _gcr_gnupg_key_set_secret_records (key, records); - } -} - -static void -process_records_as_key (GcrGnupgCollectionLoad *load) -{ - GPtrArray *records; - const gchar *keyid; - GQuark schema; - - g_assert (load->records->len); - - records = load->records; - load->records = g_ptr_array_new_with_free_func (_gcr_record_free); - - keyid = _gcr_gnupg_records_get_keyid (records); - if (keyid) { - schema = _gcr_record_get_schema (records->pdata[0]); - - /* A public key */ - if (schema == GCR_RECORD_SCHEMA_PUB) - process_records_as_public_key (load, records, keyid); - - /* A secret key */ - else if (schema == GCR_RECORD_SCHEMA_SEC) - process_records_as_secret_key (load, records, keyid); - - else - g_assert_not_reached (); - - } else { - g_warning ("parsed gnupg data had no keyid"); - } - - g_ptr_array_unref (records); -} - -static gboolean -process_outstanding_attribute (GcrGnupgCollectionLoad *load, GcrRecord *record) -{ - const gchar *fingerprint; - GPtrArray *records; - GcrRecord *xa1; - guint length; - - if (!_gcr_record_get_uint (record, GCR_RECORD_ATTRIBUTE_LENGTH, &length)) - g_return_val_if_reached (FALSE); - fingerprint = _gcr_record_get_raw (record, GCR_RECORD_ATTRIBUTE_KEY_FINGERPRINT); - g_return_val_if_fail (fingerprint != NULL, FALSE); - - /* Do we have enough data for this attribute? */ - if (!load->attribute_buf || load->attribute_buf->len < length) { - _gcr_debug ("not enough attribute data in buffer: %u", length); - return FALSE; - } - - if (!load->attributes) - load->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, (GDestroyNotify)g_ptr_array_unref); - - records = g_hash_table_lookup (load->attributes, fingerprint); - if (!records) { - records = g_ptr_array_new_with_free_func (_gcr_record_free); - g_hash_table_insert (load->attributes, g_strdup (fingerprint), records); - } - - _gcr_debug ("new attribute of length %d for key with fingerprint %s", - length, fingerprint); - - xa1 = _gcr_gnupg_build_xa1_record (record, load->attribute_buf->data, length); - g_ptr_array_add (records, xa1); - - /* Did we use up all the attribute data? Get rid of the buffer */ - if (length == load->attribute_buf->len) { - g_byte_array_unref (load->attribute_buf); - load->attribute_buf = NULL; - - /* Otherwise clear out the used data from buffer */ - } else { - g_byte_array_remove_range (load->attribute_buf, 0, length); - } - - return TRUE; -} - -static void -process_outstanding_attributes (GcrGnupgCollectionLoad *load) -{ - GcrRecord *record; - - if (load->attribute_queue == NULL) - return; - - _gcr_debug ("%d outstanding attribute records", - (gint)g_queue_get_length (load->attribute_queue)); - - for (;;) { - record = g_queue_peek_head (load->attribute_queue); - if (record == NULL) - break; - if (!process_outstanding_attribute (load, record)) - break; - g_queue_pop_head (load->attribute_queue); - _gcr_record_free (record); - } -} - -static void -on_line_parse_output (const gchar *line, gpointer user_data) -{ - GcrGnupgCollectionLoad *load = user_data; - GcrRecord *record; - GQuark schema; - - _gcr_debug ("output: %s", line); - - record = _gcr_record_parse_colons (line, -1); - if (!record) { - g_warning ("invalid gnupg output line: %s", line); - return; - } - - schema = _gcr_record_get_schema (record); - - /* - * Each time we see a line with 'pub' or 'sec' schema we assume that - * it's a new key being listed. - */ - if (schema == GCR_RECORD_SCHEMA_PUB || schema == GCR_RECORD_SCHEMA_SEC) { - _gcr_debug ("start of new key"); - if (load->records->len) - process_records_as_key (load); - g_assert (!load->records->len); - g_ptr_array_add (load->records, record); - record = NULL; - - /* - * 'uid' and 'fpr' schema lines get added to the key that came before. - */ - } else if (schema == GCR_RECORD_SCHEMA_UID || - schema == GCR_RECORD_SCHEMA_FPR) { - if (load->records->len) { - g_ptr_array_add (load->records, record); - record = NULL; - } - } - - if (record != NULL) - _gcr_record_free (record); -} - - -static gssize -on_gnupg_process_output_data (gconstpointer buffer, - gsize count, - GCancellable *cancellable, - gpointer user_data, - GError **error) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GcrGnupgCollectionLoad *load = g_simple_async_result_get_op_res_gpointer (res); - - g_string_append_len (load->out_data, buffer, count); - _gcr_util_parse_lines (load->out_data, FALSE, on_line_parse_output, load); - return count; -} - -static void -on_gnupg_process_error_line (GcrGnupgProcess *process, const gchar *line, - gpointer user_data) -{ - g_printerr ("%s\n", line); -} - -static void -on_gnupg_process_status_record (GcrGnupgProcess *process, GcrRecord *record, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GcrGnupgCollectionLoad *load = g_simple_async_result_get_op_res_gpointer (res); - - if (GCR_RECORD_SCHEMA_ATTRIBUTE != _gcr_record_get_schema (record)) - return; - - if (!load->attribute_queue) - load->attribute_queue = g_queue_new (); - - g_queue_push_tail (load->attribute_queue, _gcr_record_copy (record)); - process_outstanding_attributes (load); -} - -static gssize -on_gnupg_process_attribute_data (gconstpointer buffer, - gsize count, - GCancellable *cancellable, - gpointer user_data, - GError **error) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GcrGnupgCollectionLoad *load = g_simple_async_result_get_op_res_gpointer (res); - - /* If we don't have a buffer, just claim this one */ - if (!load->attribute_buf) - load->attribute_buf = g_byte_array_new (); - - g_byte_array_append (load->attribute_buf, buffer, count); - - process_outstanding_attributes (load); - return count; -} - -static void -on_gnupg_process_completed (GObject *source, GAsyncResult *result, gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GcrGnupgCollectionLoad *load = g_simple_async_result_get_op_res_gpointer (res); - GHashTableIter iter; - GError *error = NULL; - GObject *object; - gpointer keyid; - - if (!_gcr_gnupg_process_run_finish (GCR_GNUPG_PROCESS (source), result, &error)) { - g_simple_async_result_set_from_error (res, error); - g_simple_async_result_complete (res); - g_object_unref (res); - g_clear_error (&error); - return; - } - - /* Process any remaining output */ - _gcr_util_parse_lines (load->out_data, TRUE, on_line_parse_output, load); - - /* Process last bit as a key, if any */ - if (load->records->len) - process_records_as_key (load); - - /* If we completed loading public keys, then go and load secret */ - switch (load->loading_phase) { - case GCR_LOADING_PHASE_PUBLIC: - _gcr_debug ("public load phase completed"); - load->loading_phase = GCR_LOADING_PHASE_SECRET; - spawn_gnupg_list_process (load, res); - g_object_unref (res); - return; - case GCR_LOADING_PHASE_SECRET: - _gcr_debug ("secret load phase completed"); - /* continue below */ - break; - default: - g_assert_not_reached (); - } - - /* Remove any keys that we still have in the difference */ - g_hash_table_iter_init (&iter, load->difference); - while (g_hash_table_iter_next (&iter, &keyid, NULL)) { - object = g_hash_table_lookup (load->collection->pv->items, keyid); - if (object != NULL) { - g_object_ref (object); - _gcr_debug ("removing key no longer present in keyring: %s", (gchar*)keyid); - g_hash_table_remove (load->collection->pv->items, keyid); - gcr_collection_emit_removed (GCR_COLLECTION (load->collection), object); - g_object_unref (object); - } - } - - g_simple_async_result_complete (res); - g_object_unref (res); -} - -static void -spawn_gnupg_list_process (GcrGnupgCollectionLoad *load, GSimpleAsyncResult *res) -{ - GcrGnupgProcessFlags flags = 0; - GPtrArray *argv; - - argv = g_ptr_array_new (); - - switch (load->loading_phase) { - case GCR_LOADING_PHASE_PUBLIC: - _gcr_debug ("starting public load phase"); - g_ptr_array_add (argv, (gpointer)"--list-keys"); - /* Load photos in public phase */ - flags = GCR_GNUPG_PROCESS_WITH_ATTRIBUTES | - GCR_GNUPG_PROCESS_WITH_STATUS; - break; - case GCR_LOADING_PHASE_SECRET: - _gcr_debug ("starting secret load phase"); - g_ptr_array_add (argv, (gpointer)"--list-secret-keys"); - break; - default: - g_assert_not_reached (); - } - - g_ptr_array_add (argv, (gpointer)"--fixed-list-mode"); - g_ptr_array_add (argv, (gpointer)"--with-colons"); - g_ptr_array_add (argv, (gpointer)"--with-fingerprint"); - g_ptr_array_add (argv, NULL); - - /* res is unreffed in on_gnupg_process_completed */ - _gcr_gnupg_process_run_async (load->process, (const gchar**)argv->pdata, NULL, flags, - load->cancel, on_gnupg_process_completed, - g_object_ref (res)); - - g_ptr_array_unref (argv); -} - -/** - * _gcr_gnupg_collection_load_async: - * @self: The collection - * @cancellable: Cancellation object or %NULL - * @callback: Callback to call when result is ready - * @user_data: Data for callback - * - * Start an operation to load or reload the list of gnupg keys in this - * collection. - */ -void -_gcr_gnupg_collection_load_async (GcrGnupgCollection *self, GCancellable *cancellable, - GAsyncReadyCallback callback, gpointer user_data) -{ - GSimpleAsyncResult *res; - GcrGnupgCollectionLoad *load; - GHashTableIter iter; - gpointer keyid; - - g_return_if_fail (GCR_IS_GNUPG_COLLECTION (self)); - - /* TODO: Cancellation not yet implemented */ - - res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, - _gcr_gnupg_collection_load_async); - - load = g_slice_new0 (GcrGnupgCollectionLoad); - load->records = g_ptr_array_new_with_free_func (_gcr_record_free); - load->out_data = g_string_sized_new (1024); - load->collection = g_object_ref (self); - load->cancel = cancellable ? g_object_ref (cancellable) : cancellable; - - load->output = _gcr_callback_output_stream_new (on_gnupg_process_output_data, res, NULL); - load->outattr = _gcr_callback_output_stream_new (on_gnupg_process_attribute_data, res, NULL); - - load->process = _gcr_gnupg_process_new (self->pv->directory, NULL); - _gcr_gnupg_process_set_output_stream (load->process, load->output); - _gcr_gnupg_process_set_attribute_stream (load->process, load->outattr); - load->error_sig = g_signal_connect (load->process, "error-line", G_CALLBACK (on_gnupg_process_error_line), res); - load->status_sig = g_signal_connect (load->process, "status-record", G_CALLBACK (on_gnupg_process_status_record), res); - - /* - * Track all the keys we currently have, at end remove those that - * didn't get listed by the gpg process. - */ - load->difference = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_iter_init (&iter, self->pv->items); - while (g_hash_table_iter_next (&iter, &keyid, NULL)) - g_hash_table_insert (load->difference, keyid, keyid); - - g_simple_async_result_set_op_res_gpointer (res, load, - _gcr_gnupg_collection_load_free); - - load->loading_phase = GCR_LOADING_PHASE_PUBLIC; - spawn_gnupg_list_process (load, res); - - g_object_unref (res); -} - -/** - * _gcr_gnupg_collection_load_finish: - * @self: The collection - * @result: The result passed to the callback - * @error: Location to raise an error on failure. - * - * Get the result of an operation to load or reload the list of gnupg keys - * in this collection. - */ -gboolean -_gcr_gnupg_collection_load_finish (GcrGnupgCollection *self, GAsyncResult *result, - GError **error) -{ - g_return_val_if_fail (GCR_IS_GNUPG_COLLECTION (self), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), - _gcr_gnupg_collection_load_async), FALSE); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return FALSE; - - return TRUE; -} diff --git a/gcr/gcr-gnupg-collection.h b/gcr/gcr-gnupg-collection.h deleted file mode 100644 index a626cef9..00000000 --- a/gcr/gcr-gnupg-collection.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef GCR_GNUPG_COLLECTION_H -#define GCR_GNUPG_COLLECTION_H - -#include "gcr-base.h" -#include "gcr-collection.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_GNUPG_COLLECTION (_gcr_gnupg_collection_get_type ()) -#define GCR_GNUPG_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_GNUPG_COLLECTION, GcrGnupgCollection)) -#define GCR_GNUPG_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_GNUPG_COLLECTION, GcrGnupgCollectionClass)) -#define GCR_IS_GNUPG_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_GNUPG_COLLECTION)) -#define GCR_IS_GNUPG_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_GNUPG_COLLECTION)) -#define GCR_GNUPG_COLLECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_GNUPG_COLLECTION, GcrGnupgCollectionClass)) - -typedef struct _GcrGnupgCollection GcrGnupgCollection; -typedef struct _GcrGnupgCollectionClass GcrGnupgCollectionClass; -typedef struct _GcrGnupgCollectionPrivate GcrGnupgCollectionPrivate; - -struct _GcrGnupgCollection { - /*< private >*/ - GObject parent; - GcrGnupgCollectionPrivate *pv; -}; - -struct _GcrGnupgCollectionClass { - GObjectClass parent_class; -}; - -GType _gcr_gnupg_collection_get_type (void); - -GcrCollection* _gcr_gnupg_collection_new (const gchar *directory); - -void _gcr_gnupg_collection_load_async (GcrGnupgCollection *self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean _gcr_gnupg_collection_load_finish (GcrGnupgCollection *self, - GAsyncResult *result, - GError **error); - -G_END_DECLS - -#endif /* GCR_GNUPG_COLLECTION_H */ diff --git a/gcr/gcr-gnupg-importer.c b/gcr/gcr-gnupg-importer.c deleted file mode 100644 index db0fd39d..00000000 --- a/gcr/gcr-gnupg-importer.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-gnupg-importer.h" -#include "gcr-gnupg-process.h" -#include "gcr-internal.h" - -#include <glib/gi18n-lib.h> - -enum { - PROP_0, - PROP_LABEL, - PROP_ICON, - PROP_IMPORTED, - PROP_DIRECTORY, - PROP_INTERACTION -}; - -struct _GcrGnupgImporterPrivate { - GcrGnupgProcess *process; - GMemoryInputStream *packets; - GTlsInteraction *interaction; - GArray *imported; -}; - -static void gcr_gnupg_importer_iface (GcrImporterIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrGnupgImporter, _gcr_gnupg_importer, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_IMPORTER, gcr_gnupg_importer_iface); -); - -static void -_gcr_gnupg_importer_init (GcrGnupgImporter *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_GNUPG_IMPORTER, GcrGnupgImporterPrivate); - self->pv->packets = G_MEMORY_INPUT_STREAM (g_memory_input_stream_new ()); - self->pv->imported = g_array_new (TRUE, TRUE, sizeof (gchar *)); -} - -static void -_gcr_gnupg_importer_dispose (GObject *obj) -{ - GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj); - - if (self->pv->process) - g_object_run_dispose (G_OBJECT (self->pv->process)); - g_clear_object (&self->pv->process); - g_clear_object (&self->pv->packets); - g_clear_object (&self->pv->interaction); - - G_OBJECT_CLASS (_gcr_gnupg_importer_parent_class)->dispose (obj); -} - -static void -_gcr_gnupg_importer_finalize (GObject *obj) -{ - GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj); - - g_array_free (self->pv->imported, TRUE); - - G_OBJECT_CLASS (_gcr_gnupg_importer_parent_class)->finalize (obj); -} - -static gchar * -calculate_label (GcrGnupgImporter *self) -{ - const gchar *directory; - - directory = _gcr_gnupg_process_get_directory (self->pv->process); - if (directory == NULL) - return g_strdup (_("GnuPG Keyring")); - else - return g_strdup_printf (_("GnuPG Keyring: %s"), directory); -} - -static GIcon * -calculate_icon (GcrGnupgImporter *self) -{ - const gchar *directory; - - directory = _gcr_gnupg_process_get_directory (self->pv->process); - if (directory == NULL) - return g_themed_icon_new ("user-home"); - else - return g_themed_icon_new ("folder"); -} - -static gboolean -on_process_status_record (GcrGnupgProcess *process, - GcrRecord *record, - gpointer user_data) -{ - GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (user_data); - const gchar *value; - gchar *fingerprint; - - if (_gcr_record_get_schema (record) != GCR_RECORD_SCHEMA_IMPORT_OK) - return TRUE; - - value = _gcr_record_get_raw (record, GCR_RECORD_IMPORT_FINGERPRINT); - if (value != NULL && value[0] != 0) { - fingerprint = g_strdup (value); - g_array_append_val (self->pv->imported, fingerprint); - } - - return TRUE; -} - -static void -_gcr_gnupg_importer_set_property (GObject *obj, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj); - - switch (prop_id) { - case PROP_DIRECTORY: - self->pv->process = _gcr_gnupg_process_new (g_value_get_string (value), - NULL); - _gcr_gnupg_process_set_input_stream (self->pv->process, G_INPUT_STREAM (self->pv->packets)); - g_signal_connect (self->pv->process, "status-record", G_CALLBACK (on_process_status_record), self); - break; - case PROP_INTERACTION: - g_clear_object (&self->pv->interaction); - self->pv->interaction = g_value_dup_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_gnupg_importer_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (obj); - - switch (prop_id) { - case PROP_LABEL: - g_value_take_string (value, calculate_label (self)); - break; - case PROP_ICON: - g_value_take_object (value, calculate_icon (self)); - break; - case PROP_IMPORTED: - g_value_set_boxed (value, _gcr_gnupg_importer_get_imported (self)); - break; - case PROP_DIRECTORY: - g_value_set_string (value, _gcr_gnupg_process_get_directory (self->pv->process)); - break; - case PROP_INTERACTION: - g_value_set_object (value, self->pv->interaction); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_gnupg_importer_class_init (GcrGnupgImporterClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GckAttributes *registered; - - gobject_class->dispose = _gcr_gnupg_importer_dispose; - gobject_class->finalize = _gcr_gnupg_importer_finalize; - gobject_class->set_property = _gcr_gnupg_importer_set_property; - gobject_class->get_property = _gcr_gnupg_importer_get_property; - - g_type_class_add_private (gobject_class, sizeof (GcrGnupgImporterPrivate)); - - g_object_class_override_property (gobject_class, PROP_LABEL, "label"); - - g_object_class_override_property (gobject_class, PROP_ICON, "icon"); - - g_object_class_override_property (gobject_class, PROP_INTERACTION, "interaction"); - - g_object_class_install_property (gobject_class, PROP_IMPORTED, - g_param_spec_boxed ("imported", "Imported", "Fingerprints of imported keys", - G_TYPE_STRV, G_PARAM_READABLE)); - - g_object_class_install_property (gobject_class, PROP_DIRECTORY, - g_param_spec_string ("directory", "Directory", "Directory to import keys to", - NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - registered = gck_attributes_new (); - gck_attributes_add_ulong (registered, CKA_CLASS, CKO_GCR_GNUPG_RECORDS); - gcr_importer_register (GCR_TYPE_GNUPG_IMPORTER, registered); - gck_attributes_unref (registered); - - _gcr_initialize_library (); -} - -static GList * -_gcr_gnupg_importer_create_for_parsed (GcrParsed *parsed) -{ - GcrImporter *self; - - if (gcr_parsed_get_format (parsed) != GCR_FORMAT_OPENPGP_PACKET) - return NULL; - - self = _gcr_gnupg_importer_new (NULL); - if (!gcr_importer_queue_for_parsed (self, parsed)) - g_assert_not_reached (); - - return g_list_append (NULL, self); -} - -static gboolean -_gcr_gnupg_importer_queue_for_parsed (GcrImporter *importer, - GcrParsed *parsed) -{ - GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (importer); - gconstpointer block; - gsize n_block; - - if (gcr_parsed_get_format (parsed) != GCR_FORMAT_OPENPGP_PACKET) - return FALSE; - - block = gcr_parsed_get_data (parsed, &n_block); - g_return_val_if_fail (block, FALSE); - - g_memory_input_stream_add_data (self->pv->packets, g_memdup (block, n_block), - n_block, g_free); - return TRUE; -} - -static void -on_process_run_complete (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GError *error = NULL; - - if (!_gcr_gnupg_process_run_finish (GCR_GNUPG_PROCESS (source), result, &error)) - g_simple_async_result_take_error (res, error); - - g_simple_async_result_complete (res); - g_object_unref (res); -} - -static void -_gcr_gnupg_importer_import_async (GcrImporter *importer, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GcrGnupgImporter *self = GCR_GNUPG_IMPORTER (importer); - GSimpleAsyncResult *res; - const gchar *argv[] = { "--import", NULL }; - - res = g_simple_async_result_new (G_OBJECT (importer), callback, user_data, - _gcr_gnupg_importer_import_async); - - _gcr_gnupg_process_run_async (self->pv->process, argv, NULL, - GCR_GNUPG_PROCESS_WITH_STATUS, - cancellable, on_process_run_complete, - g_object_ref (res)); - - g_object_unref (res); -} - -static gboolean -_gcr_gnupg_importer_import_finish (GcrImporter *importer, - GAsyncResult *result, - GError **error) -{ - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (importer), - _gcr_gnupg_importer_import_async), FALSE); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return FALSE; - - return TRUE; -} - -static void -gcr_gnupg_importer_iface (GcrImporterIface *iface) -{ - iface->create_for_parsed = _gcr_gnupg_importer_create_for_parsed; - iface->queue_for_parsed = _gcr_gnupg_importer_queue_for_parsed; - iface->import_async = _gcr_gnupg_importer_import_async; - iface->import_finish = _gcr_gnupg_importer_import_finish; -} - -/** - * _gcr_gnupg_importer_new: - * @directory: (allow-none): the directory to import to, or %NULL for default - * - * Returns: (transfer full) (type Gcr.GnupgImporter): the new importer - */ -GcrImporter * -_gcr_gnupg_importer_new (const gchar *directory) -{ - return g_object_new (GCR_TYPE_GNUPG_IMPORTER, - "directory", directory, - NULL); -} - -const gchar ** -_gcr_gnupg_importer_get_imported (GcrGnupgImporter *self) -{ - g_return_val_if_fail (GCR_IS_GNUPG_IMPORTER (self), NULL); - return (const gchar **)self->pv->imported->data; -} diff --git a/gcr/gcr-gnupg-importer.h b/gcr/gcr-gnupg-importer.h deleted file mode 100644 index 8511af84..00000000 --- a/gcr/gcr-gnupg-importer.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_H_INSIDE__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> can be included directly." -#endif - -#ifndef __GCR_GNUPG_IMPORTER_H__ -#define __GCR_GNUPG_IMPORTER_H__ - -#include "gcr-importer.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_GNUPG_IMPORTER (_gcr_gnupg_importer_get_type ()) -#define GCR_GNUPG_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_GNUPG_IMPORTER, GcrGnupgImporter)) -#define GCR_GNUPG_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_GNUPG_IMPORTER, GcrGnupgImporterClass)) -#define GCR_IS_GNUPG_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_GNUPG_IMPORTER)) -#define GCR_IS_GNUPG_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_GNUPG_IMPORTER)) -#define GCR_GNUPG_IMPORTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_GNUPG_IMPORTER, GcrGnupgImporterClass)) - -typedef struct _GcrGnupgImporter GcrGnupgImporter; -typedef struct _GcrGnupgImporterClass GcrGnupgImporterClass; -typedef struct _GcrGnupgImporterPrivate GcrGnupgImporterPrivate; - -struct _GcrGnupgImporter { - GObject parent; - - /*< private >*/ - GcrGnupgImporterPrivate *pv; -}; - -struct _GcrGnupgImporterClass { - GObjectClass parent_class; -}; - -GType _gcr_gnupg_importer_get_type (void) G_GNUC_CONST; - -GcrImporter * _gcr_gnupg_importer_new (const gchar *directory); - -const gchar ** _gcr_gnupg_importer_get_imported (GcrGnupgImporter *self); - -G_END_DECLS - -#endif /* __GCR_IMPORTER_H__ */ diff --git a/gcr/gcr-gnupg-key.c b/gcr/gcr-gnupg-key.c deleted file mode 100644 index 1d1bc420..00000000 --- a/gcr/gcr-gnupg-key.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-gnupg-key.h" -#include "gcr-gnupg-records.h" -#include "gcr-record.h" -#include "gcr-memory-icon.h" - -#include "gck/gck.h" - -#include <glib/gi18n-lib.h> - -enum { - PROP_0, - PROP_KEYID, - PROP_PUBLIC_RECORDS, - PROP_SECRET_RECORDS, - PROP_LABEL, - PROP_MARKUP, - PROP_DESCRIPTION, - PROP_SHORT_KEYID, - PROP_ICON -}; - -struct _GcrGnupgKeyPrivate { - GPtrArray *public_records; - GPtrArray *secret_records; - GIcon *icon; -}; - -G_DEFINE_TYPE (GcrGnupgKey, _gcr_gnupg_key, G_TYPE_OBJECT); - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -/* Copied from GPGME */ -static void -parse_user_id (const gchar *uid, gchar **name, gchar **email, gchar **comment) -{ - gchar *src, *tail, *x; - int in_name = 0; - int in_email = 0; - int in_comment = 0; - - *name = NULL; - *email = NULL; - *comment = NULL; - - x = tail = src = g_strdup (uid); - - while (*src) { - if (in_email) { - /* Not legal but anyway. */ - if (*src == '<') - in_email++; - else if (*src == '>') { - if (!--in_email && !*email) { - *email = tail; - *src = 0; - tail = src + 1; - } - } - } else if (in_comment) { - if (*src == '(') - in_comment++; - else if (*src == ')') { - if (!--in_comment && !*comment) { - *comment = tail; - *src = 0; - tail = src + 1; - } - } - } else if (*src == '<') { - if (in_name) { - if (!*name) { - *name = tail; - *src = 0; - tail = src + 1; - } - in_name = 0; - } else - tail = src + 1; - - in_email = 1; - } else if (*src == '(') { - if (in_name) { - if (!*name) { - *name = tail; - *src = 0; - tail = src + 1; - } - in_name = 0; - } - in_comment = 1; - } else if (!in_name && *src != ' ' && *src != '\t') { - in_name = 1; - } - src++; - } - - if (in_name) { - if (!*name) { - *name = tail; - *src = 0; - tail = src + 1; - } - } - - /* Let unused parts point to an EOS. */ - *name = g_strdup (*name ? *name : ""); - *email = g_strdup (*email ? *email : ""); - *comment = g_strdup (*comment ? *comment : ""); - - g_strstrip (*name); - g_strstrip (*email); - g_strstrip (*comment); - - g_free (x); -} - -static gchar * -calculate_name (GcrGnupgKey *self) -{ - GcrRecord* record; - - record = _gcr_records_find (self->pv->public_records, GCR_RECORD_SCHEMA_UID); - g_return_val_if_fail (record, NULL); - - return _gcr_record_get_string (record, GCR_RECORD_UID_USERID); -} - -static gchar * -calculate_markup (GcrGnupgKey *self) -{ - gchar *markup = NULL; - gchar *uid, *name, *email, *comment; - - uid = calculate_name (self); - if (uid == NULL) - return NULL; - - parse_user_id (uid, &name, &email, &comment); - if (comment != NULL && comment[0] != '\0') - markup = g_markup_printf_escaped ("%s\n<small>%s \'%s\'</small>", name, email, comment); - else - markup = g_markup_printf_escaped ("%s\n<small>%s</small>", name, email); - g_free (name); - g_free (email); - g_free (comment); - g_free (uid); - - return markup; -} - -static void -_gcr_gnupg_key_init (GcrGnupgKey *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_GNUPG_KEY, GcrGnupgKeyPrivate)); -} - -static void -_gcr_gnupg_key_finalize (GObject *obj) -{ - GcrGnupgKey *self = GCR_GNUPG_KEY (obj); - - if (self->pv->public_records) - g_ptr_array_free (self->pv->public_records, TRUE); - if (self->pv->secret_records) - g_ptr_array_free (self->pv->secret_records, TRUE); - - G_OBJECT_CLASS (_gcr_gnupg_key_parent_class)->finalize (obj); -} - -static void -_gcr_gnupg_key_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrGnupgKey *self = GCR_GNUPG_KEY (obj); - - switch (prop_id) { - case PROP_PUBLIC_RECORDS: - _gcr_gnupg_key_set_public_records (self, g_value_get_boxed (value)); - break; - case PROP_SECRET_RECORDS: - _gcr_gnupg_key_set_secret_records (self, g_value_get_boxed (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_gnupg_key_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrGnupgKey *self = GCR_GNUPG_KEY (obj); - - switch (prop_id) { - case PROP_PUBLIC_RECORDS: - g_value_set_boxed (value, self->pv->public_records); - break; - case PROP_SECRET_RECORDS: - g_value_set_boxed (value, self->pv->secret_records); - break; - case PROP_KEYID: - g_value_set_string (value, _gcr_gnupg_key_get_keyid (self)); - break; - case PROP_LABEL: - g_value_take_string (value, calculate_name (self)); - break; - case PROP_DESCRIPTION: - g_value_set_string (value, _("PGP Key")); - break; - case PROP_MARKUP: - g_value_take_string (value, calculate_markup (self)); - break; - case PROP_SHORT_KEYID: - g_value_set_string (value, _gcr_gnupg_records_get_short_keyid (self->pv->public_records)); - break; - case PROP_ICON: - g_value_set_object (value, _gcr_gnupg_key_get_icon (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_gnupg_key_class_init (GcrGnupgKeyClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - _gcr_gnupg_key_parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private (klass, sizeof (GcrGnupgKeyPrivate)); - - gobject_class->finalize = _gcr_gnupg_key_finalize; - gobject_class->set_property = _gcr_gnupg_key_set_property; - gobject_class->get_property = _gcr_gnupg_key_get_property; - - /** - * GcrGnupgKey:public-records: - * - * Public key data. Should always be present. - */ - g_object_class_install_property (gobject_class, PROP_PUBLIC_RECORDS, - g_param_spec_boxed ("public-records", "Public Records", "Public Key Colon Records", - G_TYPE_PTR_ARRAY, G_PARAM_READWRITE)); - - /** - * GcrGnupgKey:secret-records: - * - * Secret key data. The keyid of this data must match public-dataset. - * If present, this key represents a secret key. - */ - g_object_class_install_property (gobject_class, PROP_SECRET_RECORDS, - g_param_spec_boxed ("secret-records", "Secret Records", "Secret Key Colon Records", - G_TYPE_PTR_ARRAY, G_PARAM_READWRITE)); - - /** - * GcrGnupgKey:keyid: - * - * Key identifier. - */ - g_object_class_install_property (gobject_class, PROP_KEYID, - g_param_spec_string ("keyid", "Key ID", "Key identifier", - "", G_PARAM_READABLE)); - - /** - * GcrGnupgKey:label: - * - * User readable label for this key. - */ - g_object_class_install_property (gobject_class, PROP_LABEL, - g_param_spec_string ("label", "Label", "Key label", - "", G_PARAM_READABLE)); - - /** - * GcrGnupgKey::description: - * - * Description of type of key. - */ - g_object_class_install_property (gobject_class, PROP_DESCRIPTION, - g_param_spec_string ("description", "Description", "Description of object type", - "", G_PARAM_READABLE)); - - /** - * GcrGnupgKey:markup: - * - * User readable markup which contains key label. - */ - g_object_class_install_property (gobject_class, PROP_MARKUP, - g_param_spec_string ("markup", "Markup", "Markup which describes key", - "", G_PARAM_READABLE)); - - /** - * GcrGnupgKey:short-keyid: - * - * User readable key identifier. - */ - g_object_class_install_property (gobject_class, PROP_SHORT_KEYID, - g_param_spec_string ("short-keyid", "Short Key ID", "Display key identifier", - "", G_PARAM_READABLE)); - - /** - * GcrGnupgKey:icon: - * - * Icon for this key. - */ - g_object_class_install_property (gobject_class, PROP_ICON, - g_param_spec_object ("icon", "Icon", "Icon for this key", - G_TYPE_ICON, G_PARAM_READABLE)); -} - -/** - * _gcr_gnupg_key_new: - * @pubset: array of GcrRecord* representing public part of key - * @secset: (allow-none): array of GcrRecord* representing secret part of key. - * - * Create a new GcrGnupgKey for the record data passed. If the secret part - * of the key is set, then this represents a secret key; otherwise it represents - * a public key. - * - * Returns: (transfer full): A newly allocated key. - */ -GcrGnupgKey* -_gcr_gnupg_key_new (GPtrArray *pubset, GPtrArray *secset) -{ - g_return_val_if_fail (pubset, NULL); - return g_object_new (GCR_TYPE_GNUPG_KEY, - "public-records", pubset, - "secret-records", secset, - NULL); -} - -/** - * _gcr_gnupg_key_get_public_records: - * @self: The key - * - * Get the record data this key is based on. - * - * Returns: (transfer none): An array of GcrRecord*. - */ -GPtrArray* -_gcr_gnupg_key_get_public_records (GcrGnupgKey *self) -{ - g_return_val_if_fail (GCR_IS_GNUPG_KEY (self), NULL); - return self->pv->public_records; -} - -/** - * _gcr_gnupg_key_set_public_records: - * @self: The key - * @records: The new array of GcrRecord* - * - * Change the record data that this key is based on. - */ -void -_gcr_gnupg_key_set_public_records (GcrGnupgKey *self, GPtrArray *records) -{ - GObject *obj; - - g_return_if_fail (GCR_IS_GNUPG_KEY (self)); - g_return_if_fail (records); - - /* Check that it matches previous */ - if (self->pv->public_records) { - const gchar *old_keyid = _gcr_gnupg_records_get_keyid (self->pv->public_records); - const gchar *new_keyid = _gcr_gnupg_records_get_keyid (records); - - if (g_strcmp0 (old_keyid, new_keyid) != 0) { - g_warning ("it is an error to change a gnupg key so that the " - "fingerprint is no longer the same: %s != %s", - old_keyid, new_keyid); - return; - } - } - - g_ptr_array_ref (records); - if (self->pv->public_records) - g_ptr_array_unref (self->pv->public_records); - self->pv->public_records = records; - - obj = G_OBJECT (self); - g_object_freeze_notify (obj); - g_object_notify (obj, "public-records"); - g_object_notify (obj, "label"); - g_object_notify (obj, "markup"); - g_object_thaw_notify (obj); -} - -/** - * _gcr_gnupg_key_get_secret_records: - * @self: The key - * - * Get the record secret data this key is based on. %NULL if a public key. - * - * Returns: (transfer none) (allow-none): An array of GcrColons*. - */ -GPtrArray* -_gcr_gnupg_key_get_secret_records (GcrGnupgKey *self) -{ - g_return_val_if_fail (GCR_IS_GNUPG_KEY (self), NULL); - return self->pv->secret_records; -} - -/** - * _gcr_gnupg_key_set_secret_records: - * @self: The key - * @records: (allow-none): The new array of GcrRecord* - * - * Set the secret data for this key. %NULL if public key. - */ -void -_gcr_gnupg_key_set_secret_records (GcrGnupgKey *self, GPtrArray *records) -{ - GObject *obj; - - g_return_if_fail (GCR_IS_GNUPG_KEY (self)); - - /* Check that it matches public key */ - if (self->pv->public_records && records) { - const gchar *pub_keyid = _gcr_gnupg_records_get_keyid (self->pv->public_records); - const gchar *sec_keyid = _gcr_gnupg_records_get_keyid (records); - - if (g_strcmp0 (pub_keyid, sec_keyid) != 0) { - g_warning ("it is an error to create a gnupg key so that the " - "fingerprint of thet pub and sec parts are not the same: %s != %s", - pub_keyid, sec_keyid); - return; - } - } - - if (records) - g_ptr_array_ref (records); - if (self->pv->secret_records) - g_ptr_array_unref (self->pv->secret_records); - self->pv->secret_records = records; - - obj = G_OBJECT (self); - g_object_freeze_notify (obj); - g_object_notify (obj, "secret-records"); - g_object_thaw_notify (obj); -} - -/** - * _gcr_gnupg_key_get_keyid: - * @self: The key - * - * Get the keyid for this key. - * - * Returns: (transfer none): The keyid. - */ -const gchar* -_gcr_gnupg_key_get_keyid (GcrGnupgKey *self) -{ - g_return_val_if_fail (GCR_IS_GNUPG_KEY (self), NULL); - return _gcr_gnupg_records_get_keyid (self->pv->public_records); -} - -/** - * _gcr_gnupg_key_get_icon: - * @self: A gnupg key. - * - * Get the display icon for this key. - * - * Return value: (transfer none): The icon, owned by the key. - */ -GIcon* -_gcr_gnupg_key_get_icon (GcrGnupgKey *self) -{ - g_return_val_if_fail (GCR_IS_GNUPG_KEY (self), NULL); - - if (self->pv->icon == NULL) { - self->pv->icon = _gcr_gnupg_records_get_icon (self->pv->public_records); - if (self->pv->icon == NULL) { - if (self->pv->secret_records) - self->pv->icon = g_themed_icon_new ("gcr-key-pair"); - else - self->pv->icon = g_themed_icon_new ("gcr-key"); - } - } - - return self->pv->icon; -} - -/** - * _gcr_gnupg_key_get_columns: - * - * Get the columns that we should display for gnupg keys. - * - * Returns: (transfer none): The columns, NULL terminated, should not be freed. - */ -const GcrColumn* -_gcr_gnupg_key_get_columns (void) -{ - static GcrColumn columns[] = { - { "icon", /* later */ 0, /* later */ 0, NULL, 0, NULL, 0 }, - { "label", G_TYPE_STRING, G_TYPE_STRING, NC_("column", "Name"), - GCR_COLUMN_SORTABLE, NULL, 0 }, - { "short-keyid", G_TYPE_STRING, G_TYPE_STRING, NC_("column", "Key ID"), - GCR_COLUMN_SORTABLE, NULL, 0 }, - { NULL } - }; - - columns[0].property_type = columns[0].column_type = G_TYPE_ICON; - return columns; -} diff --git a/gcr/gcr-gnupg-key.h b/gcr/gcr-gnupg-key.h deleted file mode 100644 index 2c120af2..00000000 --- a/gcr/gcr-gnupg-key.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef GCR_GNUPG_KEY_H -#define GCR_GNUPG_KEY_H - -#include <glib-object.h> - -#include "gcr-column.h" -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_GNUPG_KEY_COLUMNS (_gcr_gnupg_key_get_columns ()) -#define GCR_TYPE_GNUPG_KEY (_gcr_gnupg_key_get_type ()) -#define GCR_GNUPG_KEY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_GNUPG_KEY, GcrGnupgKey)) -#define GCR_GNUPG_KEY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_GNUPG_KEY, GcrGnupgKeyClass)) -#define GCR_IS_GNUPG_KEY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_GNUPG_KEY)) -#define GCR_IS_GNUPG_KEY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_GNUPG_KEY)) -#define GCR_GNUPG_KEY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_GNUPG_KEY, GcrGnupgKeyClass)) - -typedef struct _GcrGnupgKey GcrGnupgKey; -typedef struct _GcrGnupgKeyClass GcrGnupgKeyClass; -typedef struct _GcrGnupgKeyPrivate GcrGnupgKeyPrivate; - -struct _GcrGnupgKey { - /*< private >*/ - GObject parent; - GcrGnupgKeyPrivate *pv; -}; - -struct _GcrGnupgKeyClass { - GObjectClass parent_class; -}; - -GType _gcr_gnupg_key_get_type (void); - -const GcrColumn* _gcr_gnupg_key_get_columns (void); - -GcrGnupgKey* _gcr_gnupg_key_new (GPtrArray *pubset, - GPtrArray *secset); - -const gchar* _gcr_gnupg_key_get_keyid (GcrGnupgKey *self); - -GPtrArray* _gcr_gnupg_key_get_public_records (GcrGnupgKey *self); - -void _gcr_gnupg_key_set_public_records (GcrGnupgKey *self, - GPtrArray *records); - -GPtrArray* _gcr_gnupg_key_get_secret_records (GcrGnupgKey *self); - -void _gcr_gnupg_key_set_secret_records (GcrGnupgKey *self, - GPtrArray *records); - -GIcon* _gcr_gnupg_key_get_icon (GcrGnupgKey *self); - -G_END_DECLS - -#endif /* __GCR_GNUPG_KEY_H__ */ diff --git a/gcr/gcr-gnupg-process.c b/gcr/gcr-gnupg-process.c deleted file mode 100644 index 81423da4..00000000 --- a/gcr/gcr-gnupg-process.c +++ /dev/null @@ -1,1157 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#define DEBUG_FLAG GCR_DEBUG_GNUPG -#include "gcr-debug.h" -#include "gcr-gnupg-process.h" -#include "gcr-marshal.h" -#include "gcr-util.h" - -#include <glib/gi18n-lib.h> - -#include <sys/wait.h> -#include <fcntl.h> -#include <errno.h> -#include <string.h> - -/** - * GcrGnupgProcessFlags: - * @GCR_GNUPG_PROCESS_NONE: No flags - * @GCR_GNUPG_PROCESS_RESPECT_LOCALE: Respect the user's locale when running gnupg. - * @GCR_GNUPG_PROCESS_WITH_STATUS: Ask the process to send status records. - * @GCR_GNUPG_PROCESS_WITH_ATTRIBUTES: Ask the process to output attribute data. - * - * Flags for running a gnupg process. - */ - -enum { - PROP_0, - PROP_DIRECTORY, - PROP_EXECUTABLE, - PROP_INPUT_STREAM, - PROP_OUTPUT_STREAM, - PROP_ATTRIBUTE_STREAM -}; - -enum { - FD_INPUT, - FD_OUTPUT, - FD_ERROR, - FD_STATUS, - FD_ATTRIBUTE, - NUM_FDS -}; - -enum { - ERROR_LINE, - STATUS_RECORD, - NUM_SIGNALS -}; - -static gint signals[NUM_SIGNALS] = { 0, }; - -typedef struct _GnupgSource { - GSource source; - GPollFD polls[NUM_FDS]; /* The various fd's we're listening to */ - - GcrGnupgProcess *process; /* Pointer back to the process object */ - - GByteArray *input_buf; - GString *error_buf; - GString *status_buf; - guint source_sig; - - GPid child_pid; - guint child_sig; - - GCancellable *cancellable; - guint cancel_sig; -} GnupgSource; - -struct _GcrGnupgProcessPrivate { - gchar *directory; - gchar *executable; - - GInputStream *input; - GOutputStream *output; - GOutputStream *attributes; - - gboolean running; - gboolean complete; - GError *error; - - GAsyncReadyCallback async_callback; - gpointer user_data; -}; - -/* Forward declarations */ -static void _gcr_gnupg_process_init_async (GAsyncResultIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrGnupgProcess, _gcr_gnupg_process, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, _gcr_gnupg_process_init_async)); - -static void -_gcr_gnupg_process_init (GcrGnupgProcess *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_GNUPG_PROCESS, - GcrGnupgProcessPrivate); -} - -static void -_gcr_gnupg_process_constructed (GObject *obj) -{ - GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj); - - if (G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->constructed) - G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->constructed (obj); - - if (!self->pv->executable) - self->pv->executable = g_strdup (GPG_EXECUTABLE); -} - -static void -_gcr_gnupg_process_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj); - - switch (prop_id) { - case PROP_DIRECTORY: - g_value_set_string (value, self->pv->directory); - break; - case PROP_EXECUTABLE: - g_value_set_string (value, self->pv->executable); - break; - case PROP_INPUT_STREAM: - g_value_set_object (value, _gcr_gnupg_process_get_input_stream (self)); - break; - case PROP_OUTPUT_STREAM: - g_value_set_object (value, _gcr_gnupg_process_get_output_stream (self)); - break; - case PROP_ATTRIBUTE_STREAM: - g_value_set_object (value, _gcr_gnupg_process_get_attribute_stream (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_gnupg_process_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj); - - switch (prop_id) { - case PROP_DIRECTORY: - g_return_if_fail (!self->pv->directory); - self->pv->directory = g_value_dup_string (value); - break; - case PROP_EXECUTABLE: - g_return_if_fail (!self->pv->executable); - self->pv->executable = g_value_dup_string (value); - break; - case PROP_INPUT_STREAM: - _gcr_gnupg_process_set_input_stream (self, g_value_get_object (value)); - break; - case PROP_OUTPUT_STREAM: - _gcr_gnupg_process_set_output_stream (self, g_value_get_object (value)); - break; - case PROP_ATTRIBUTE_STREAM: - _gcr_gnupg_process_set_attribute_stream (self, g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_gnupg_process_dispose (GObject *obj) -{ - GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj); - - g_clear_object (&self->pv->input); - g_clear_object (&self->pv->output); - g_clear_object (&self->pv->attributes); - - G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->dispose (obj); -} - -static void -_gcr_gnupg_process_finalize (GObject *obj) -{ - GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj); - - g_assert (!self->pv->running); - g_free (self->pv->directory); - g_free (self->pv->executable); - g_clear_error (&self->pv->error); - - G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->finalize (obj); -} - -static void -_gcr_gnupg_process_class_init (GcrGnupgProcessClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->constructed = _gcr_gnupg_process_constructed; - gobject_class->get_property = _gcr_gnupg_process_get_property; - gobject_class->set_property = _gcr_gnupg_process_set_property; - gobject_class->dispose = _gcr_gnupg_process_dispose; - gobject_class->finalize = _gcr_gnupg_process_finalize; - - /** - * GcrGnupgProcess:directory: - * - * Directory to run as gnupg home directory, or %NULL for default - * ~/.gnupg/ directory. - */ - g_object_class_install_property (gobject_class, PROP_DIRECTORY, - g_param_spec_string ("directory", "Directory", "Gnupg Directory", - NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - /** - * GcrGnupgProcess:executable: - * - * Path to the gnupg executable, or %NULL for default. - */ - g_object_class_install_property (gobject_class, PROP_EXECUTABLE, - g_param_spec_string ("executable", "Executable", "Gnupg Executable", - GPG_EXECUTABLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - /** - * GcrGnupgProcess:input-stream: - * - * Input for gnupg, or %NULL for no input. - */ - g_object_class_install_property (gobject_class, PROP_INPUT_STREAM, - g_param_spec_object ("input-stream", "Input Stream", "Input Stream", - G_TYPE_INPUT_STREAM, G_PARAM_READWRITE)); - - /** - * GcrGnupgProcess:output-stream: - * - * Output from gnupg, or %NULL for ignored output. - */ - g_object_class_install_property (gobject_class, PROP_OUTPUT_STREAM, - g_param_spec_object ("output-stream", "Output Stream", "Output Stream", - G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE)); - - /** - * GcrGnupgProcess:attribute-stream: - * - * Output of attribute data from gnupg, or %NULL for ignored attributes. - */ - g_object_class_install_property (gobject_class, PROP_ATTRIBUTE_STREAM, - g_param_spec_object ("attribute-stream", "Attribute Stream", "Attribute Stream", - G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE)); - - /** - * GcrGnupgProcess::error-line: - * @line: a line of error output. - * - * Signal emitted when a line of error output is available from the - * gnupg process. - */ - signals[ERROR_LINE] = g_signal_new ("error-line", GCR_TYPE_GNUPG_PROCESS, - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, error_line), - NULL, NULL, _gcr_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); - - /** - * GcrGnupgProcess::status-record: - * @record: a status record. - * - * Signal emitted when a status record is available from the gnupg process. - */ - signals[STATUS_RECORD] = g_signal_new ("status-record", GCR_TYPE_GNUPG_PROCESS, - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, status_record), - NULL, NULL, _gcr_marshal_VOID__BOXED, - G_TYPE_NONE, 1, GCR_TYPE_RECORD); - - g_type_class_add_private (gobject_class, sizeof (GcrGnupgProcessPrivate)); -} - -static gpointer -_gcr_gnupg_process_get_user_data (GAsyncResult *result) -{ - g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (result), NULL); - return GCR_GNUPG_PROCESS (result)->pv->user_data; -} - -static GObject* -_gcr_gnupg_process_get_source_object (GAsyncResult *result) -{ - g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (result), NULL); - return G_OBJECT (result); -} - -static void -_gcr_gnupg_process_init_async (GAsyncResultIface *iface) -{ - iface->get_source_object = _gcr_gnupg_process_get_source_object; - iface->get_user_data = _gcr_gnupg_process_get_user_data; -} - -/** - * _gcr_gnupg_process_new: - * @directory: (allow-none): The gnupg home directory - * @executable: (allow-none): The gpg executable - * - * Create a new GcrGnupgProcess. - * - * The gnupg home directory is where the keyring files live. If directory is - * %NULL then the default gnupg home directory is used. - * - * The executable will default to the compiled in path if a %NULL executable - * argument is used. - * - * Returns: (transfer full): A newly allocated process. - */ -GcrGnupgProcess* -_gcr_gnupg_process_new (const gchar *directory, const gchar *executable) -{ - return g_object_new (GCR_TYPE_GNUPG_PROCESS, - "directory", directory, - "executable", executable, - NULL); -} - -const gchar * -_gcr_gnupg_process_get_directory (GcrGnupgProcess *self) -{ - g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL); - return self->pv->directory; -} - -GInputStream * -_gcr_gnupg_process_get_input_stream (GcrGnupgProcess *self) -{ - g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL); - return self->pv->input; -} - -void -_gcr_gnupg_process_set_input_stream (GcrGnupgProcess *self, - GInputStream *input) -{ - g_return_if_fail (GCR_GNUPG_PROCESS (self)); - g_return_if_fail (input == NULL || G_INPUT_STREAM (input)); - - if (input) - g_object_ref (input); - if (self->pv->input) - g_object_unref (self->pv->input); - self->pv->input = input; - g_object_notify (G_OBJECT (self), "input-stream"); -} - -GOutputStream * -_gcr_gnupg_process_get_output_stream (GcrGnupgProcess *self) -{ - g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL); - return self->pv->output; -} - -void -_gcr_gnupg_process_set_output_stream (GcrGnupgProcess *self, - GOutputStream *output) -{ - g_return_if_fail (GCR_GNUPG_PROCESS (self)); - g_return_if_fail (output == NULL || G_OUTPUT_STREAM (output)); - - if (output) - g_object_ref (output); - if (self->pv->output) - g_object_unref (self->pv->output); - self->pv->output = output; - g_object_notify (G_OBJECT (self), "output-stream"); -} - -GOutputStream * -_gcr_gnupg_process_get_attribute_stream (GcrGnupgProcess *self) -{ - g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL); - return self->pv->attributes; -} - -void -_gcr_gnupg_process_set_attribute_stream (GcrGnupgProcess *self, - GOutputStream *output) -{ - g_return_if_fail (GCR_GNUPG_PROCESS (self)); - g_return_if_fail (output == NULL || G_OUTPUT_STREAM (output)); - - if (output) - g_object_ref (output); - if (self->pv->attributes) - g_object_unref (self->pv->attributes); - self->pv->attributes = output; - g_object_notify (G_OBJECT (self), "attribute-stream"); -} - -static void -run_async_ready_callback (GcrGnupgProcess *self) -{ - GAsyncReadyCallback callback; - gpointer user_data; - - _gcr_debug ("running async callback"); - - /* Remove these before completing */ - callback = self->pv->async_callback; - user_data = self->pv->user_data; - self->pv->async_callback = NULL; - self->pv->user_data = NULL; - - if (callback != NULL) - (callback) (G_OBJECT (self), G_ASYNC_RESULT (self), user_data); -} - -static gboolean -on_run_async_ready_callback_later (gpointer user_data) -{ - run_async_ready_callback (GCR_GNUPG_PROCESS (user_data)); - return FALSE; /* Don't run this callback again */ -} - -static void -run_async_ready_callback_later (GcrGnupgProcess *self) -{ - _gcr_debug ("running async callback later"); - g_idle_add_full (G_PRIORITY_DEFAULT, on_run_async_ready_callback_later, - g_object_ref (self), g_object_unref); -} - -static void -complete_run_process (GcrGnupgProcess *self) -{ - g_return_if_fail (self->pv->running); - g_return_if_fail (!self->pv->complete); - - self->pv->running = FALSE; - self->pv->complete = TRUE; - - if (self->pv->error == NULL) { - _gcr_debug ("completed process"); - } else { - _gcr_debug ("completed process with error: %s", - self->pv->error->message); - } -} - -static gboolean -complete_source_is_done (GnupgSource *gnupg_source) -{ - _gcr_debug ("all fds closed and process exited, completing"); - - g_assert (gnupg_source->child_sig == 0); - g_assert (gnupg_source->source_sig == 0); - - complete_run_process (gnupg_source->process); - run_async_ready_callback (gnupg_source->process); - - /* All done, the source can go away now */ - g_source_unref ((GSource*)gnupg_source); - return TRUE; -} - -static void -close_fd (int *fd) -{ - g_assert (fd); - if (*fd >= 0) { - _gcr_debug ("closing fd: %d", *fd); - close (*fd); - } - *fd = -1; -} - -static void -close_poll (GSource *source, GPollFD *poll) -{ - g_source_remove_poll (source, poll); - close_fd (&poll->fd); - poll->revents = 0; -} - -static gboolean -unused_callback (gpointer data) -{ - /* Never called */ - g_assert_not_reached (); - return FALSE; -} - -static gboolean -on_gnupg_source_prepare (GSource *source, gint *timeout_) -{ - GnupgSource *gnupg_source = (GnupgSource*)source; - gint i; - - for (i = 0; i < NUM_FDS; ++i) { - if (gnupg_source->polls[i].fd >= 0) - return FALSE; - } - - /* If none of the FDs are valid, then process immediately */ - return TRUE; -} - -static gboolean -on_gnupg_source_check (GSource *source) -{ - GnupgSource *gnupg_source = (GnupgSource*)source; - gint i; - - for (i = 0; i < NUM_FDS; ++i) { - if (gnupg_source->polls[i].fd >= 0 && gnupg_source->polls[i].revents != 0) - return TRUE; - } - return FALSE; -} - -static void -on_gnupg_source_finalize (GSource *source) -{ - GnupgSource *gnupg_source = (GnupgSource*)source; - gint i; - - if (gnupg_source->cancel_sig) - g_signal_handler_disconnect (gnupg_source->cancellable, gnupg_source->cancel_sig); - if (gnupg_source->cancellable) - g_object_unref (gnupg_source->cancellable); - - for (i = 0; i < NUM_FDS; ++i) - close_fd (&gnupg_source->polls[i].fd); - - g_object_unref (gnupg_source->process); - if (gnupg_source->input_buf) - g_byte_array_free (gnupg_source->input_buf, TRUE); - g_string_free (gnupg_source->error_buf, TRUE); - g_string_free (gnupg_source->status_buf, TRUE); - - g_assert (!gnupg_source->child_pid); - g_assert (!gnupg_source->child_sig); -} - -static gboolean -read_output (int fd, GByteArray *buffer) -{ - guchar block[1024]; - gssize result; - - g_return_val_if_fail (fd >= 0, FALSE); - - do { - result = read (fd, block, sizeof (block)); - if (result < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - return FALSE; - } else { - g_byte_array_append (buffer, block, result); - } - } while (result == sizeof (block)); - - return TRUE; -} - -static gboolean -write_input (int fd, GByteArray *buffer) -{ - gssize result; - - g_return_val_if_fail (fd >= 0, FALSE); - - for (;;) { - result = write (fd, buffer->data, buffer->len); - if (result < 0) { - if (errno == EINTR || errno == EAGAIN) - continue; - return FALSE; - } else { - g_byte_array_remove_range (buffer, 0, result); - return TRUE; - } - } -} - -static void -emit_status_for_each_line (const gchar *line, gpointer user_data) -{ - GcrRecord *record; - - if (g_str_has_prefix (line, "[GNUPG:] ")) { - _gcr_debug ("received status line: %s", line); - line += 9; - } else { - g_message ("gnupg status record was not prefixed appropriately: %s", line); - return; - } - - record = _gcr_record_parse_spaces (line, -1); - if (!record) { - g_message ("couldn't parse status record: %s", line); - return; - } - - g_signal_emit (GCR_GNUPG_PROCESS (user_data), signals[STATUS_RECORD], 0, record); - _gcr_record_free (record); -} - -static void -emit_error_for_each_line (const gchar *line, gpointer user_data) -{ - _gcr_debug ("received error line: %s", line); - g_signal_emit (GCR_GNUPG_PROCESS (user_data), signals[ERROR_LINE], 0, line); -} - -static gboolean -on_gnupg_source_input (GcrGnupgProcess *self, - GnupgSource *gnupg_source, - gint fd) -{ - gssize read; - - if (gnupg_source->input_buf == NULL || - gnupg_source->input_buf->len == 0) { - if (self->pv->input == NULL) - return FALSE; - if (!gnupg_source->input_buf) - gnupg_source->input_buf = g_byte_array_new (); - g_byte_array_set_size (gnupg_source->input_buf, 4096); - read = g_input_stream_read (self->pv->input, - gnupg_source->input_buf->data, - gnupg_source->input_buf->len, - gnupg_source->cancellable, NULL); - g_byte_array_set_size (gnupg_source->input_buf, read < 0 ? 0 : read); - if (read < 0) - return FALSE; - if (read == 0) - return FALSE; - } - - if (!write_input (fd, gnupg_source->input_buf)) { - g_warning ("couldn't write output data to gnupg process"); - return FALSE; - } - - return TRUE; -} - -static gboolean -on_gnupg_source_status (GcrGnupgProcess *self, - GnupgSource *gnupg_source, - gint fd) -{ - GByteArray *buffer = g_byte_array_new (); - gboolean result = TRUE; - - if (!read_output (fd, buffer)) { - g_warning ("couldn't read status data from gnupg process"); - result = FALSE; - } else { - g_string_append_len (gnupg_source->status_buf, (gchar*)buffer->data, buffer->len); - _gcr_util_parse_lines (gnupg_source->status_buf, buffer->len == 0, - emit_status_for_each_line, self); - } - - g_byte_array_unref (buffer); - return result; -} - -static gboolean -on_gnupg_source_attribute (GcrGnupgProcess *self, - GnupgSource *gnupg_source, - gint fd) -{ - GByteArray *buffer = g_byte_array_new (); - gboolean result = TRUE; - - if (!read_output (fd, buffer)) { - g_warning ("couldn't read attribute data from gnupg process"); - result = FALSE; - } else if (buffer->len > 0) { - _gcr_debug ("received %d bytes of attribute data", (gint)buffer->len); - if (self->pv->attributes != NULL) - g_output_stream_write_all (self->pv->attributes, buffer->data, - buffer->len, NULL, - gnupg_source->cancellable, NULL); - } - - g_byte_array_unref (buffer); - return result; -} - -static gboolean -on_gnupg_source_output (GcrGnupgProcess *self, - GnupgSource *gnupg_source, - gint fd) -{ - GByteArray *buffer = g_byte_array_new (); - gboolean result = TRUE; - - if (!read_output (fd, buffer)) { - g_warning ("couldn't read output data from gnupg process"); - result = FALSE; - } else if (buffer->len > 0) { - _gcr_debug ("received %d bytes of output data", (gint)buffer->len); - if (self->pv->output != NULL) - g_output_stream_write_all (self->pv->output, buffer->data, buffer->len, - NULL, gnupg_source->cancellable, NULL); - } - - g_byte_array_unref (buffer); - return result; -} - -static gboolean -on_gnupg_source_error (GcrGnupgProcess *self, - GnupgSource *gnupg_source, - gint fd, - gboolean last) -{ - GByteArray *buffer = g_byte_array_new (); - gboolean result = TRUE; - - if (!read_output (fd, buffer)) { - g_warning ("couldn't read error data from gnupg process"); - result = FALSE; - } else { - g_string_append_len (gnupg_source->error_buf, (gchar*)buffer->data, buffer->len); - _gcr_util_parse_lines (gnupg_source->error_buf, last, - emit_error_for_each_line, gnupg_source->process); - } - - g_byte_array_unref (buffer); - return result; -} - -static gboolean -on_gnupg_source_dispatch (GSource *source, GSourceFunc unused, gpointer user_data) -{ - GnupgSource *gnupg_source = (GnupgSource*)source; - GcrGnupgProcess *self = gnupg_source->process; - GPollFD *poll; - guint i; - - /* Standard input, no support yet */ - poll = &gnupg_source->polls[FD_INPUT]; - if (poll->fd >= 0) { - if (poll->revents & G_IO_OUT) - if (!on_gnupg_source_input (self, gnupg_source, poll->fd)) - poll->revents |= G_IO_HUP; - if (poll->revents & G_IO_HUP) - close_poll (source, poll); - poll->revents = 0; - } - - /* Status output */ - poll = &gnupg_source->polls[FD_STATUS]; - if (poll->fd >= 0) { - if (poll->revents & G_IO_IN) - if (!on_gnupg_source_status (self, gnupg_source, poll->fd)) - poll->revents |= G_IO_HUP; - if (poll->revents & G_IO_HUP) - close_poll (source, poll); - poll->revents = 0; - } - - /* Attribute output */ - poll = &gnupg_source->polls[FD_ATTRIBUTE]; - if (poll->fd >= 0) { - if (poll->revents & G_IO_IN) - if (!on_gnupg_source_attribute (self, gnupg_source, poll->fd)) - poll->revents |= G_IO_HUP; - if (poll->revents & G_IO_HUP) - close_poll (source, poll); - poll->revents = 0; - } - - /* Standard output */ - poll = &gnupg_source->polls[FD_OUTPUT]; - if (poll->fd >= 0) { - if (poll->revents & G_IO_IN) - if (!on_gnupg_source_output (self, gnupg_source, poll->fd)) - poll->revents |= G_IO_HUP; - if (poll->revents & G_IO_HUP) - close_poll (source, poll); - poll->revents = 0; - } - - /* Standard error */ - poll = &gnupg_source->polls[FD_ERROR]; - if (poll->fd >= 0) { - if (poll->revents & G_IO_IN) - if (!on_gnupg_source_error (self, gnupg_source, poll->fd, - (poll->revents & G_IO_HUP) ? TRUE : FALSE)) - poll->revents |= G_IO_HUP; - if (poll->revents & G_IO_HUP) - close_poll (source, poll); - poll->revents = 0; - } - - for (i = 0; i < NUM_FDS; ++i) { - if (gnupg_source->polls[i].fd >= 0) - return TRUE; - } - - /* Because we return below */ - gnupg_source->source_sig = 0; - - if (!gnupg_source->child_pid) - complete_source_is_done (gnupg_source); - - return FALSE; /* Disconnect this source */ -} - -static GSourceFuncs gnupg_source_funcs = { - on_gnupg_source_prepare, - on_gnupg_source_check, - on_gnupg_source_dispatch, - on_gnupg_source_finalize, -}; - -static void -on_gnupg_process_child_exited (GPid pid, gint status, gpointer user_data) -{ - GnupgSource *gnupg_source = user_data; - GcrGnupgProcess *self = gnupg_source->process; - GError *error = NULL; - gint code; - guint i; - - _gcr_debug ("process exited: %d", (int)pid); - - g_spawn_close_pid (gnupg_source->child_pid); - gnupg_source->child_pid = 0; - gnupg_source->child_sig = 0; - - if (WIFEXITED (status)) { - code = WEXITSTATUS (status); - if (code != 0) { - error = g_error_new (G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Gnupg process exited with code: %d"), code); - } - } else if (WIFSIGNALED (status)) { - code = WTERMSIG (status); - /* Ignore cases where we've signaled the process because we were cancelled */ - if (!g_error_matches (self->pv->error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - error = g_error_new (G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, - _("Gnupg process was terminated with signal: %d"), code); - } - - /* Take this as the async result error */ - if (error && !self->pv->error) { - _gcr_debug ("%s", error->message); - self->pv->error = error; - - /* Already have an error, just print out message */ - } else if (error) { - g_warning ("%s", error->message); - g_error_free (error); - } - - for (i = 0; i < NUM_FDS; ++i) { - if (gnupg_source->polls[i].fd >= 0) - return; - } - - complete_source_is_done (gnupg_source); -} - -static void -on_gnupg_process_child_setup (gpointer user_data) -{ - int *child_fds = user_data; - long val; - guint i; - - /* - * Clear close-on-exec flag for these file descriptors, so that - * gnupg can write to them - */ - - for (i = 0; i < NUM_FDS; i++) { - if (child_fds[i] >= 0) { - val = fcntl (child_fds[i], F_GETFD); - fcntl (child_fds[i], F_SETFD, val & ~FD_CLOEXEC); - } - } -} - -static void -on_cancellable_cancelled (GCancellable *cancellable, gpointer user_data) -{ - GnupgSource *gnupg_source = user_data; - - g_assert (gnupg_source->process); - - _gcr_debug ("process cancelled"); - - /* Set an error, which is respected when this actually completes. */ - if (gnupg_source->process->pv->error == NULL) - gnupg_source->process->pv->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, - _("The operation was cancelled")); - - /* Try and kill the child process */ - if (gnupg_source->child_pid) { - _gcr_debug ("sending term signal to process: %d", - (int)gnupg_source->child_pid); - kill (gnupg_source->child_pid, SIGTERM); - } -} - -/** - * _gcr_gnupg_process_run_async: - * @self: The process - * @argv: (array zero-terminated=1): The arguments for the process, not including executable, terminated with %NULL. - * @envp: (allow-none) (array zero-terminated=1): The environment for new process, terminated with %NULL. - * @flags: Flags for starting the process. - * @cancellable: (allow-none): Cancellation object - * @callback: Will be called when operation completes. - * @user_data: (closure): Data passed to callback. - * - * Run the gpg process. Only one 'run' operation can run per GcrGnupgProcess - * object. The GcrGnupgProcess:output_data and GcrGnupgProcess:error_line - * signals will be emitted when data is received from the gpg process. - * - * Unless the %GCR_GNUPG_PROCESS_RESPECT_LOCALE flag is specified, the process - * will be run in the 'C' locale. If the %GCR_GNUPG_PROCESS_WITH_STATUS or - * %GCR_GNUPG_PROCESS_WITH_ATTRIBUTES flags are set, then the gpg process - * will be status and attribute output respectively. The - * GcrGnupgProcess:status_record and GcrGnupgProcess:attribute_data signals - * will provide this data. - */ -void -_gcr_gnupg_process_run_async (GcrGnupgProcess *self, const gchar **argv, const gchar **envp, - GcrGnupgProcessFlags flags, GCancellable *cancellable, - GAsyncReadyCallback callback, gpointer user_data) -{ - GError *error = NULL; - GPtrArray *args; - GPtrArray *envs; - int child_fds[NUM_FDS]; - int status_fds[2] = { -1, -1 }; - int attribute_fds[2] = { -1, -1 }; - int output_fd = -1; - int error_fd = -1; - int input_fd = -1; - GnupgSource *gnupg_source; - GSource *source; - GPid pid; - guint i; - - g_return_if_fail (GCR_IS_GNUPG_PROCESS (self)); - g_return_if_fail (argv); - g_return_if_fail (callback); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - g_return_if_fail (self->pv->running == FALSE); - g_return_if_fail (self->pv->complete == FALSE); - g_return_if_fail (self->pv->executable); - - self->pv->async_callback = callback; - self->pv->user_data = user_data; - - for (i = 0; i < NUM_FDS; i++) - child_fds[i] = -1; - - /* The command needs to be updated with these status and attribute fds */ - args = g_ptr_array_new_with_free_func (g_free); - g_ptr_array_add (args, g_strdup (self->pv->executable)); - - /* Spawn/child will close all other attributes, besides thesthose in child_fds */ - child_fds[FD_INPUT] = 0; - child_fds[FD_OUTPUT] = 1; - child_fds[FD_ERROR] = 2; - - if (flags & GCR_GNUPG_PROCESS_WITH_STATUS) { - if (pipe (status_fds) < 0) - g_return_if_reached (); - child_fds[FD_STATUS] = status_fds[1]; - g_ptr_array_add (args, g_strdup ("--status-fd")); - g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_STATUS])); - } - if (flags & GCR_GNUPG_PROCESS_WITH_ATTRIBUTES) { - if (pipe (attribute_fds) < 0) - g_return_if_reached (); - child_fds[FD_ATTRIBUTE] = attribute_fds[1]; - g_ptr_array_add (args, g_strdup ("--attribute-fd")); - g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_ATTRIBUTE])); - } - - if (self->pv->directory) { - g_ptr_array_add (args, g_strdup ("--homedir")); - g_ptr_array_add (args, g_strdup (self->pv->directory)); - } - - /* All the remaining arguments */ - for (i = 0; argv[i] != NULL; i++) - g_ptr_array_add (args, g_strdup (argv[i])); - g_ptr_array_add (args, NULL); - - envs = g_ptr_array_new (); - for (i = 0; envp && envp[i] != NULL; i++) { - if (flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE || - !g_str_has_prefix (envp[i], "LOCALE=")) - g_ptr_array_add (envs, (gpointer)envp[i]); - } - if (!(flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE)) - g_ptr_array_add (envs, (gpointer)"LOCALE=C"); - g_ptr_array_add (envs, NULL); - - if (_gcr_debugging) { - gchar *command = g_strjoinv (" ", (gchar**)args->pdata); - gchar *environ = g_strjoinv (", ", (gchar**)envs->pdata); - _gcr_debug ("running command: %s", command); - _gcr_debug ("process environment: %s", environ); - g_free (command); - g_free (environ); - } - - g_spawn_async_with_pipes (self->pv->directory, (gchar**)args->pdata, - (gchar**)envs->pdata, G_SPAWN_DO_NOT_REAP_CHILD, - on_gnupg_process_child_setup, child_fds, - &pid, &input_fd, &output_fd, &error_fd, &error); - - g_ptr_array_free (args, TRUE); - g_ptr_array_free (envs, TRUE); - - /* Close 'wrong' ends of extra file descriptors */ - close_fd (&(status_fds[1])); - close_fd (&(attribute_fds[1])); - - self->pv->complete = FALSE; - self->pv->running = TRUE; - - if (error) { - close_fd (&(status_fds[0])); - close_fd (&(attribute_fds[0])); - g_assert (!self->pv->error); - self->pv->error = error; - complete_run_process (self); - run_async_ready_callback_later (self); - return; - } - - _gcr_debug ("process started: %d", (int)pid); - - source = g_source_new (&gnupg_source_funcs, sizeof (GnupgSource)); - - /* Initialize the source */ - gnupg_source = (GnupgSource*)source; - for (i = 0; i < NUM_FDS; i++) - gnupg_source->polls[i].fd = -1; - gnupg_source->error_buf = g_string_sized_new (128); - gnupg_source->status_buf = g_string_sized_new (128); - gnupg_source->process = g_object_ref (self); - gnupg_source->child_pid = pid; - - gnupg_source->polls[FD_INPUT].fd = input_fd; - if (input_fd >= 0) { - gnupg_source->polls[FD_INPUT].events = G_IO_HUP | G_IO_OUT; - g_source_add_poll (source, &gnupg_source->polls[FD_INPUT]); - } - gnupg_source->polls[FD_OUTPUT].fd = output_fd; - if (output_fd >= 0) { - gnupg_source->polls[FD_OUTPUT].events = G_IO_HUP | G_IO_IN; - g_source_add_poll (source, &gnupg_source->polls[FD_OUTPUT]); - } - gnupg_source->polls[FD_ERROR].fd = error_fd; - if (error_fd >= 0) { - gnupg_source->polls[FD_ERROR].events = G_IO_HUP | G_IO_IN; - g_source_add_poll (source, &gnupg_source->polls[FD_ERROR]); - } - gnupg_source->polls[FD_STATUS].fd = status_fds[0]; - if (status_fds[0] >= 0) { - gnupg_source->polls[FD_STATUS].events = G_IO_HUP | G_IO_IN; - g_source_add_poll (source, &gnupg_source->polls[FD_STATUS]); - } - gnupg_source->polls[FD_ATTRIBUTE].fd = attribute_fds[0]; - if (attribute_fds[0] >= 0) { - gnupg_source->polls[FD_ATTRIBUTE].events = G_IO_HUP | G_IO_IN; - g_source_add_poll (source, &gnupg_source->polls[FD_ATTRIBUTE]); - } - - if (cancellable) { - gnupg_source->cancellable = g_object_ref (cancellable); - gnupg_source->cancel_sig = g_cancellable_connect (cancellable, - G_CALLBACK (on_cancellable_cancelled), - g_source_ref (source), - (GDestroyNotify)g_source_unref); - } - - g_source_set_callback (source, unused_callback, NULL, NULL); - gnupg_source->source_sig = g_source_attach (source, g_main_context_default ()); - - /* This assumes the outstanding reference to source */ - g_assert (!gnupg_source->child_sig); - gnupg_source->child_sig = g_child_watch_add_full (G_PRIORITY_DEFAULT, pid, - on_gnupg_process_child_exited, - g_source_ref (source), - (GDestroyNotify)g_source_unref); - - /* source is unreffed in complete_if_source_is_done() */ -} - -/** - * _gcr_gnupg_process_run_finish: - * @self: The process - * @result: The result passed to the callback - * @error: Location to raise an error on failure. - * - * Get the result of running a gnupg process. - * - * Return value: Whether the Gnupg process was run or not. - */ -gboolean -_gcr_gnupg_process_run_finish (GcrGnupgProcess *self, GAsyncResult *result, - GError **error) -{ - g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (self), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - g_return_val_if_fail (G_ASYNC_RESULT (self) == result, FALSE); - g_return_val_if_fail (self->pv->complete, FALSE); - - /* This allows the process to run again... */ - self->pv->complete = FALSE; - - g_assert (!self->pv->running); - g_assert (!self->pv->async_callback); - g_assert (!self->pv->user_data); - - if (self->pv->error) { - g_propagate_error (error, self->pv->error); - self->pv->error = NULL; - return FALSE; - } - - return TRUE; -} diff --git a/gcr/gcr-gnupg-process.h b/gcr/gcr-gnupg-process.h deleted file mode 100644 index 61e4894b..00000000 --- a/gcr/gcr-gnupg-process.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef GCR_GNUPG_PROCESS_H -#define GCR_GNUPG_PROCESS_H - -#include "gcr-base.h" -#include "gcr-record.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_GNUPG_PROCESS (_gcr_gnupg_process_get_type ()) -#define GCR_GNUPG_PROCESS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_GNUPG_PROCESS, GcrGnupgProcess)) -#define GCR_GNUPG_PROCESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_GNUPG_PROCESS, GcrGnupgProcessClass)) -#define GCR_IS_GNUPG_PROCESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_GNUPG_PROCESS)) -#define GCR_IS_GNUPG_PROCESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_GNUPG_PROCESS)) -#define GCR_GNUPG_PROCESS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_GNUPG_PROCESS, GcrGnupgProcessClass)) - -typedef struct _GcrGnupgProcess GcrGnupgProcess; -typedef struct _GcrGnupgProcessClass GcrGnupgProcessClass; -typedef struct _GcrGnupgProcessPrivate GcrGnupgProcessPrivate; - -struct _GcrGnupgProcess { - /*< private >*/ - GObject parent; - GcrGnupgProcessPrivate *pv; -}; - -struct _GcrGnupgProcessClass { - GObjectClass parent_class; - - /* signals */ - gboolean (*error_line) (GcrGnupgProcess *self, const gchar *line); - - gboolean (*status_record) (GcrGnupgProcess *self, GcrRecord *record); -}; - -typedef enum { - GCR_GNUPG_PROCESS_NONE = 0, - GCR_GNUPG_PROCESS_RESPECT_LOCALE = 1 << 0, - GCR_GNUPG_PROCESS_WITH_STATUS = 1 << 1, - GCR_GNUPG_PROCESS_WITH_ATTRIBUTES = 1 << 2 -} GcrGnupgProcessFlags; - -GType _gcr_gnupg_process_get_type (void) G_GNUC_CONST; - -GcrGnupgProcess* _gcr_gnupg_process_new (const gchar *directory, - const gchar *executable); - -const gchar * _gcr_gnupg_process_get_directory (GcrGnupgProcess *self); - -GInputStream * _gcr_gnupg_process_get_input_stream (GcrGnupgProcess *self); - -void _gcr_gnupg_process_set_input_stream (GcrGnupgProcess *self, - GInputStream *input); - -GOutputStream * _gcr_gnupg_process_get_output_stream (GcrGnupgProcess *self); - -void _gcr_gnupg_process_set_output_stream (GcrGnupgProcess *self, - GOutputStream *output); - -GOutputStream * _gcr_gnupg_process_get_attribute_stream (GcrGnupgProcess *self); - -void _gcr_gnupg_process_set_attribute_stream (GcrGnupgProcess *self, - GOutputStream *output); - -void _gcr_gnupg_process_run_async (GcrGnupgProcess *self, - const gchar **argv, - const gchar **envp, - GcrGnupgProcessFlags flags, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean _gcr_gnupg_process_run_finish (GcrGnupgProcess *self, - GAsyncResult *result, - GError **error); - -G_END_DECLS - -#endif /* GCR_GNUPG_PROCESS_H */ diff --git a/gcr/gcr-gnupg-records.c b/gcr/gcr-gnupg-records.c deleted file mode 100644 index e634b1f1..00000000 --- a/gcr/gcr-gnupg-records.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-gnupg-records.h" -#include "gcr-record.h" -#include "gcr-memory-icon.h" - -#include "gck/gck.h" - -#include <glib/gi18n-lib.h> - -/* Copied from GPGME */ -gboolean -_gcr_gnupg_records_parse_user_id (const gchar *user_id, - gchar **rname, - gchar **remail, - gchar **rcomment) -{ - gchar *src, *tail, *x; - int in_name = 0; - int in_email = 0; - int in_comment = 0; - gboolean anything; - const gchar *name = NULL; - const gchar *email = NULL; - const gchar *comment = NULL; - - x = tail = src = g_strdup (user_id); - - while (*src) { - if (in_email) { - /* Not legal but anyway. */ - if (*src == '<') - in_email++; - else if (*src == '>') { - if (!--in_email && !email) { - email = tail; - *src = 0; - tail = src + 1; - } - } - } else if (in_comment) { - if (*src == '(') - in_comment++; - else if (*src == ')') { - if (!--in_comment && !comment) { - comment = tail; - *src = 0; - tail = src + 1; - } - } - } else if (*src == '<') { - if (in_name) { - if (!name) { - name = tail; - *src = 0; - tail = src + 1; - } - in_name = 0; - } else - tail = src + 1; - - in_email = 1; - } else if (*src == '(') { - if (in_name) { - if (!name) { - name = tail; - *src = 0; - tail = src + 1; - } - in_name = 0; - } - in_comment = 1; - } else if (!in_name && *src != ' ' && *src != '\t') { - in_name = 1; - } - src++; - } - - if (in_name) { - if (!name) { - name = tail; - *src = 0; - tail = src + 1; - } - } - - anything = FALSE; - - if (rname) { - *rname = g_strdup (name); - if (name) { - g_strstrip (*rname); - anything = TRUE; - } - } - - if (remail) { - *remail = g_strdup (email); - if (email) { - g_strstrip (*remail); - anything = TRUE; - } - } - - if (rcomment) { - *rcomment = g_strdup (comment); - if (comment) { - g_strstrip (*rcomment); - anything = TRUE; - } - } - - g_free (x); - return anything; -} - -const gchar * -_gcr_gnupg_records_get_keyid (GPtrArray *records) -{ - GcrRecord *record; - - record = _gcr_records_find (records, GCR_RECORD_SCHEMA_PUB); - if (record != NULL) - return _gcr_record_get_raw (record, GCR_RECORD_KEY_KEYID); - record = _gcr_records_find (records, GCR_RECORD_SCHEMA_SEC); - if (record != NULL) - return _gcr_record_get_raw (record, GCR_RECORD_KEY_KEYID); - return NULL; -} - -const gchar * -_gcr_gnupg_records_get_short_keyid (GPtrArray *records) -{ - const gchar *keyid; - gsize length; - - keyid = _gcr_gnupg_records_get_keyid (records); - if (keyid == NULL) - return NULL; - - length = strlen (keyid); - if (length > 8) - keyid += (length - 8); - - return keyid; -} - -gchar * -_gcr_gnupg_records_get_user_id (GPtrArray *records) -{ - GcrRecord *record; - - record = _gcr_records_find (records, GCR_RECORD_SCHEMA_UID); - if (record != NULL) - return _gcr_record_get_string (record, GCR_RECORD_UID_USERID); - return NULL; -} - -const gchar * -_gcr_gnupg_records_get_fingerprint (GPtrArray *records) -{ - GcrRecord *record; - - record = _gcr_records_find (records, GCR_RECORD_SCHEMA_FPR); - if (record != NULL) - return _gcr_record_get_raw (record, GCR_RECORD_FPR_FINGERPRINT); - return NULL; -} - -#define TYPE_IMAGE 0x01 -#define IMAGE_HEADER_LEN 0x10 -#define IMAGE_JPEG_SIG "\x10\x00\x01\x01" -#define IMAGE_JPEG_SIG_LEN 4 - -static void -add_emblem_to_icon (GIcon **icon, - const gchar *emblem_name) -{ - GIcon *emblem_icon; - GIcon *result; - GEmblem *emblem; - - emblem_icon = g_themed_icon_new (emblem_name); - emblem = g_emblem_new_with_origin (emblem_icon, G_EMBLEM_ORIGIN_LIVEMETADATA); - result = g_emblemed_icon_new (*icon, emblem); - g_object_unref (*icon); - *icon = result; - g_object_unref (emblem); - g_object_unref (emblem_icon); -} - -GIcon * -_gcr_gnupg_records_get_icon (GPtrArray *records) -{ - GcrRecord *record; - gchar validity; - guchar *data; - gsize n_data; - guint type; - GIcon *icon; - guint i; - - for (i = 0; i < records->len; i++) { - record = records->pdata[i]; - if (GCR_RECORD_SCHEMA_XA1 != _gcr_record_get_schema (record)) - continue; - if (!_gcr_record_get_uint (record, GCR_RECORD_XA1_TYPE, &type)) - continue; - if (type != TYPE_IMAGE) - continue; - - data = _gcr_record_get_base64 (record, GCR_RECORD_XA1_DATA, &n_data); - g_return_val_if_fail (data != NULL, NULL); - - /* Header is 16 bytes long */ - if (n_data <= IMAGE_HEADER_LEN) { - g_free (data); - continue; - } - - /* These are the header bytes. See gnupg doc/DETAILS */ - g_assert (IMAGE_JPEG_SIG_LEN < IMAGE_HEADER_LEN); - if (memcmp (data, IMAGE_JPEG_SIG, IMAGE_JPEG_SIG_LEN) != 0) { - g_free (data); - continue; - } - - icon = G_ICON (_gcr_memory_icon_new_full ("image/jpeg", data, - n_data, IMAGE_HEADER_LEN, - g_free)); - - validity = _gcr_record_get_char (record, GCR_RECORD_XA1_TRUST); - if (validity != 0 && validity != 'm' && validity != 'f' && validity != 'u') - add_emblem_to_icon (&icon, "dialog-question"); - - /* We have a valid header */ - return icon; - } - - if (_gcr_records_find (records, GCR_RECORD_SCHEMA_SEC)) - return g_themed_icon_new ("gcr-key-pair"); - else - return g_themed_icon_new ("gcr-key"); - - return NULL; -} diff --git a/gcr/gcr-gnupg-records.h b/gcr/gcr-gnupg-records.h deleted file mode 100644 index 4a61ff97..00000000 --- a/gcr/gcr-gnupg-records.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_H_INSIDE__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> can be included directly." -#endif - -#ifndef GCR_GNUPG_RECORDS_H -#define GCR_GNUPG_RECORDS_H - -#include <gio/gio.h> - -#include "gcr-record.h" - -G_BEGIN_DECLS - -const gchar * _gcr_gnupg_records_get_keyid (GPtrArray *records); - -const gchar * _gcr_gnupg_records_get_short_keyid (GPtrArray *records); - -const gchar * _gcr_gnupg_records_get_fingerprint (GPtrArray *records); - -gchar * _gcr_gnupg_records_get_user_id (GPtrArray *records); - -gboolean _gcr_gnupg_records_parse_user_id (const gchar *user_id, - gchar **name, - gchar **email, - gchar **comment); - -GIcon * _gcr_gnupg_records_get_icon (GPtrArray *records); - -G_END_DECLS - -#endif /* __GCR_GNUPG_RECORD_H__ */ diff --git a/gcr/gcr-gnupg-renderer.c b/gcr/gcr-gnupg-renderer.c deleted file mode 100644 index 663e32c9..00000000 --- a/gcr/gcr-gnupg-renderer.c +++ /dev/null @@ -1,853 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-display-view.h" -#include "gcr-icons.h" -#include "gcr-gnupg-records.h" -#include "gcr-gnupg-renderer.h" -#include "gcr-openpgp.h" -#include "gcr-simple-certificate.h" -#include "gcr-renderer.h" -#include "gcr-types.h" - -#include "gck/gck.h" - -#include "egg/egg-hex.h" - -#include <gdk/gdk.h> -#include <glib/gi18n-lib.h> - -#include <stdlib.h> - -enum { - PROP_0, - PROP_RECORDS, - PROP_LABEL, - PROP_ATTRIBUTES -}; - -struct _GcrGnupgRendererPrivate { - GPtrArray *records; - GckAttributes *attrs; - gchar *label; -}; - -static void _gcr_gnupg_renderer_iface_init (GcrRendererIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrGnupgRenderer, _gcr_gnupg_renderer, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, _gcr_gnupg_renderer_iface_init); -); - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -static gchar * -calculate_label (GcrGnupgRenderer *self) -{ - gchar *userid; - gchar *label; - - if (self->pv->attrs) { - if (gck_attributes_find_string (self->pv->attrs, CKA_LABEL, &label)) - return label; - } - - userid = _gcr_gnupg_records_get_user_id (self->pv->records); - if (userid != NULL) { - if (!_gcr_gnupg_records_parse_user_id (userid, &label, NULL, NULL)) - label = NULL; - } - - if (label != NULL) - return label; - - if (self->pv->label) - return g_strdup (self->pv->label); - - return g_strdup (_("PGP Key")); -} - -static void -_gcr_gnupg_renderer_init (GcrGnupgRenderer *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_GNUPG_RENDERER, - GcrGnupgRendererPrivate)); -} - -static void -_gcr_gnupg_renderer_finalize (GObject *obj) -{ - GcrGnupgRenderer *self = GCR_GNUPG_RENDERER (obj); - - gck_attributes_unref (self->pv->attrs); - g_free (self->pv->label); - if (self->pv->records) - g_ptr_array_unref (self->pv->records); - - G_OBJECT_CLASS (_gcr_gnupg_renderer_parent_class)->finalize (obj); -} - -static void -_gcr_gnupg_renderer_set_property (GObject *obj, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GcrGnupgRenderer *self = GCR_GNUPG_RENDERER (obj); - - switch (prop_id) { - case PROP_RECORDS: - _gcr_gnupg_renderer_set_records (self, g_value_get_boxed (value)); - break; - case PROP_LABEL: - g_free (self->pv->label); - self->pv->label = g_value_dup_string (value); - g_object_notify (obj, "label"); - gcr_renderer_emit_data_changed (GCR_RENDERER (self)); - break; - case PROP_ATTRIBUTES: - _gcr_gnupg_renderer_set_attributes (self, g_value_get_boxed (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_gnupg_renderer_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GcrGnupgRenderer *self = GCR_GNUPG_RENDERER (obj); - - switch (prop_id) { - case PROP_RECORDS: - g_value_set_object (value, self->pv->records); - break; - case PROP_LABEL: - g_value_take_string (value, calculate_label (self)); - break; - case PROP_ATTRIBUTES: - g_value_set_boxed (value, self->pv->attrs); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_gnupg_renderer_class_init (GcrGnupgRendererClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GckAttributes *registered; - - _gcr_gnupg_renderer_parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private (klass, sizeof (GcrGnupgRendererPrivate)); - - gobject_class->finalize = _gcr_gnupg_renderer_finalize; - gobject_class->set_property = _gcr_gnupg_renderer_set_property; - gobject_class->get_property = _gcr_gnupg_renderer_get_property; - - g_object_class_install_property (gobject_class, PROP_RECORDS, - g_param_spec_boxed ("records", "Records", "Gnupg records to display", - G_TYPE_PTR_ARRAY, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, - g_param_spec_boxed ("attributes", "Attributes", "Certificate pkcs11 attributes", - GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_LABEL, - g_param_spec_string ("label", "Label", "Certificate Label", - "", G_PARAM_READWRITE)); - - /* Register this as a renderer which can be loaded */ - registered = gck_attributes_new (); - gck_attributes_add_ulong (registered, CKA_CLASS, CKO_GCR_GNUPG_RECORDS); - gcr_renderer_register (GCR_TYPE_GNUPG_RENDERER, registered); - gck_attributes_unref (registered); -} - -static const gchar * -name_for_algo (guint algo) -{ - switch (algo) - { - case GCR_OPENPGP_ALGO_RSA: - case GCR_OPENPGP_ALGO_RSA_E: - case GCR_OPENPGP_ALGO_RSA_S: - return _("RSA"); - case GCR_OPENPGP_ALGO_ELG_E: - return _("Elgamal"); - case GCR_OPENPGP_ALGO_DSA: - return _("DSA"); - default: - return NULL; - } -} - -static const gchar * -capability_for_code (gchar code) -{ - switch (code) { - case 'e': case 'E': - return _("Encrypt"); - case 's': case 'S': - return _("Sign"); - case 'c': case 'C': - return _("Certify"); - case 'a': case 'A': - return _("Authenticate"); - case 'D': - return _("Disabled"); - default: - return NULL; - } -} - -static gchar * -capabilities_for_codes (const gchar *codes) -{ - const gchar *cap; - GString *result; - guint i; - - result = g_string_new (""); - for (i = 0; codes[i] != 0; i++) { - if (result->len) - g_string_append_unichar (result, GCR_DISPLAY_VIEW_LINE_BREAK); - cap = capability_for_code (codes[i]); - if (cap != NULL) - g_string_append (result, cap); - else - g_string_append_c (result, codes[i]); - } - return g_string_free (result, FALSE); -} - -static const gchar * -status_for_code (gchar code) -{ - switch (code) { - case 'o': - return _("Unknown"); - case 'i': - return _("Invalid"); - case 'd': - return _("Disabled"); - case 'r': - return _("Revoked"); - case 'e': - return _("Expired"); - case 'q': case '-': - return _("Undefined trust"); - case 'n': - return _("Distrusted"); - case 'm': - return _("Marginally trusted"); - case 'f': - return _("Fully trusted"); - case 'u': - return _("Ultimately trusted"); - default: - return NULL; - } -} - -static const gchar * -message_for_code (gchar code, - GtkMessageType *message_type) -{ - *message_type = GTK_MESSAGE_OTHER; - switch (code) { - case 'o': - *message_type = GTK_MESSAGE_QUESTION; - return _("The information in this key has not yet been verified"); - case 'i': - *message_type = GTK_MESSAGE_ERROR; - return _("This key is invalid"); - case 'd': - *message_type = GTK_MESSAGE_WARNING; - return _("This key has been disabled"); - case 'r': - *message_type = GTK_MESSAGE_ERROR; - return _("This key has been revoked"); - case 'e': - *message_type = GTK_MESSAGE_ERROR; - return _("This key has expired"); - case 'q': case '-': - return NULL; - case 'n': - *message_type = GTK_MESSAGE_WARNING; - return _("This key is distrusted"); - case 'm': - *message_type = GTK_MESSAGE_OTHER; - return _("This key is marginally trusted"); - case 'f': - *message_type = GTK_MESSAGE_OTHER; - return _("This key is fully trusted"); - case 'u': - *message_type = GTK_MESSAGE_OTHER; - return _("This key is ultimately trusted"); - default: - return NULL; - } -} - -static void -append_key_record (GcrGnupgRenderer *self, - GcrDisplayView *view, - GcrRecord *record, - const gchar *title) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - const gchar *value; - gchar *display; - GDateTime *date; - gchar code; - guint algo; - guint bits; - - _gcr_display_view_append_heading (view, renderer, title); - - /* Key ID */ - value = _gcr_record_get_raw (record, GCR_RECORD_KEY_KEYID); - if (value != NULL) - _gcr_display_view_append_value (view, renderer, _("Key ID"), value, TRUE); - - /* Algorithm */ - if (_gcr_record_get_uint (record, GCR_RECORD_KEY_ALGO, &algo)) { - display = NULL; - value = name_for_algo (algo); - if (value == NULL) - value = display = g_strdup_printf ("%u", algo); - _gcr_display_view_append_value (view, renderer, _("Algorithm"), value, FALSE); - g_free (display); - } - - /* Key Size */ - if (_gcr_record_get_uint (record, GCR_RECORD_KEY_BITS, &bits)) { - display = g_strdup_printf ("%u", bits); - _gcr_display_view_append_value (view, renderer, _("Key Size"), display, FALSE); - g_free (display); - } - - /* Created */ - date = _gcr_record_get_date (record, GCR_RECORD_KEY_TIMESTAMP); - if (date != NULL) { - display = g_date_time_format (date, "%x"); - _gcr_display_view_append_value (view, renderer, _("Created"), display, FALSE); - g_free (display); - g_date_time_unref (date); - } - - /* Expiry */ - date = _gcr_record_get_date (record, GCR_RECORD_KEY_EXPIRY); - if (date != NULL) { - display = g_date_time_format (date, "%x"); - _gcr_display_view_append_value (view, renderer, _("Expiry"), display, FALSE); - g_free (display); - g_date_time_unref (date); - } - - /* Capabilities */ - value = _gcr_record_get_raw (record, GCR_RECORD_PUB_CAPS); - if (value != NULL) { - display = capabilities_for_codes (value); - _gcr_display_view_append_value (view, renderer, _("Capabilities"), display, FALSE); - g_free (display); - } - - /* Owner Trust */ - code = _gcr_record_get_char (record, GCR_RECORD_KEY_OWNERTRUST); - if (code != 0) { - display = NULL; - value = status_for_code (code); - if (value == NULL) { - value = display = g_new0 (gchar, 2); - display[0] = code; - } - _gcr_display_view_append_value (view, renderer, _("Owner trust"), value, FALSE); - g_free (display); - } -} - -static void -append_uid_record (GcrGnupgRenderer *self, - GcrDisplayView *view, - GcrRecord *record) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - gchar *userid; - gchar *name; - gchar *comment; - gchar *email; - GDateTime *date; - gchar *display; - - _gcr_display_view_append_heading (view, renderer, _("User ID")); - - userid = _gcr_record_get_string (record, GCR_RECORD_UID_USERID); - if (userid == NULL) { - _gcr_display_view_append_value (view, renderer, _("Value"), _("Unknown"), FALSE); - return; - } - - if (_gcr_gnupg_records_parse_user_id (userid, &name, &email, &comment)) { - if (name != NULL) - _gcr_display_view_append_value (view, renderer, _("Name"), name, FALSE); - g_free (name); - if (email != NULL) - _gcr_display_view_append_value (view, renderer, _("Email"), email, FALSE); - g_free (email); - if (comment != NULL) - _gcr_display_view_append_value (view, renderer, _("Comment"), comment, FALSE); - g_free (comment); - - /* Unparseable user id */ - } else { - _gcr_display_view_append_value (view, renderer, _("Value"), userid, FALSE); - } - - /* Created */ - date = _gcr_record_get_date (record, GCR_RECORD_UID_TIMESTAMP); - if (date != NULL) { - display = g_date_time_format (date, "%x"); - _gcr_display_view_append_value (view, renderer, _("Created"), display, FALSE); - g_free (display); - g_date_time_unref (date); - } - - /* Expiry */ - date = _gcr_record_get_date (record, GCR_RECORD_UID_EXPIRY); - if (date != NULL) { - display = g_date_time_format (date, "%x"); - _gcr_display_view_append_value (view, renderer, _("Expiry"), display, FALSE); - g_free (display); - g_date_time_unref (date); - } - - g_free (userid); -} - -static void -append_uat_record (GcrGnupgRenderer *self, - GcrDisplayView *view, - GcrRecord *record) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - gchar **parts; - gchar *display; - const gchar *value; - GDateTime *date; - - _gcr_display_view_append_heading (view, renderer, _("User Attribute")); - - /* Size */ - value = _gcr_record_get_raw (record, GCR_RECORD_UAT_COUNT_SIZE); - if (value != NULL) { - parts = g_strsplit (value, " ", 2); - if (parts && parts[0] && parts[1]) - _gcr_display_view_append_value (view, renderer, _("Size"), parts[1], FALSE); - g_strfreev (parts); - } - - /* Created */ - date = _gcr_record_get_date (record, GCR_RECORD_KEY_TIMESTAMP); - if (date != NULL) { - display = g_date_time_format (date, "%x"); - _gcr_display_view_append_value (view, renderer, _("Created"), display, FALSE); - g_free (display); - g_date_time_unref (date); - } - - /* Expiry */ - date = _gcr_record_get_date (record, GCR_RECORD_KEY_EXPIRY); - if (date != NULL) { - display = g_date_time_format (date, "%x"); - _gcr_display_view_append_value (view, renderer, _("Expiry"), display, FALSE); - g_free (display); - g_date_time_unref (date); - } -} - -static const gchar * -signature_klass_string (const gchar *klass) -{ - char *end; - guint val; - - val = strtoul (klass, &end, 16); - if (end != klass + 2) - return NULL; - - switch (val) { - case 0x00: - return _("Signature of a binary document"); - case 0x01: - return _("Signature of a canonical text document"); - case 0x02: - return _("Standalone signature"); - case 0x10: - return _("Generic certification of key"); - case 0x11: - return _("Persona certification of key"); - case 0x12: - return _("Casual certification of key"); - case 0x13: - return _("Positive certification of key"); - case 0x18: - return _("Subkey binding signature"); - case 0x19: - return _("Primary key binding signature"); - case 0x1F: - return _("Signature directly on key"); - case 0x20: - return _("Key revocation signature"); - case 0x28: - return _("Subkey revocation signature"); - case 0x30: - return _("Certification revocation signature"); - case 0x40: - return _("Timestamp signature"); - case 0x50: - return _("Third-party confirmation signature"); - default: - return NULL; - } -} - -static void -append_sig_record (GcrGnupgRenderer *self, - GcrDisplayView *view, - GcrRecord *record, - const gchar *keyid) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - const gchar *sigid; - gchar *display; - const gchar *value; - const gchar *klass; - guint algo; - - /* Hide self-signatures. There's so many of them */ - sigid = _gcr_record_get_raw (record, GCR_RECORD_SIG_KEYID); - if (sigid && keyid && g_str_equal (sigid, keyid)) - return; - - _gcr_display_view_append_heading (view, renderer, _("Signature")); - - /* Key ID */ - if (sigid != NULL) - _gcr_display_view_append_value (view, renderer, _("Key ID"), sigid, TRUE); - - /* Algorithm */ - if (_gcr_record_get_uint (record, GCR_RECORD_SIG_ALGO, &algo)) { - display = NULL; - value = name_for_algo (algo); - if (value == NULL) - value = display = g_strdup_printf ("%u", algo); - _gcr_display_view_append_value (view, renderer, _("Algorithm"), value, FALSE); - g_free (display); - } - - /* User ID */ - display = _gcr_record_get_string (record, GCR_RECORD_SIG_USERID); - if (display != NULL) - _gcr_display_view_append_value (view, renderer, _("User ID"), display, FALSE); - g_free (display); - - /* Signature class */ - klass = _gcr_record_get_raw (record, GCR_RECORD_SIG_CLASS); - if (klass != NULL) { - value = NULL; - if (strlen (klass) >= 2) { - value = signature_klass_string (klass); - if (value != NULL) { - _gcr_display_view_append_value (view, renderer, _("Class"), value, FALSE); - if (klass[2] == 'l') - _gcr_display_view_append_value (view, renderer, _("Type"), _("Local only"), FALSE); - else if (klass[2] == 'x') - _gcr_display_view_append_value (view, renderer, _("Type"), _("Exportable"), FALSE); - } - } - if (value == NULL) - _gcr_display_view_append_value (view, renderer, _("Class"), klass, FALSE); - } -} - -static void -append_rvk_record (GcrGnupgRenderer *self, - GcrDisplayView *view, - GcrRecord *record) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - const gchar *value; - gchar *display; - guint algo; - - _gcr_display_view_append_heading (view, renderer, _("Revocation Key")); - - /* Algorithm */ - if (_gcr_record_get_uint (record, GCR_RECORD_RVK_ALGO, &algo)) { - display = NULL; - value = name_for_algo (algo); - if (value == NULL) - value = display = g_strdup_printf ("%u", algo); - _gcr_display_view_append_value (view, renderer, _("Algorithm"), value, FALSE); - g_free (display); - } - - value = _gcr_record_get_raw (record, GCR_RECORD_RVK_FINGERPRINT); - if (value != NULL) - _gcr_display_view_append_value (view, renderer, _("Fingerprint"), value, TRUE); -} - -static void -append_fpr_record (GcrGnupgRenderer *self, - GcrDisplayView *view, - GcrRecord *record, - GQuark last_schema) -{ - GcrRenderer *renderer = GCR_RENDERER (self); - const gchar *value; - gpointer raw; - gsize n_raw; - - if (last_schema != GCR_RECORD_SCHEMA_PUB && - last_schema != GCR_RECORD_SCHEMA_SUB && - last_schema != GCR_RECORD_SCHEMA_SEC && - last_schema != GCR_RECORD_SCHEMA_SSB) - return; - - value = _gcr_record_get_raw (record, GCR_RECORD_FPR_FINGERPRINT); - if (value != NULL) { - raw = egg_hex_decode (value, -1, &n_raw); - if (raw != NULL) - _gcr_display_view_append_hex (view, renderer, _("Fingerprint"), raw, n_raw); - else - _gcr_display_view_append_value (view, renderer, _("Fingerprint"), value, TRUE); - g_free (raw); - } -} - -static void -_gcr_gnupg_renderer_render (GcrRenderer *renderer, - GcrViewer *viewer) -{ - GtkMessageType message_type; - GcrGnupgRenderer *self; - GcrDisplayView *view; - GDateTime *date; - const gchar *value; - gchar *display; - gchar *userid; - gchar *email; - gchar *comment; - GIcon *icon; - GQuark schema; - GQuark last_schema; - gchar code; - guint i; - - self = GCR_GNUPG_RENDERER (renderer); - - if (GCR_IS_DISPLAY_VIEW (viewer)) { - view = GCR_DISPLAY_VIEW (viewer); - - } else { - g_warning ("GcrGnupgRenderer only works with internal specific " - "GcrViewer returned by gcr_viewer_new()."); - return; - } - - _gcr_display_view_begin (view, renderer); - - if (self->pv->records == NULL || self->pv->records->len == 0) { - _gcr_display_view_end (view, renderer); - return; - } - - icon = _gcr_gnupg_records_get_icon (self->pv->records); - _gcr_display_view_set_icon (view, GCR_RENDERER (self), icon); - g_object_unref (icon); - - display = calculate_label (self); - _gcr_display_view_append_title (view, renderer, display); - g_free (display); - - userid = _gcr_gnupg_records_get_user_id (self->pv->records); - if (userid != NULL) { - if (_gcr_gnupg_records_parse_user_id (userid, NULL, &email, &comment)) { - if (email != NULL) - _gcr_display_view_append_content (view, renderer, _("Email"), email); - g_free (email); - if (comment != NULL) - _gcr_display_view_append_content (view, renderer, _("Comment"), comment); - g_free (comment); - } - g_free (userid); - } - - code = _gcr_record_get_char (self->pv->records->pdata[0], GCR_RECORD_TRUST); - if (code != 'e') { - date = _gcr_record_get_date (self->pv->records->pdata[0], GCR_RECORD_KEY_EXPIRY); - if (date != NULL) { - display = g_date_time_format (date, "%x"); - _gcr_display_view_append_content (view, renderer, _("Expires"), display); - g_date_time_unref (date); - g_free (display); - } - } - - /* The warning or status */ - value = message_for_code (code, &message_type); - if (value != NULL) - _gcr_display_view_append_message (view, renderer, message_type, value); - - _gcr_display_view_start_details (view, renderer); - - value = _gcr_gnupg_records_get_keyid (self->pv->records); - last_schema = 0; - - for (i = 0; i < self->pv->records->len; i++) { - schema = _gcr_record_get_schema (self->pv->records->pdata[i]); - if (schema == GCR_RECORD_SCHEMA_PUB) - append_key_record (self, view, self->pv->records->pdata[i], _("Public Key")); - else if (schema == GCR_RECORD_SCHEMA_SUB) - append_key_record (self, view, self->pv->records->pdata[i], _("Public Subkey")); - else if (schema == GCR_RECORD_SCHEMA_SEC) - append_key_record (self, view, self->pv->records->pdata[i], _("Secret Key")); - else if (schema == GCR_RECORD_SCHEMA_SSB) - append_key_record (self, view, self->pv->records->pdata[i], _("Secret Subkey")); - else if (schema == GCR_RECORD_SCHEMA_UID) - append_uid_record (self, view, self->pv->records->pdata[i]); - else if (schema == GCR_RECORD_SCHEMA_UAT) - append_uat_record (self, view, self->pv->records->pdata[i]); - else if (schema == GCR_RECORD_SCHEMA_SIG) - append_sig_record (self, view, self->pv->records->pdata[i], value); - else if (schema == GCR_RECORD_SCHEMA_RVK) - append_rvk_record (self, view, self->pv->records->pdata[i]); - else if (schema == GCR_RECORD_SCHEMA_FPR) - append_fpr_record (self, view, self->pv->records->pdata[i], last_schema); - last_schema = schema; - } - - _gcr_display_view_end (view, renderer); -} - -static void -_gcr_gnupg_renderer_iface_init (GcrRendererIface *iface) -{ - iface->render_view = _gcr_gnupg_renderer_render; -} - -GcrGnupgRenderer * -_gcr_gnupg_renderer_new (GPtrArray *records) -{ - g_return_val_if_fail (records != NULL, NULL); - - return g_object_new (GCR_TYPE_GNUPG_RENDERER, - "records", records, - NULL); -} - -GcrGnupgRenderer * -_gcr_gnupg_renderer_new_for_attributes (const gchar *label, - GckAttributes *attrs) -{ - g_return_val_if_fail (attrs != NULL, NULL); - - return g_object_new (GCR_TYPE_GNUPG_RENDERER, - "label", label, - "attributes", attrs, - NULL); -} - -GPtrArray * -_gcr_gnupg_renderer_get_records (GcrGnupgRenderer *self) -{ - g_return_val_if_fail (GCR_IS_GNUPG_RENDERER (self), NULL); - return self->pv->records; -} - -void -_gcr_gnupg_renderer_set_records (GcrGnupgRenderer *self, - GPtrArray *records) -{ - g_return_if_fail (GCR_IS_GNUPG_RENDERER (self)); - - if (records) - g_ptr_array_ref (records); - if (self->pv->records) - g_ptr_array_unref (self->pv->records); - self->pv->records = records; - - if (self->pv->attrs) { - gck_attributes_unref (self->pv->attrs); - self->pv->attrs = NULL; - g_object_notify (G_OBJECT (self), "attributes"); - } - - gcr_renderer_emit_data_changed (GCR_RENDERER (self)); - g_object_notify (G_OBJECT (self), "records"); -} - -GckAttributes* -_gcr_gnupg_renderer_get_attributes (GcrGnupgRenderer *self) -{ - g_return_val_if_fail (GCR_IS_GNUPG_RENDERER (self), NULL); - return self->pv->attrs; -} - -void -_gcr_gnupg_renderer_set_attributes (GcrGnupgRenderer *self, - GckAttributes *attrs) -{ - GckAttribute *attr; - GPtrArray *records; - - g_return_if_fail (GCR_IS_GNUPG_RENDERER (self)); - - attr = gck_attributes_find (attrs, CKA_VALUE); - g_return_if_fail (attr != NULL); - records = _gcr_records_parse_colons (attr->value, attr->length); - g_return_if_fail (records != NULL); - - if (attrs) - gck_attributes_ref (attrs); - gck_attributes_unref (self->pv->attrs); - self->pv->attrs = attrs; - - if (self->pv->records) - g_ptr_array_unref (self->pv->records); - self->pv->records = records; - g_object_notify (G_OBJECT (self), "records"); - - gcr_renderer_emit_data_changed (GCR_RENDERER (self)); - g_object_notify (G_OBJECT (self), "attributes"); - -} diff --git a/gcr/gcr-gnupg-renderer.h b/gcr/gcr-gnupg-renderer.h deleted file mode 100644 index 0d09c313..00000000 --- a/gcr/gcr-gnupg-renderer.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_H_INSIDE__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> can be included directly." -#endif - -#ifndef __GCR_GNUPG_RENDERER_H__ -#define __GCR_GNUPG_RENDERER_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-record.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_GNUPG_RENDERER (_gcr_gnupg_renderer_get_type ()) -#define GCR_GNUPG_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_GNUPG_RENDERER, GcrGnupgRenderer)) -#define GCR_GNUPG_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_GNUPG_RENDERER, GcrGnupgRendererClass)) -#define GCR_IS_GNUPG_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_GNUPG_RENDERER)) -#define GCR_IS_GNUPG_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_GNUPG_RENDERER)) -#define GCR_GNUPG_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_GNUPG_RENDERER, GcrGnupgRendererClass)) - -typedef struct _GcrGnupgRenderer GcrGnupgRenderer; -typedef struct _GcrGnupgRendererClass GcrGnupgRendererClass; -typedef struct _GcrGnupgRendererPrivate GcrGnupgRendererPrivate; - -struct _GcrGnupgRenderer { - GObject parent; - - /*< private >*/ - GcrGnupgRendererPrivate *pv; -}; - -struct _GcrGnupgRendererClass { - GObjectClass parent_class; -}; - -GType _gcr_gnupg_renderer_get_type (void); - -GcrGnupgRenderer * _gcr_gnupg_renderer_new (GPtrArray *records); - -GcrGnupgRenderer * _gcr_gnupg_renderer_new_for_attributes (const gchar *label, - GckAttributes *attrs); - -GPtrArray * _gcr_gnupg_renderer_get_records (GcrGnupgRenderer *self); - -void _gcr_gnupg_renderer_set_records (GcrGnupgRenderer *self, - GPtrArray *records); - -GckAttributes * _gcr_gnupg_renderer_get_attributes (GcrGnupgRenderer *self); - -void _gcr_gnupg_renderer_set_attributes (GcrGnupgRenderer *self, - GckAttributes *attrs); - -G_END_DECLS - -#endif /* __GCR_GNUPG_RENDERER_H__ */ diff --git a/gcr/gcr-gnupg-util.c b/gcr/gcr-gnupg-util.c deleted file mode 100644 index b85836b5..00000000 --- a/gcr/gcr-gnupg-util.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "egg/egg-hex.h" - -#include "gcr-gnupg-util.h" - -#include <gcrypt.h> - -/** - * _gcr_gnupg_build_xa1_record: - * @meta: Status metadata record about the attribute data. - * @attribute: Pointer to attribute data. - * @n_attribute: Length of attribute data. - * - * Build a record for attribute data. We use this records to convert attribute - * data into something we can keep with an array of GcrRecord. - * - * Returns: (transfer full): The newly allocated record. - */ -GcrRecord* -_gcr_gnupg_build_xa1_record (GcrRecord *meta, gpointer attribute, - gsize n_attribute) -{ - gchar hash[20]; - gchar *hex; - gchar status = 0; - GcrRecord *record; - guint flags, type; - const gchar *created, *expiry; - - g_return_val_if_fail (meta, NULL); - - record = _gcr_record_new (GCR_RECORD_SCHEMA_XA1, GCR_RECORD_XA1_MAX, ':'); - - gcry_md_hash_buffer (GCRY_MD_RMD160, hash, attribute, n_attribute); - hex = egg_hex_encode_full (hash, sizeof (hash), TRUE, 0, 1); - _gcr_record_take_raw (record, GCR_RECORD_XA1_FINGERPRINT, hex); - - if (!_gcr_record_get_uint (meta, GCR_RECORD_ATTRIBUTE_FLAGS, &flags)) - flags = 0; - - if (_gcr_record_get_uint (meta, GCR_RECORD_ATTRIBUTE_TYPE, &type)) - _gcr_record_set_uint (record, GCR_RECORD_XA1_TYPE, type); - - created = _gcr_record_get_raw (meta, GCR_RECORD_ATTRIBUTE_TIMESTAMP); - if (created == NULL) - _gcr_record_set_raw (record, GCR_RECORD_XA1_TIMESTAMP, created); - - expiry = _gcr_record_get_raw (meta, GCR_RECORD_ATTRIBUTE_EXPIRY); - if (expiry != NULL) - _gcr_record_set_raw (record, GCR_RECORD_XA1_EXPIRY, expiry); - - /* These values are from gnupg doc/DETAILS */ - if (flags & 0x02) - status = 'r'; - else if (flags & 0x04) - status = 'e'; - else if (flags & 0x01) - status = 'P'; - if (status != 0) - _gcr_record_set_char (record, GCR_RECORD_XA1_TRUST, status); - - _gcr_record_set_base64 (record, GCR_RECORD_XA1_DATA, attribute, n_attribute); - - return record; -} diff --git a/gcr/gcr-gnupg-util.h b/gcr/gcr-gnupg-util.h deleted file mode 100644 index 5910bfbd..00000000 --- a/gcr/gcr-gnupg-util.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef GCR_GNUPG_UTIL_H -#define GCR_GNUPG_UTIL_H - -#include <glib.h> - -#include "gcr-record.h" - -G_BEGIN_DECLS - -GcrRecord* _gcr_gnupg_build_xa1_record (GcrRecord *meta, - gpointer attribute, - gsize n_attribute); - -G_END_DECLS - -#endif /* __GCR_GNUPG_KEY_H__ */ diff --git a/gcr/gcr-icons.c b/gcr/gcr-icons.c deleted file mode 100644 index e375d009..00000000 --- a/gcr/gcr-icons.c +++ /dev/null @@ -1,55 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-base.h" -#include "gcr-icons.h" - -/** - * gcr_icon_for_token: - * @token_info: the token info - * - * Get an appropriate icon for the token - * - * Returns: (transfer full): the icon - */ -GIcon * -gcr_icon_for_token (GckTokenInfo *token_info) -{ - GIcon *icon; - - g_return_val_if_fail (token_info != NULL, NULL); - - if (g_strcmp0 (token_info->manufacturer_id, "Gnome Keyring") == 0) - icon = g_themed_icon_new (GCR_ICON_HOME_DIRECTORY); - - else if (g_strcmp0 (token_info->manufacturer_id, "Mozilla Foundation") == 0 && - g_strcmp0 (token_info->model, "NSS 3") == 0) - icon = g_themed_icon_new (GCR_ICON_HOME_DIRECTORY); - - else - icon = g_themed_icon_new (GCR_ICON_SMART_CARD); - - return icon; -} diff --git a/gcr/gcr-icons.h b/gcr/gcr-icons.h deleted file mode 100644 index 7fb4f6c1..00000000 --- a/gcr/gcr-icons.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * Copyright (C) 2011 Collabora Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_ICONS_H__ -#define __GCR_ICONS_H__ - -#include <gck/gck.h> - -#include <gio/gio.h> - -G_BEGIN_DECLS - -#define GCR_ICON_CERTIFICATE "application-certificate" -#define GCR_ICON_KEY "gcr-key" -#define GCR_ICON_KEY_PAIR "gcr-key-pair" -#define GCR_ICON_SMART_CARD "gcr-smart-card" -#define GCR_ICON_HOME_DIRECTORY "user-home" - -GIcon * gcr_icon_for_token (GckTokenInfo *token_info); - -G_END_DECLS - -#endif /* __GCR_SMART_CARD_H__ */ diff --git a/gcr/gcr-import-button.c b/gcr/gcr-import-button.c deleted file mode 100644 index b25f20cf..00000000 --- a/gcr/gcr-import-button.c +++ /dev/null @@ -1,560 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-import-button.h" -#include "gcr-internal.h" -#include "gcr-marshal.h" -#include "gcr-parser.h" -#include "gcr-pkcs11-import-interaction.h" - -#include <glib/gi18n-lib.h> - -enum { - PROP_0, - PROP_LABEL -}; - -/** - * SECTION:gcr-import-button - * @title: GcrImportButton - * @short_description: Button which imports parsed certificates and keys - * - * A button which imports keys and certificates. Shows a spinner when the - * button is activated. When more than one importer is available shows - * a drop down to select which to import to. - */ - -/** - * GcrImportButton: - * - * Button which imports parsed certificates and keys. - */ - -/** - * GcrImportButtonClass: - * @parent_class: The parent class - * @imported: Emitted when the import completes, or fails. - * - * Class for #GcrImportButton. - */ - -struct _GcrImportButtonPrivate { - GList *queued; - GList *importers; - gboolean ready; - gboolean created; - gboolean importing; - gchar *imported; - GtkWidget *spinner; - GtkWidget *arrow; - GtkWidget *label; - GCancellable *cancellable; - GtkMenu *menu; -}; - -enum { - IMPORTED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static GQuark QUARK_IMPORTER = 0; - -G_DEFINE_TYPE (GcrImportButton, gcr_import_button, GTK_TYPE_BUTTON); - -static void -gcr_import_button_init (GcrImportButton *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_IMPORT_BUTTON, GcrImportButtonPrivate); - self->pv->cancellable = g_cancellable_new (); - self->pv->label = gtk_label_new (""); -} - -static void -update_import_button (GcrImportButton *self) -{ - gchar *message; - gchar *label; - - /* Initializing, set a spinner */ - if (self->pv->queued && !self->pv->ready) { - gtk_widget_show (self->pv->spinner); - gtk_spinner_start (GTK_SPINNER (self->pv->spinner)); - gtk_widget_hide (self->pv->arrow); - gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE); - gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("Initializing...")); - - /* Importing, set a spinner */ - } else if (self->pv->importing) { - gtk_widget_show (self->pv->spinner); - gtk_spinner_start (GTK_SPINNER (self->pv->spinner)); - gtk_widget_hide (self->pv->arrow); - gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE); - gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("Import is in progress...")); - - } else if (self->pv->imported) { - gtk_widget_hide (self->pv->spinner); - gtk_spinner_stop (GTK_SPINNER (self->pv->spinner)); - gtk_widget_hide (self->pv->arrow); - gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE); - message = g_strdup_printf (_("Imported to: %s"), self->pv->imported); - gtk_widget_set_tooltip_text (GTK_WIDGET (self), message); - g_free (message); - - /* Not importing, but have importers */ - } else if (self->pv->importers) { - - gtk_widget_hide (self->pv->spinner); - gtk_spinner_stop (GTK_SPINNER (self->pv->spinner)); - gtk_widget_set_sensitive (GTK_WIDGET (self), TRUE); - - /* More than one importer */ - if (self->pv->importers->next) { - gtk_widget_show (self->pv->arrow); - gtk_widget_set_tooltip_text (GTK_WIDGET (self), NULL); - - /* Only one importer */ - } else { - gtk_widget_hide (self->pv->arrow); - g_object_get (self->pv->importers->data, "label", &label, NULL); - message = g_strdup_printf (_("Import to: %s"), label); - gtk_widget_set_tooltip_text (GTK_WIDGET (self), message); - g_free (message); - g_free (label); - } - - /* No importers, none compatible */ - } else if (self->pv->created) { - gtk_widget_hide (self->pv->spinner); - gtk_spinner_stop (GTK_SPINNER (self->pv->spinner)); - gtk_widget_hide (self->pv->arrow); - - gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE); - gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("Cannot import because there are no compatible importers")); - - /* No importers yet added */ - } else { - gtk_widget_hide (self->pv->spinner); - gtk_spinner_stop (GTK_SPINNER (self->pv->spinner)); - gtk_widget_hide (self->pv->arrow); - - gtk_widget_set_sensitive (GTK_WIDGET (self), FALSE); - gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("No data to import")); - } -} - -static void -on_library_pkcs11_ready (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GcrImportButton *self = GCR_IMPORT_BUTTON (user_data); - GList *queued, *l; - - self->pv->ready = TRUE; - - /* Process the parsed items that have been seen */ - queued = self->pv->queued; - self->pv->queued = NULL; - for (l = queued; l != NULL; l = g_list_next (l)) - gcr_import_button_add_parsed (self, l->data); - g_assert (self->pv->queued == NULL); - g_list_free_full (queued, gcr_parsed_unref); -} - -static void -gcr_import_button_constructed (GObject *obj) -{ - GcrImportButton *self = GCR_IMPORT_BUTTON (obj); - GtkWidget *grid; - - G_OBJECT_CLASS (gcr_import_button_parent_class)->constructed (obj); - - self->pv->spinner = gtk_spinner_new (); - self->pv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); - grid = gtk_grid_new (); - - gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_HORIZONTAL); - gtk_container_add (GTK_CONTAINER (grid), self->pv->spinner); - gtk_container_add (GTK_CONTAINER (grid), self->pv->label); - gtk_container_add (GTK_CONTAINER (grid), self->pv->arrow); - gtk_grid_set_row_spacing (GTK_GRID (grid), 3); - gtk_widget_set_hexpand (grid, TRUE); - gtk_widget_set_halign (grid, GTK_ALIGN_CENTER); - - gtk_widget_show (self->pv->label); - gtk_widget_show (grid); - - gtk_container_add (GTK_CONTAINER (self), grid); - - update_import_button (self); - - gcr_pkcs11_initialize_async (NULL, on_library_pkcs11_ready, g_object_ref (self)); -} - -static void -gcr_import_button_set_property (GObject *obj, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GcrImportButton *self = GCR_IMPORT_BUTTON (obj); - - switch (prop_id) { - case PROP_LABEL: - gtk_label_set_label (GTK_LABEL (self->pv->label), g_value_get_string (value)); - g_object_notify (obj, "label"); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_import_button_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GcrImportButton *self = GCR_IMPORT_BUTTON (obj); - - switch (prop_id) { - case PROP_LABEL: - g_value_set_string (value, gtk_label_get_label (GTK_LABEL (self->pv->label))); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_import_button_dispose (GObject *obj) -{ - GcrImportButton *self = GCR_IMPORT_BUTTON (obj); - - gck_list_unref_free (self->pv->importers); - self->pv->importers = NULL; - g_cancellable_cancel (self->pv->cancellable); - g_clear_object (&self->pv->menu); - - g_list_free_full (self->pv->queued, gcr_parsed_unref); - self->pv->queued = NULL; - - G_OBJECT_CLASS (gcr_import_button_parent_class)->dispose (obj); -} - -static void -gcr_import_button_finalize (GObject *obj) -{ - GcrImportButton *self = GCR_IMPORT_BUTTON (obj); - - g_object_unref (self->pv->cancellable); - - G_OBJECT_CLASS (gcr_import_button_parent_class)->finalize (obj); -} - -static void -on_import_complete (GObject *importer, - GAsyncResult *result, - gpointer user_data) -{ - GcrImportButton *self = GCR_IMPORT_BUTTON (user_data); - GError *error = NULL; - - g_return_if_fail (self->pv->imported == NULL); - - self->pv->importing = FALSE; - - gcr_importer_import_finish (GCR_IMPORTER (importer), result, &error); - if (error == NULL) { - g_object_get (importer, "label", &self->pv->imported, NULL); - gck_list_unref_free (self->pv->importers); - self->pv->importers = NULL; - } - - g_signal_emit (self, signals[IMPORTED], 0, importer, error); - g_clear_error (&error); - - update_import_button (self); -} - -static void -begin_import (GcrImportButton *self, - GcrImporter *importer) -{ - GTlsInteraction *interaction; - GtkWindow *window; - - g_return_if_fail (self->pv->importing == FALSE); - - self->pv->importing = TRUE; - g_free (self->pv->imported); - self->pv->imported = NULL; - - /* TODO: Hack. Need to figure out how to pair these up... */ - if (g_strcmp0 (G_OBJECT_TYPE_NAME (importer), "GcrPkcs11Importer") == 0) { - window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))); - interaction = _gcr_pkcs11_import_interaction_new (window); - gcr_importer_set_interaction (importer, interaction); - g_object_unref (interaction); - } - - gcr_importer_import_async (importer, - self->pv->cancellable, - on_import_complete, - g_object_ref (self)); -} - -static void -on_importer_menu_activated (GtkMenuItem *menu_item, - gpointer user_data) -{ - GcrImportButton *self = GCR_IMPORT_BUTTON (user_data); - GcrImporter *importer; - - importer = g_object_get_qdata (G_OBJECT (menu_item), QUARK_IMPORTER); - g_return_if_fail (GCR_IMPORTER (importer)); - g_return_if_fail (self->pv->importing == FALSE); - - begin_import (self, importer); - update_import_button (self); -} - -static void -update_importer_menu (GcrImportButton *self) -{ - GtkWidget *menu_item; - GtkWidget *image; - GList *children, *l; - GIcon *icon; - gchar *label; - - if (!self->pv->menu) { - self->pv->menu = GTK_MENU (gtk_menu_new ()); - g_object_ref_sink (self->pv->menu); - } - - children = gtk_container_get_children (GTK_CONTAINER (self->pv->menu)); - for (l = children; l != NULL; l = g_list_next (l)) - gtk_container_remove (GTK_CONTAINER (self->pv->menu), l->data); - g_list_free (children); - - for (l = self->pv->importers; l != NULL; l = g_list_next (l)) { - g_object_get (l->data, "label", &label, "icon", &icon, NULL); - menu_item = gtk_image_menu_item_new_with_label (label); - g_signal_connect (menu_item, "activate", G_CALLBACK (on_importer_menu_activated), self); - g_object_set_qdata (G_OBJECT (menu_item), QUARK_IMPORTER, l->data); - image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), image); - gtk_image_menu_item_set_always_show_image (GTK_IMAGE_MENU_ITEM (menu_item), TRUE); - gtk_widget_show (image); - gtk_widget_show (menu_item); - gtk_container_add (GTK_CONTAINER (self->pv->menu), menu_item); - g_object_unref (icon); - g_free (label); - } -} - -static void -on_menu_position (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - gpointer user_data) -{ - GcrImportButton *self = GCR_IMPORT_BUTTON (user_data); - GtkWidget *widget = GTK_WIDGET (self); - GtkAllocation allocation; - GtkRequisition menu_req; - GdkRectangle monitor; - GdkWindow *window; - GtkWidget *toplevel; - GdkScreen *screen; - gint monitor_num; - gint sx = 0; - gint sy = 0; - - g_return_if_fail (x != NULL); - g_return_if_fail (y != NULL); - g_return_if_fail (push_in != NULL); - - gtk_widget_get_allocation (widget, &allocation); - - if (!gtk_widget_get_has_window (widget)) { - sx += allocation.x; - sy += allocation.y; - } - - window = gtk_widget_get_window (widget); - gdk_window_get_root_coords (window, sx, sy, &sx, &sy); - - gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &menu_req); - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) - *x = sx; - else - *x = sx + allocation.width - menu_req.width; - *y = sy; - - screen = gtk_widget_get_screen (widget); - monitor_num = gdk_screen_get_monitor_at_window (screen, window); - if (monitor_num < 0) - monitor_num = 0; - gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); - - if (*x < monitor.x) - *x = monitor.x; - else if (*x + menu_req.width > monitor.x + monitor.width) - *x = monitor.x + monitor.width - menu_req.width; - - if (monitor.y + monitor.height - *y - allocation.height >= menu_req.height) - *y += allocation.height; - else if (*y - monitor.y >= menu_req.height) - *y -= menu_req.height; - else if (monitor.y + monitor.height - *y - allocation.height > *y - monitor.y) - *y += allocation.height; - else - *y -= menu_req.height; - - gtk_menu_set_monitor (menu, monitor_num); - - toplevel = gtk_widget_get_parent (GTK_WIDGET (menu)); - if (GTK_IS_WINDOW (toplevel) && gtk_widget_get_visible (toplevel)) - gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU); - - *push_in = FALSE; -} - -static void -gcr_import_button_clicked (GtkButton *button) -{ - GcrImportButton *self = GCR_IMPORT_BUTTON (button); - - g_return_if_fail (self->pv->importing == FALSE); - g_return_if_fail (self->pv->importers != NULL); - - /* More than one importer, show the menu */ - if (self->pv->importers->next) { - update_importer_menu (self); - gtk_menu_popup (self->pv->menu, NULL, NULL, on_menu_position, - self, 1, gtk_get_current_event_time ()); - - /* Only one importer, import on click */ - } else { - begin_import (self, self->pv->importers->data); - } - - update_import_button (self); -} - -static void -gcr_import_button_class_init (GcrImportButtonClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass); - - gobject_class->constructed = gcr_import_button_constructed; - gobject_class->dispose = gcr_import_button_dispose; - gobject_class->finalize = gcr_import_button_finalize; - gobject_class->get_property = gcr_import_button_get_property; - gobject_class->set_property = gcr_import_button_set_property; - - button_class->clicked = gcr_import_button_clicked; - - g_object_class_override_property (gobject_class, PROP_LABEL, "label"); - - /** - * GcrImportButton::imported: - * @self: the import button - * @importer: the importer that was imported to - * @error: if import was successful %NULL, or an error - * - * Signal emitted when an import completes or fails. - */ - signals[IMPORTED] = g_signal_new ("imported", GCR_TYPE_IMPORT_BUTTON, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GcrImportButtonClass, imported), - NULL, NULL, _gcr_marshal_VOID__OBJECT_BOXED, - G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_ERROR); - - QUARK_IMPORTER = g_quark_from_static_string ("gcr-import-button-importer"); - - g_type_class_add_private (klass, sizeof (GcrImportButtonPrivate)); -} - -/** - * gcr_import_button_new: - * @label: (allow-none): label to display on the button - * - * Create a new #GcrImportButton. - * - * Returns: (transfer full): a newly created #GcrImportButton - */ -GcrImportButton * -gcr_import_button_new (const gchar *label) -{ - return g_object_new (GCR_TYPE_IMPORT_BUTTON, - "label", label, - NULL); -} - -/** - * gcr_import_button_add_parsed: - * @self: an import button - * @parsed: a parsed item - * - * Queue an item to import via the button - */ -void -gcr_import_button_add_parsed (GcrImportButton *self, - GcrParsed *parsed) -{ - GList *importers; - - g_return_if_fail (GCR_IS_IMPORT_BUTTON (self)); - g_return_if_fail (parsed != NULL); - - if (!self->pv->ready) { - self->pv->queued = g_list_prepend (self->pv->queued, gcr_parsed_ref (parsed)); - update_import_button (self); - return; - } - - g_free (self->pv->imported); - self->pv->imported = NULL; - - if (self->pv->created) { - importers = gcr_importer_queue_and_filter_for_parsed (self->pv->importers, parsed); - } else { - importers = gcr_importer_create_for_parsed (parsed); - self->pv->created = TRUE; - } - - gck_list_unref_free (self->pv->importers); - self->pv->importers = importers; - - update_import_button (self); -} diff --git a/gcr/gcr-import-button.h b/gcr/gcr-import-button.h deleted file mode 100644 index 6c839fcb..00000000 --- a/gcr/gcr-import-button.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef __GCR_IMPORT_BUTTON_H__ -#define __GCR_IMPORT_BUTTON_H__ - -#include "gcr.h" - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_IMPORT_BUTTON (gcr_import_button_get_type ()) -#define GCR_IMPORT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_IMPORT_BUTTON, GcrImportButton)) -#define GCR_IMPORT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_IMPORT_BUTTON, GcrImportButtonClass)) -#define GCR_IS_IMPORT_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_IMPORT_BUTTON)) -#define GCR_IS_IMPORT_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_IMPORT_BUTTON)) -#define GCR_IMPORT_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_IMPORT_BUTTON, GcrImportButtonClass)) - -typedef struct _GcrImportButton GcrImportButton; -typedef struct _GcrImportButtonClass GcrImportButtonClass; -typedef struct _GcrImportButtonPrivate GcrImportButtonPrivate; - -struct _GcrImportButton { - GtkButton parent; - - /*< private >*/ - GcrImportButtonPrivate *pv; -}; - -struct _GcrImportButtonClass { - GtkButtonClass parent_class; - - void (*imported) (GcrImportButton *self, - GcrImporter *importer, - GError *error); -}; - -GType gcr_import_button_get_type (void) G_GNUC_CONST; - -GcrImportButton * gcr_import_button_new (const gchar *label); - -void gcr_import_button_add_parsed (GcrImportButton *self, - GcrParsed *parsed); - -G_END_DECLS - -#endif /* __GCR_IMPORT_BUTTON_H__ */ diff --git a/gcr/gcr-import-interaction.c b/gcr/gcr-import-interaction.c deleted file mode 100644 index 19d0bc01..00000000 --- a/gcr/gcr-import-interaction.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-import-interaction.h" - -/** - * SECTION:gcr-importer - * @title: GcrImporter - * @short_description: Import certificates and keys - * - * An interface which allows importing of certificates and keys. Each - * #GcrImporter is registered with a set of PKCS\#11 attributes to match - * stuff that it can import. - * - * An importer gets passed a #GcrParser and accesses the currently parsed - * item. To create a set of importers that can import the currently parsed - * item in a #GcrParser, use gcr_importer_create_for_parsed(). The list of - * importers returned has the parsed item queued for import. - * - * To queue additional items with a importer use gcr_importer_queue_for_parsed(). - * In addition you can try and queue an additional item with a set of importers - * using the gcr_importer_queue_and_filter_for_parsed(). - * - * To start the import use gcr_importer_import() or the async variants. - */ - -/** - * GcrImporter: - * - * Imports certificates and keys - */ - -/** - * GcrImporterIface: - * @parent: parent interface - * @create_for_parsed: implementation of gcr_importer_create_for_parsed(), required - * @queue_for_parsed: implementation of gcr_importer_queue_for_parsed(), required - * @import_sync: optional implemantionon of gcr_importer_import() - * @import_async: implementation of gcr_importer_import_async(), required - * @import_finish: implementation of gcr_importer_import_finish() - * - * Interface implemented for a #GcrImporter. - */ - -typedef GcrImportInteractionIface GcrImportInteractionInterface; - -G_DEFINE_INTERFACE (GcrImportInteraction, gcr_import_interaction, G_TYPE_TLS_INTERACTION); - -static void -gcr_import_interaction_default_init (GcrImportInteractionIface *iface) -{ - static volatile gsize initialized = 0; - - if (g_once_init_enter (&initialized)) { - g_once_init_leave (&initialized, 1); - } -} - -/** - * gcr_import_interaction_supplement_prep: - * @interaction: the interaction - * @attributes: attributes to supplement - * - * Prepare for supplementing the given attributes before import. This means - * prompting the user for things like labels and the like. The attributes - * will contain attributes for values that the importer needs, either empty - * or prefilled with suggested values. - * - * This method does not prompt the user, but rather just prepares the - * interaction that these are the attributes that are needed. - */ -void -gcr_import_interaction_supplement_prep (GcrImportInteraction *interaction, - GckAttributes *attributes) -{ - GcrImportInteractionIface *iface; - - g_return_if_fail (GCR_IS_IMPORT_INTERACTION (interaction)); - g_return_if_fail (attributes != NULL); - - iface = GCR_IMPORT_INTERACTION_GET_INTERFACE (interaction); - if (iface->supplement != NULL) - (iface->supplement_prep) (interaction, attributes); -} - -/** - * gcr_import_interaction_supplement: - * @interaction: the interaction - * @attributes: supplemented attributes - * @cancellable: optional cancellable object - * @error: location to store error on failure - * - * Supplement attributes before import. This means prompting the user for - * things like labels and the like. The needed attributes will have been passed - * to gcr_import_interaction_supplement_prep(). - * - * This method prompts the user and fills in the attributes. If the user or - * cancellable cancels the operation the error should be set with %G_IO_ERROR_CANCELLED. - * - * Returns: %G_TLS_INTERACTION_HANDLED if successful or %G_TLS_INTERACTION_FAILED - */ -GTlsInteractionResult -gcr_import_interaction_supplement (GcrImportInteraction *interaction, - GckAttributes *attributes, - GCancellable *cancellable, - GError **error) -{ - GcrImportInteractionIface *iface; - - g_return_val_if_fail (GCR_IS_IMPORT_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED); - g_return_val_if_fail (attributes != NULL, G_TLS_INTERACTION_UNHANDLED); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED); - g_return_val_if_fail (error == NULL || *error == NULL, G_TLS_INTERACTION_UNHANDLED); - - iface = GCR_IMPORT_INTERACTION_GET_INTERFACE (interaction); - g_return_val_if_fail (iface->supplement != NULL, G_TLS_INTERACTION_UNHANDLED); - - return (iface->supplement) (interaction, attributes, cancellable, error); -} - - -/** - * gcr_import_interaction_supplement_async: - * @interaction: the interaction - * @attributes: supplemented attributes - * @cancellable: optional cancellable object - * @callback: called when the operation completes - * @user_data: data to be passed to the callback - * - * Asynchronously supplement attributes before import. This means prompting the - * user for things like labels and the like. The needed attributes will have - * been passed to gcr_import_interaction_supplement_prep(). - * - * This method prompts the user and fills in the attributes. - */ -void -gcr_import_interaction_supplement_async (GcrImportInteraction *interaction, - GckAttributes *attributes, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GcrImportInteractionIface *iface; - - g_return_if_fail (GCR_IS_IMPORT_INTERACTION (interaction)); - g_return_if_fail (attributes != NULL); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - iface = GCR_IMPORT_INTERACTION_GET_INTERFACE (interaction); - g_return_if_fail (iface->supplement != NULL); - - (iface->supplement_async) (interaction, attributes, cancellable, callback, user_data); -} - -/** - * gcr_import_interaction_supplement_finish: - * @interaction: the interaction - * @result: the asynchronous result - * @error: location to place an error on failure - * - * Complete operation to asynchronously supplement attributes before import. - * - * If the user or cancellable cancels the operation the error should be set - * with %G_IO_ERROR_CANCELLED. - * - * Returns: %G_TLS_INTERACTION_HANDLED if successful or %G_TLS_INTERACTION_FAILED - */ -GTlsInteractionResult -gcr_import_interaction_supplement_finish (GcrImportInteraction *interaction, - GAsyncResult *result, - GError **error) -{ - GcrImportInteractionIface *iface; - - g_return_val_if_fail (GCR_IS_IMPORT_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED); - g_return_val_if_fail (G_IS_ASYNC_RESULT (result), G_TLS_INTERACTION_UNHANDLED); - g_return_val_if_fail (error == NULL || *error == NULL, G_TLS_INTERACTION_UNHANDLED); - - iface = GCR_IMPORT_INTERACTION_GET_INTERFACE (interaction); - g_return_val_if_fail (iface->supplement != NULL, G_TLS_INTERACTION_UNHANDLED); - - return (iface->supplement_finish) (interaction, result, error); -} diff --git a/gcr/gcr-import-interaction.h b/gcr/gcr-import-interaction.h deleted file mode 100644 index 2793d139..00000000 --- a/gcr/gcr-import-interaction.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_IMPORT_INTERACTION_H__ -#define __GCR_IMPORT_INTERACTION_H__ - -#include "gcr-importer.h" - -#include <glib-object.h> - -#include <gio/gio.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_IMPORT_INTERACTION (gcr_import_interaction_get_type ()) -#define GCR_IMPORT_INTERACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_IMPORT_INTERACTION, GcrImportInteraction)) -#define GCR_IS_IMPORT_INTERACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_IMPORT_INTERACTION)) -#define GCR_IMPORT_INTERACTION_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_IMPORT_INTERACTION, GcrImportInteractionIface)) - -typedef struct _GcrImportInteraction GcrImportInteraction; -typedef struct _GcrImportInteractionIface GcrImportInteractionIface; - -struct _GcrImportInteractionIface { - GTypeInterface parent; - - void (*supplement_prep) (GcrImportInteraction *interaction, - GckAttributes *attributes); - - GTlsInteractionResult (*supplement) (GcrImportInteraction *interaction, - GckAttributes *attributes, - GCancellable *cancellable, - GError **error); - - void (*supplement_async) (GcrImportInteraction *interaction, - GckAttributes *attributes, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - - GTlsInteractionResult (*supplement_finish) (GcrImportInteraction *interaction, - GAsyncResult *result, - GError **error); - - /*< private >*/ - gpointer reserved[6]; -}; - -GType gcr_import_interaction_get_type (void); - -void gcr_import_interaction_supplement_prep (GcrImportInteraction *interaction, - GckAttributes *attributes); - -GTlsInteractionResult gcr_import_interaction_supplement (GcrImportInteraction *interaction, - GckAttributes *attributes, - GCancellable *cancellable, - GError **error); - -void gcr_import_interaction_supplement_async (GcrImportInteraction *interaction, - GckAttributes *attributes, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -GTlsInteractionResult gcr_import_interaction_supplement_finish (GcrImportInteraction *interaction, - GAsyncResult *result, - GError **error); - -G_END_DECLS - -#endif /* __GCR_IMPORT_INTERACTION_H__ */ diff --git a/gcr/gcr-importer.c b/gcr/gcr-importer.c deleted file mode 100644 index cb572851..00000000 --- a/gcr/gcr-importer.c +++ /dev/null @@ -1,628 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-deprecated-base.h" -#include "gcr-importer.h" -#include "gcr-internal.h" -#include "gcr-marshal.h" -#include "gcr-gnupg-importer.h" -#include "gcr-parser.h" -#include "gcr-pkcs11-importer.h" - -#include <glib/gi18n-lib.h> - -/** - * SECTION:gcr-importer - * @title: GcrImporter - * @short_description: Import certificates and keys - * - * An interface which allows importing of certificates and keys. Each - * #GcrImporter is registered with a set of PKCS\#11 attributes to match - * stuff that it can import. - * - * An importer gets passed a #GcrParser and accesses the currently parsed - * item. To create a set of importers that can import the currently parsed - * item in a #GcrParser, use gcr_importer_create_for_parsed(). The list of - * importers returned has the parsed item queued for import. - * - * To queue additional items with a importer use gcr_importer_queue_for_parsed(). - * In addition you can try and queue an additional item with a set of importers - * using the gcr_importer_queue_and_filter_for_parsed(). - * - * To start the import use gcr_importer_import() or the async variants. - */ - -/** - * GcrImporter: - * - * Imports certificates and keys - */ - -/** - * GcrImporterIface: - * @parent: parent interface - * @create_for_parsed: implementation of gcr_importer_create_for_parsed(), required - * @queue_for_parsed: implementation of gcr_importer_queue_for_parsed(), required - * @import_sync: optional implemantionon of gcr_importer_import() - * @import_async: implementation of gcr_importer_import_async(), required - * @import_finish: implementation of gcr_importer_import_finish() - * - * Interface implemented for a #GcrImporter. - */ - -typedef GcrImporterIface GcrImporterInterface; - -G_DEFINE_INTERFACE (GcrImporter, gcr_importer, G_TYPE_OBJECT); - -typedef struct _GcrRegistered { - GckAttributes *attrs; - GType importer_type; -} GcrRegistered; - -static GArray *registered_importers = NULL; -static gboolean registered_sorted = FALSE; - -static void -gcr_importer_default_init (GcrImporterIface *iface) -{ - static volatile gsize initialized = 0; - - if (g_once_init_enter (&initialized)) { - - /** - * GcrImporter:label: - * - * The label for the importer. - */ - g_object_interface_install_property (iface, - g_param_spec_string ("label", "Label", "The label for the importer", - "", G_PARAM_READABLE)); - - /** - * GcrImporter:icon: - * - * The icon for the importer. - */ - g_object_interface_install_property (iface, - g_param_spec_object ("icon", "Icon", "The icon for the importer", - G_TYPE_ICON, G_PARAM_READABLE)); - - /** - * GcrImporter:interaction: - * - * The interaction for the importer. - */ - g_object_interface_install_property (iface, - g_param_spec_object ("interaction", "Interaction", - "Interaction for prompts", - G_TYPE_TLS_INTERACTION, G_PARAM_READWRITE)); - - g_once_init_leave (&initialized, 1); - } -} - -/** - * gcr_importer_register: - * @importer_type: the GType of the importer being registered - * @attrs: the attributes that this importer is compatible with - * - * Register an importer to handle parsed items that match the given attributes. - */ -void -gcr_importer_register (GType importer_type, - GckAttributes *attrs) -{ - GcrRegistered registered; - - if (!registered_importers) - registered_importers = g_array_new (FALSE, FALSE, sizeof (GcrRegistered)); - - registered.importer_type = importer_type; - registered.attrs = gck_attributes_ref (attrs); - g_array_append_val (registered_importers, registered); - registered_sorted = FALSE; -} - -static gint -sort_registered_by_n_attrs (gconstpointer a, gconstpointer b) -{ - const GcrRegistered *ra = a; - const GcrRegistered *rb = b; - gulong na, nb; - - g_assert (a); - g_assert (b); - - na = gck_attributes_count (ra->attrs); - nb = gck_attributes_count (rb->attrs); - - /* Note we're sorting in reverse order */ - if (na < nb) - return 1; - return (na == nb) ? 0 : -1; -} - -static gboolean -check_if_seen_or_add (GHashTable *seen, - gpointer key) -{ - if (g_hash_table_lookup (seen, key)) - return TRUE; - g_hash_table_insert (seen, key, key); - return FALSE; -} - -/** - * gcr_importer_create_for_parsed: - * @parsed: a parser with a parsed item to import - * - * Create a set of importers which can import this parsed item. - * The parsed item is represented by the state of the GcrParser at the - * time of calling this method. - * - * Returns: (element-type Gcr.Importer) (transfer full): a list of importers - * which can import the parsed item, which should be freed with - * g_object_unref(), or %NULL if no types of importers can be created - */ -GList * -gcr_importer_create_for_parsed (GcrParsed *parsed) -{ - GcrRegistered *registered; - GcrImporterIface *iface; - gpointer instance_class; - GckAttributes *attrs; - gboolean matched; - gulong n_attrs; - GList *results = NULL; - GHashTable *seen; - gulong j; - gsize i; - - g_return_val_if_fail (parsed != NULL, NULL); - - gcr_importer_register_well_known (); - - if (!registered_importers) - return NULL; - - if (!registered_sorted) { - g_array_sort (registered_importers, sort_registered_by_n_attrs); - registered_sorted = TRUE; - } - - attrs = gcr_parsed_get_attributes (parsed); - if (attrs != NULL) - gck_attributes_ref (attrs); - else - attrs = gck_attributes_new (); - - seen = g_hash_table_new (g_direct_hash, g_direct_equal); - - for (i = 0; i < registered_importers->len; ++i) { - registered = &(g_array_index (registered_importers, GcrRegistered, i)); - n_attrs = gck_attributes_count (registered->attrs); - - matched = TRUE; - - for (j = 0; j < n_attrs; ++j) { - if (!gck_attributes_contains (attrs, gck_attributes_at (registered->attrs, j))) { - matched = FALSE; - break; - } - } - - if (matched) { - if (check_if_seen_or_add (seen, GUINT_TO_POINTER (registered->importer_type))) - continue; - - instance_class = g_type_class_ref (registered->importer_type); - - iface = g_type_interface_peek (instance_class, GCR_TYPE_IMPORTER); - g_return_val_if_fail (iface != NULL, NULL); - g_return_val_if_fail (iface->create_for_parsed, NULL); - results = g_list_concat (results, (iface->create_for_parsed) (parsed)); - - g_type_class_unref (instance_class); - } - } - - g_hash_table_unref (seen); - gck_attributes_unref (attrs); - return results; -} - -/** - * gcr_importer_queue_for_parsed: - * @importer: an importer to add additional items to - * @parsed: a parsed item to import - * - * Queues an additional item to be imported. The parsed item is represented - * by the state of the #GcrParser at the time of calling this method. - * - * If the parsed item is incompatible with the importer, then this will - * fail and the item will not be queued. - * - * Returns: whether the item was queued or not - */ -gboolean -gcr_importer_queue_for_parsed (GcrImporter *importer, - GcrParsed *parsed) -{ - GcrImporterIface *iface; - - g_return_val_if_fail (GCR_IS_IMPORTER (importer), FALSE); - g_return_val_if_fail (parsed != NULL, FALSE); - - iface = GCR_IMPORTER_GET_INTERFACE (importer); - g_return_val_if_fail (iface != NULL, FALSE); - g_return_val_if_fail (iface->queue_for_parsed != NULL, FALSE); - - return (iface->queue_for_parsed) (importer, parsed); -} - -/** - * gcr_importer_queue_and_filter_for_parsed: - * @importers: (element-type Gcr.Importer): a set of importers - * @parsed: a parsed item - * - * Queues an additional item to be imported in all compattible importers - * in the set. The parsed item is represented by the state of the #GcrParser - * at the time of calling this method. - * - * If the parsed item is incompatible with an importer, then that the item - * will not be queued on that importer. - * - * Returns: (transfer full) (element-type Gcr.Importer): a new set of importers - * that queued the item, which should be freed with gck_list_unref_free() - */ -GList * -gcr_importer_queue_and_filter_for_parsed (GList *importers, - GcrParsed *parsed) -{ - GList *results = NULL; - GList *l; - - for (l = importers; l != NULL; l = g_list_next (l)) { - if (gcr_importer_queue_for_parsed (l->data, parsed)) - results = g_list_prepend (results, g_object_ref (l->data)); - } - - return g_list_reverse (results); -} - -typedef struct { - gboolean complete; - GCond *cond; - GMutex *mutex; - GError *error; - GMainContext *context; -} ImportClosure; - -static void -on_import_async_complete (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - ImportClosure *closure = user_data; - GError *error = NULL; - - if (!gcr_importer_import_finish (GCR_IMPORTER (source), result, &error)) { - if (error == NULL) { - g_warning ("%s::import_finished returned false, but did not set error", - G_OBJECT_TYPE_NAME (source)); - } - } - - g_mutex_lock (closure->mutex); - - closure->complete = TRUE; - closure->error = error; - g_cond_signal (closure->cond); - - g_mutex_unlock (closure->mutex); -} - -/** - * gcr_importer_import: - * @importer: the importer - * @cancellable: a #GCancellable, or %NULL - * @error: the location to place an error on failure, or %NULL - * - * Import the queued items in the importer. This call will block - * until the operation completes. - * - * Returns: whether the items were imported successfully or not - */ -gboolean -gcr_importer_import (GcrImporter *importer, - GCancellable *cancellable, - GError **error) -{ - gboolean result; - ImportClosure *closure; - GcrImporterIface *iface; - - g_return_val_if_fail (GCR_IS_IMPORTER (importer), FALSE); - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - iface = GCR_IMPORTER_GET_INTERFACE (importer); - if (iface->import_sync) - return (iface->import_sync) (importer, cancellable, error); - - g_return_val_if_fail (iface->import_async != NULL, FALSE); - g_return_val_if_fail (iface->import_finish != NULL, FALSE); - - closure = g_new0 (ImportClosure, 1); - closure->cond = g_cond_new (); - closure->mutex = g_mutex_new (); - closure->context = g_main_context_get_thread_default (); - g_mutex_lock (closure->mutex); - - (iface->import_async) (importer, cancellable, on_import_async_complete, closure); - - /* - * Handle the case where we've been called from within the main context - * or in the case where the main context is not running. This approximates - * the behavior of a modal dialog. - */ - if (g_main_context_acquire (closure->context)) { - while (!closure->complete) { - g_mutex_unlock (closure->mutex); - g_main_context_iteration (closure->context, TRUE); - g_mutex_lock (closure->mutex); - } - - g_main_context_release (closure->context); - - /* - * Handle the case where we're in a different thread than the main - * context and a main loop is running. - */ - } else { - while (!closure->complete) - g_cond_wait (closure->cond, closure->mutex); - } - - g_mutex_unlock (closure->mutex); - - result = (closure->error == NULL); - if (closure->error) - g_propagate_error (error, closure->error); - - g_cond_free (closure->cond); - g_mutex_free (closure->mutex); - g_free (closure); - - return result; -} - -/** - * gcr_importer_import_async: - * @importer: the importer - * @cancellable: a #GCancellable, or %NULL - * @callback: called when the operation completes - * @user_data: data to be passed to the callback - * - * Import the queued items in the importer. This function returns immediately - * and completes asynchronously. - */ -void -gcr_importer_import_async (GcrImporter *importer, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GcrImporterIface *iface; - - g_return_if_fail (GCR_IS_IMPORTER (importer)); - g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - - iface = GCR_IMPORTER_GET_INTERFACE (importer); - g_return_if_fail (iface != NULL); - g_return_if_fail (iface->import_async != NULL); - - return (iface->import_async) (importer, cancellable, callback, user_data); -} - -/** - * gcr_importer_import_finish: - * @importer: the importer - * @result: an asynchronous result - * @error: the location to place an error on failure, or %NULL - * - * Complete an asynchronous operation to import queued items. - * - * Returns: whether the import succeeded or failed - */ -gboolean -gcr_importer_import_finish (GcrImporter *importer, - GAsyncResult *result, - GError **error) -{ - GcrImporterIface *iface; - - g_return_val_if_fail (GCR_IS_IMPORTER (importer), FALSE); - g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - - iface = GCR_IMPORTER_GET_INTERFACE (importer); - g_return_val_if_fail (iface != NULL, FALSE); - g_return_val_if_fail (iface->import_finish != NULL, FALSE); - - return (iface->import_finish) (importer, result, error); -} - -/** - * gcr_importer_get_interaction: - * @importer: the importer - * - * Get the interaction used to prompt the user when needed by this - * importer. - * - * Returns: (transfer none) (allow-none): the interaction or %NULL - */ -GTlsInteraction * -gcr_importer_get_interaction (GcrImporter *importer) -{ - GTlsInteraction *interaction = NULL; - - g_return_val_if_fail (GCR_IS_IMPORTER (importer), NULL); - - g_object_get (importer, "interaction", &interaction, NULL); - - if (interaction != NULL) - g_object_unref (interaction); - - return interaction; -} - -/** - * gcr_importer_set_interaction: - * @importer: the importer - * @interaction: the interaction used by the importer - * - * Set the interaction used to prompt the user when needed by this - * importer. - */ -void -gcr_importer_set_interaction (GcrImporter *importer, - GTlsInteraction *interaction) -{ - g_return_if_fail (GCR_IS_IMPORTER (importer)); - g_object_set (importer, "interaction", interaction, NULL); -} - -/** - * gcr_importer_register_well_known: - * - * Register built-in PKCS\#11 and GnuPG importers. - */ -void -gcr_importer_register_well_known (void) -{ - g_type_class_unref (g_type_class_ref (GCR_TYPE_PKCS11_IMPORTER)); - g_type_class_unref (g_type_class_ref (GCR_TYPE_GNUPG_IMPORTER)); -} - -#ifndef GCR_DISABLE_DEPRECATED - -/** - * gcr_importer_get_parser: - * @self: An importer - * - * Has no effect. Use gcr_importer_listen() instead. - * - * Returns: %NULL is always returned. - * Deprecated: Since 3.0.0 - */ -GcrParser* -gcr_importer_get_parser (GcrImporter *self) -{ - g_warning ("gcr_importer_get_parser() is no longer supported " - "Use gcr_importer_listen() instead."); - return NULL; -} - -/** - * gcr_importer_set_parser: - * @self: An importer - * @parser: A parser - * - * Has no effect. Use gcr_importer_listen() instead. - * - * Deprecated: Since 3.0.0 - */ -void -gcr_importer_set_parser (GcrImporter *self, - GcrParser *parser) -{ - g_warning ("gcr_importer_set_parser() is no longer supported " - "Use gcr_importer_listen() instead."); -} - -/* - * gcr_importer_get_slot: - * @self: The importer - * - * Returns %NULL. - * - * Deprecated: since 3.4.0 - */ -GckSlot * -gcr_importer_get_slot (GcrImporter *self) -{ - g_warning ("gcr_importer_get_slot() is no longer supported."); - return NULL; -} - -/** - * gcr_importer_set_slot: - * @self: The importer - * @slot: The slot to import to - * - * Has no effect. - * - * Deprecated: since 3.4.0 - */ -void -gcr_importer_set_slot (GcrImporter *self, - GckSlot *slot) -{ - g_warning ("gcr_importer_set_slot() is no longer supported."); -} - -/** - * gcr_importer_get_prompt_behavior: - * @self: The importer - * - * Returns: zero - * - * Deprecated: since 3.4.0 - */ -GcrImporterPromptBehavior -gcr_importer_get_prompt_behavior (GcrImporter *self) -{ - g_warning ("gcr_importer_get_prompt_behavior() is no longer supported."); - return 0; -} - -/** - * gcr_importer_set_prompt_behavior: - * @self: The importer - * @behavior: The prompt behavior flag - * - * Has no effect. - * - * Deprecated: since 3.4.0 - */ -void -gcr_importer_set_prompt_behavior (GcrImporter *self, - GcrImporterPromptBehavior behavior) -{ - g_warning ("gcr_importer_set_prompt_behavior() is no longer supported."); -} - -#endif /* GCR_DISABLE_DEPRECATED */ diff --git a/gcr/gcr-importer.h b/gcr/gcr-importer.h deleted file mode 100644 index d9159408..00000000 --- a/gcr/gcr-importer.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_IMPORTER_H__ -#define __GCR_IMPORTER_H__ - -#include "gcr-parser.h" - -#include <glib-object.h> - -#include <gio/gio.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_IMPORTER (gcr_importer_get_type ()) -#define GCR_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_IMPORTER, GcrImporter)) -#define GCR_IS_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_IMPORTER)) -#define GCR_IMPORTER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_IMPORTER, GcrImporterIface)) - -typedef struct _GcrImporter GcrImporter; -typedef struct _GcrImporterIface GcrImporterIface; - -struct _GcrImporterIface { - GTypeInterface parent; - - GList * (*create_for_parsed) (GcrParsed *parsed); - - gboolean (*queue_for_parsed) (GcrImporter *importer, - GcrParsed *parsed); - - gboolean (*import_sync) (GcrImporter *importer, - GCancellable *cancellable, - GError **error); - - void (*import_async) (GcrImporter *importer, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - - gboolean (*import_finish) (GcrImporter *importer, - GAsyncResult *result, - GError **error); - - /*< private >*/ - gpointer reserved[14]; -}; - -GType gcr_importer_get_type (void); - -GList * gcr_importer_create_for_parsed (GcrParsed *parsed); - -gboolean gcr_importer_queue_for_parsed (GcrImporter *importer, - GcrParsed *parsed); - -GList * gcr_importer_queue_and_filter_for_parsed (GList *importers, - GcrParsed *parsed); - -gboolean gcr_importer_import (GcrImporter *importer, - GCancellable *cancellable, - GError **error); - -void gcr_importer_import_async (GcrImporter *importer, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean gcr_importer_import_finish (GcrImporter *importer, - GAsyncResult *result, - GError **error); - -GTlsInteraction * gcr_importer_get_interaction (GcrImporter *importer); - -void gcr_importer_set_interaction (GcrImporter *importer, - GTlsInteraction *interaction); - -void gcr_importer_register (GType importer_type, - GckAttributes *attrs); - -void gcr_importer_register_well_known (void); - -G_END_DECLS - -#endif /* __GCR_IMPORTER_H__ */ diff --git a/gcr/gcr-internal.h b/gcr/gcr-internal.h deleted file mode 100644 index ef6153fc..00000000 --- a/gcr/gcr-internal.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef GCR_INTERNAL_H_ -#define GCR_INTERNAL_H_ - -#include <glib.h> -#include <gio/gio.h> - -/* Should only be used internally */ -#define GCR_SUCCESS 0 - -void _gcr_initialize_library (void); - -void _gcr_set_pkcs11_config_dir (const gchar *dir); - -#endif /* GCR_INTERNAL_H_ */ diff --git a/gcr/gcr-key-renderer.c b/gcr/gcr-key-renderer.c deleted file mode 100644 index 91020692..00000000 --- a/gcr/gcr-key-renderer.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-key-renderer.h" -#include "gcr-display-view.h" -#include "gcr-fingerprint.h" -#include "gcr-icons.h" -#include "gcr-renderer.h" -#include "gcr-viewer.h" - -#include "gck/gck.h" - -#include <gdk/gdk.h> -#include <glib/gi18n-lib.h> - -/** - * GcrKeyRenderer: - * - * An implementation of #GcrRenderer which renders keys. - */ - -/** - * GcrKeyRendererClass: - * @parent_class: The parent class. - * - * The class for #GcrKeyRenderer. - */ - -enum { - PROP_0, - PROP_LABEL, - PROP_ATTRIBUTES -}; - -struct _GcrKeyRendererPrivate { - guint key_size; - gchar *label; - GckAttributes *attributes; - GIcon *icon; -}; - -static void gcr_key_renderer_renderer_iface (GcrRendererIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrKeyRenderer, gcr_key_renderer, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_key_renderer_renderer_iface)); - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -static gchar* -calculate_label (GcrKeyRenderer *self) -{ - gchar *label; - - if (self->pv->label) - return g_strdup (self->pv->label); - - if (self->pv->attributes) { - if (gck_attributes_find_string (self->pv->attributes, CKA_LABEL, &label)) - return label; - } - - return g_strdup (_("Key")); -} - -static gint -calculate_rsa_key_size (GckAttributes *attrs) -{ - GckAttribute *attr; - gulong bits; - - attr = gck_attributes_find (attrs, CKA_MODULUS); - - /* Calculate the bit length, and remove the complement */ - if (attr != NULL) - return (attr->length / 2) * 2 * 8; - - if (gck_attributes_find_ulong (attrs, CKA_MODULUS_BITS, &bits)) - return (gint)bits; - - return -1; -} - -static guint -calculate_dsa_key_size (GckAttributes *attrs) -{ - GckAttribute *attr; - gulong bits; - - attr = gck_attributes_find (attrs, CKA_PRIME); - - /* Calculate the bit length, and remove the complement */ - if (attr != NULL) - return (attr->length / 2) * 2 * 8; - - if (gck_attributes_find_ulong (attrs, CKA_PRIME_BITS, &bits)) - return (gint)bits; - - return -1; -} - -static gint -calculate_key_size (GckAttributes *attrs, gulong key_type) -{ - if (key_type == CKK_RSA) - return calculate_rsa_key_size (attrs); - else if (key_type == CKK_DSA) - return calculate_dsa_key_size (attrs); - else - return -1; -} - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static void -gcr_key_renderer_init (GcrKeyRenderer *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_KEY_RENDERER, GcrKeyRendererPrivate)); - self->pv->icon = g_themed_icon_new (GCR_ICON_KEY); -} - -static void -gcr_key_renderer_dispose (GObject *obj) -{ - G_OBJECT_CLASS (gcr_key_renderer_parent_class)->dispose (obj); -} - -static void -gcr_key_renderer_finalize (GObject *obj) -{ - GcrKeyRenderer *self = GCR_KEY_RENDERER (obj); - - if (self->pv->attributes) - gck_attributes_unref (self->pv->attributes); - self->pv->attributes = NULL; - - g_free (self->pv->label); - self->pv->label = NULL; - - if (self->pv->icon) - g_object_unref (self->pv->icon); - self->pv->icon = NULL; - - G_OBJECT_CLASS (gcr_key_renderer_parent_class)->finalize (obj); -} - -static void -gcr_key_renderer_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrKeyRenderer *self = GCR_KEY_RENDERER (obj); - - switch (prop_id) { - case PROP_LABEL: - g_free (self->pv->label); - self->pv->label = g_value_dup_string (value); - g_object_notify (obj, "label"); - gcr_renderer_emit_data_changed (GCR_RENDERER (self)); - break; - case PROP_ATTRIBUTES: - g_return_if_fail (!self->pv->attributes); - self->pv->attributes = g_value_dup_boxed (value); - gcr_renderer_emit_data_changed (GCR_RENDERER (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_key_renderer_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrKeyRenderer *self = GCR_KEY_RENDERER (obj); - - switch (prop_id) { - case PROP_LABEL: - g_value_take_string (value, calculate_label (self)); - break; - case PROP_ATTRIBUTES: - g_value_set_boxed (value, self->pv->attributes); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_key_renderer_class_init (GcrKeyRendererClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GckAttributes *registered; - - gcr_key_renderer_parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private (klass, sizeof (GcrKeyRendererPrivate)); - - gobject_class->dispose = gcr_key_renderer_dispose; - gobject_class->finalize = gcr_key_renderer_finalize; - gobject_class->set_property = gcr_key_renderer_set_property; - gobject_class->get_property = gcr_key_renderer_get_property; - - g_object_class_override_property (gobject_class, PROP_LABEL, "label"); - g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes"); - - /* Register this as a view which can be loaded */ - registered = gck_attributes_new (); - gck_attributes_add_ulong (registered, CKA_CLASS, CKO_PRIVATE_KEY); - gcr_renderer_register (GCR_TYPE_KEY_RENDERER, registered); - gck_attributes_unref (registered); -} - -static void -gcr_key_renderer_real_render (GcrRenderer *renderer, GcrViewer *viewer) -{ - GcrKeyRenderer *self; - GcrDisplayView *view; - const gchar *text = ""; - gpointer fingerprint; - gsize n_fingerprint; - gchar *display; - gulong klass; - gulong key_type; - gint size; - - self = GCR_KEY_RENDERER (renderer); - - if (GCR_IS_DISPLAY_VIEW (viewer)) { - view = GCR_DISPLAY_VIEW (viewer); - - } else { - g_warning ("GcrKeyRenderer only works with internal specific " - "GcrViewer returned by gcr_viewer_new()."); - return; - } - - _gcr_display_view_begin (view, renderer); - - if (!self->pv->attributes) { - _gcr_display_view_end (view, renderer); - return; - } - - if (!gck_attributes_find_ulong (self->pv->attributes, CKA_CLASS, &klass) || - !gck_attributes_find_ulong (self->pv->attributes, CKA_KEY_TYPE, &key_type)) { - g_warning ("private key does not have the CKA_CLASS and CKA_KEY_TYPE attributes"); - _gcr_display_view_end (view, renderer); - return; - } - - _gcr_display_view_set_icon (view, renderer, self->pv->icon); - - display = calculate_label (self); - _gcr_display_view_append_title (view, renderer, display); - g_free (display); - - if (klass == CKO_PRIVATE_KEY) { - if (key_type == CKK_RSA) - text = _("Private RSA Key"); - else if (key_type == CKK_DSA) - text = _("Private DSA Key"); - else - text = _("Private Key"); - } else if (klass == CKO_PUBLIC_KEY) { - if (key_type == CKK_RSA) - text = _("Public DSA Key"); - else if (key_type == CKK_DSA) - text = _("Public DSA Key"); - else - text = _("Public Key"); - } - - _gcr_display_view_append_content (view, renderer, text, NULL); - - size = calculate_key_size (self->pv->attributes, key_type); - if (size >= 0) { - display = g_strdup_printf (ngettext ("%d bit", "%d bits", size), size); - _gcr_display_view_append_content (view, renderer, _("Strength"), display); - g_free (display); - } - - _gcr_display_view_start_details (view, renderer); - - - if (key_type == CKK_RSA) - text = _("RSA"); - else if (key_type == CKK_DSA) - text = _("DSA"); - else - text = _("Unknown"); - _gcr_display_view_append_value (view, renderer, _("Algorithm"), text, FALSE); - - size = calculate_key_size (self->pv->attributes, key_type); - if (size < 0) - display = g_strdup (_("Unknown")); - else - display = g_strdup_printf ("%d", size); - _gcr_display_view_append_value (view, renderer, _("Size"), display, FALSE); - g_free (display); - - /* Fingerprints */ - _gcr_display_view_append_heading (view, renderer, _("Fingerprints")); - - fingerprint = gcr_fingerprint_from_attributes (self->pv->attributes, - G_CHECKSUM_SHA1, &n_fingerprint); - if (fingerprint) { - _gcr_display_view_append_hex (view, renderer, _("SHA1"), fingerprint, n_fingerprint); - g_free (fingerprint); - } - fingerprint = gcr_fingerprint_from_attributes (self->pv->attributes, - G_CHECKSUM_SHA256, &n_fingerprint); - if (fingerprint) { - _gcr_display_view_append_hex (view, renderer, _("SHA256"), fingerprint, n_fingerprint); - g_free (fingerprint); - } - - _gcr_display_view_end (view, renderer); -} - -static void -gcr_key_renderer_renderer_iface (GcrRendererIface *iface) -{ - iface->render_view = gcr_key_renderer_real_render; -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_key_renderer_new: - * @label: (allow-none): label describing the key - * @attrs: (allow-none): key to display, or %NULL - * - * Create a new key renderer which renders a given key in the attributes. - * - * Returns: (transfer full): a newly allocated #GcrKeyRenderer, which should be - * freed with g_object_unref() - */ -GcrKeyRenderer* -gcr_key_renderer_new (const gchar *label, GckAttributes *attrs) -{ - return g_object_new (GCR_TYPE_KEY_RENDERER, "label", label, "attributes", attrs, NULL); -} - -/** - * gcr_key_renderer_set_attributes: - * @self: The key renderer - * @attrs: (allow-none): the attributes to display - * - * Get the attributes displayed in the renderer. The attributes should represent - * either an RSA or DSA key in PKCS\#11 style. - */ -void -gcr_key_renderer_set_attributes (GcrKeyRenderer *self, GckAttributes *attrs) -{ - g_return_if_fail (GCR_IS_KEY_RENDERER (self)); - - if (self->pv->attributes) - gck_attributes_unref (self->pv->attributes); - self->pv->attributes = attrs; - if (self->pv->attributes) - gck_attributes_ref (self->pv->attributes); - - g_object_notify (G_OBJECT (self), "attributes"); - gcr_renderer_emit_data_changed (GCR_RENDERER (self)); -} - -/** - * gcr_key_renderer_get_attributes: - * @self: The key renderer - * - * Get the attributes displayed in the renderer. - * - * Returns: (transfer none) (allow-none): the attributes, owned by the renderer - */ -GckAttributes* -gcr_key_renderer_get_attributes (GcrKeyRenderer *self) -{ - g_return_val_if_fail (GCR_IS_KEY_RENDERER (self), NULL); - return self->pv->attributes; -} diff --git a/gcr/gcr-key-renderer.h b/gcr/gcr-key-renderer.h deleted file mode 100644 index 1c796444..00000000 --- a/gcr/gcr-key-renderer.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_KEY_RENDERER_H__ -#define __GCR_KEY_RENDERER_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_KEY_RENDERER (gcr_key_renderer_get_type ()) -#define GCR_KEY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_KEY_RENDERER, GcrKeyRenderer)) -#define GCR_KEY_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_KEY_RENDERER, GcrKeyRendererClass)) -#define GCR_IS_KEY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_KEY_RENDERER)) -#define GCR_IS_KEY_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_KEY_RENDERER)) -#define GCR_KEY_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_KEY_RENDERER, GcrKeyRendererClass)) - -typedef struct _GcrKeyRenderer GcrKeyRenderer; -typedef struct _GcrKeyRendererClass GcrKeyRendererClass; -typedef struct _GcrKeyRendererPrivate GcrKeyRendererPrivate; - -struct _GcrKeyRenderer { - GObject parent; - - /*< private >*/ - GcrKeyRendererPrivate *pv; -}; - -struct _GcrKeyRendererClass { - GObjectClass parent_class; -}; - -GType gcr_key_renderer_get_type (void); - -GcrKeyRenderer* gcr_key_renderer_new (const gchar *label, - GckAttributes *attrs); - -void gcr_key_renderer_set_attributes (GcrKeyRenderer *self, - GckAttributes *attrs); - -GckAttributes* gcr_key_renderer_get_attributes (GcrKeyRenderer *self); - -G_END_DECLS - -#endif /* __GCR_KEY_RENDERER_H__ */ diff --git a/gcr/gcr-key-widget.c b/gcr/gcr-key-widget.c deleted file mode 100644 index 65b57911..00000000 --- a/gcr/gcr-key-widget.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-key-renderer.h" -#include "gcr-key-widget.h" -#include "gcr-renderer.h" -#include "gcr-viewer.h" - -#include "gck/gck.h" - -#include <gdk/gdk.h> -#include <glib/gi18n-lib.h> - -/** - * SECTION:gcr-key-widget - * @title: GcrKeyWidget - * @short_description: Key widget and renderer - * - * A #GcrKeyWidget can be used to display a RSA or DSA key. The widget - * is normally in a collapsed state showing only details, but can be expanded - * by the user. - * - * Use gcr_key_widget_new() to create a new key widget. Only - * one key can be displayed. A #GcrKeyWidget contains a - * #GcrViewer internally and #GcrKeyRenderer is used to render the - * key to the viewer. To show more than one key in a view, - * create the viewer and add renderers to it. - */ - -/** - * GcrKeyWidget: - * - * A widget that displays a key. - */ - -/** - * GcrKeyWidgetClass: - * - * The class for #GcrKeyWidget - */ -enum { - PROP_0, - PROP_ATTRIBUTES -}; - -struct _GcrKeyWidget { - GtkAlignment parent; - - /*< private >*/ - GcrKeyWidgetPrivate *pv; -}; - -struct _GcrKeyWidgetClass { - /*< private >*/ - GtkAlignmentClass parent_class; -}; - -struct _GcrKeyWidgetPrivate { - GcrViewer *viewer; - GcrKeyRenderer *renderer; -}; - -G_DEFINE_TYPE (GcrKeyWidget, gcr_key_widget, GTK_TYPE_ALIGNMENT); - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static GObject* -gcr_key_widget_constructor (GType type, guint n_props, GObjectConstructParam *props) -{ - GObject *obj = G_OBJECT_CLASS (gcr_key_widget_parent_class)->constructor (type, n_props, props); - GcrKeyWidget *self = NULL; - - g_return_val_if_fail (obj, NULL); - - self = GCR_KEY_WIDGET (obj); - - self->pv->viewer = gcr_viewer_new_scrolled (); - gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (self->pv->viewer)); - gtk_widget_show (GTK_WIDGET (self->pv->viewer)); - - gcr_viewer_add_renderer (self->pv->viewer, GCR_RENDERER (self->pv->renderer)); - return obj; -} - -static void -gcr_key_widget_init (GcrKeyWidget *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_KEY_WIDGET, GcrKeyWidgetPrivate)); - self->pv->renderer = gcr_key_renderer_new (NULL, NULL); -} - -static void -gcr_key_widget_finalize (GObject *obj) -{ - GcrKeyWidget *self = GCR_KEY_WIDGET (obj); - - g_assert (self->pv->renderer); - g_object_unref (self->pv->renderer); - self->pv->renderer = NULL; - - g_assert (self->pv->viewer); - self->pv->viewer = NULL; - - G_OBJECT_CLASS (gcr_key_widget_parent_class)->finalize (obj); -} - -static void -gcr_key_widget_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrKeyWidget *self = GCR_KEY_WIDGET (obj); - - switch (prop_id) { - case PROP_ATTRIBUTES: - gcr_key_widget_set_attributes (self, g_value_get_boxed (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_key_widget_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrKeyWidget *self = GCR_KEY_WIDGET (obj); - - switch (prop_id) { - case PROP_ATTRIBUTES: - g_value_set_boxed (value, gcr_key_widget_get_attributes (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_key_widget_class_init (GcrKeyWidgetClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gcr_key_widget_parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private (klass, sizeof (GcrKeyWidgetPrivate)); - - gobject_class->constructor = gcr_key_widget_constructor; - gobject_class->finalize = gcr_key_widget_finalize; - gobject_class->set_property = gcr_key_widget_set_property; - gobject_class->get_property = gcr_key_widget_get_property; - - g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, - g_param_spec_boxed ("attributes", "Attributes", "The data displayed in the widget", - GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE)); -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_key_widget_new: - * @attrs: (allow-none): key to display, or %NULL - * - * Create a new key widget which displays a given key in the attributes. - * - * Returns: A newly allocated #GcrKeyWidget, which should be freed - * with g_object_unref(). - */ -GcrKeyWidget* -gcr_key_widget_new (GckAttributes *attrs) -{ - return g_object_new (GCR_TYPE_KEY_WIDGET, "attributes", attrs, NULL); -} - -/** - * gcr_key_widget_set_attributes: - * @self: The key widget - * @attrs: (allow-none): the attributes to display - * - * Get the attributes displayed in the widget. The attributes should represent - * either an RSA or DSA key in PKCS\#11 style. - */ -void -gcr_key_widget_set_attributes (GcrKeyWidget *self, GckAttributes *attrs) -{ - g_return_if_fail (GCR_IS_KEY_WIDGET (self)); - gcr_key_renderer_set_attributes (self->pv->renderer, attrs); -} - -/** - * gcr_key_widget_get_attributes: - * @self: The key widget - * - * Get the attributes displayed in the widget. - * - * Returns: (allow-none) (transfer none): The attributes, owned by the widget. - */ -GckAttributes* -gcr_key_widget_get_attributes (GcrKeyWidget *self) -{ - g_return_val_if_fail (GCR_IS_KEY_WIDGET (self), NULL); - return gcr_key_renderer_get_attributes (self->pv->renderer); -} diff --git a/gcr/gcr-key-widget.h b/gcr/gcr-key-widget.h deleted file mode 100644 index 4901aad6..00000000 --- a/gcr/gcr-key-widget.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_KEY_WIDGET_H__ -#define __GCR_KEY_WIDGET_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_KEY_WIDGET (gcr_key_widget_get_type ()) -#define GCR_KEY_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_KEY_WIDGET, GcrKeyWidget)) -#define GCR_KEY_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_KEY_WIDGET, GcrKeyWidgetClass)) -#define GCR_IS_KEY_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_KEY_WIDGET)) -#define GCR_IS_KEY_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_KEY_WIDGET)) -#define GCR_KEY_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_KEY_WIDGET, GcrKeyWidgetClass)) - -typedef struct _GcrKeyWidget GcrKeyWidget; -typedef struct _GcrKeyWidgetClass GcrKeyWidgetClass; -typedef struct _GcrKeyWidgetPrivate GcrKeyWidgetPrivate; - -/* - * TODO: GcrKeyWidget and GcrKeyWidgetClass are hidden until - * we can figure out what they should be derived from. - */ - -GType gcr_key_widget_get_type (void); - -GcrKeyWidget* gcr_key_widget_new (GckAttributes *attrs); - -void gcr_key_widget_set_attributes (GcrKeyWidget *self, - GckAttributes *attrs); - -GckAttributes* gcr_key_widget_get_attributes (GcrKeyWidget *self); - -G_END_DECLS - -#endif /* __GCR_KEY_WIDGET_H__ */ diff --git a/gcr/gcr-library.c b/gcr/gcr-library.c deleted file mode 100644 index 4910e6cd..00000000 --- a/gcr/gcr-library.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-base.h" -#define DEBUG_FLAG GCR_DEBUG_LIBRARY -#include "gcr-debug.h" -#include "gcr-internal.h" -#include "gcr-library.h" -#include "gcr-types.h" - -#include "egg/egg-error.h" -#include "egg/egg-libgcrypt.h" -#include "egg/egg-secure-memory.h" - -#include <p11-kit/p11-kit.h> - -#include <gck/gck.h> - -#include <gcrypt.h> - -#include <glib/gi18n-lib.h> - -/** - * SECTION:gcr-library - * @title: Library Settings - * @short_description: functions for manipulating GCR library global settings. - * - * Manage or lookup various global aspesct and settings of the library. - * - * The GCR library maintains a global list of PKCS\#11 modules to use for - * its various lookups and storage operations. Each module is represented by - * a GckModule object. You can examine this list by using - * gcr_pkcs11_get_modules(). - * - * The list is configured automatically by looking for system installed - * PKCS\#11 modules. It's not not normally necessary to modify this list. But - * if you have special needs, you can use the gcr_pkcs11_set_modules() and - * gcr_pkcs11_add_module() to do so. - * - * Trust assertions are stored and looked up in specific PKCS\#11 slots. - * You can examine this list with gcr_pkcs11_get_trust_lookup_slots() - */ - -/** - * SECTION:gcr-private - * @title: Private declarations - * @short_description: private declarations to supress warnings. - * - * This section is only here to supress warnings, and should not be displayed. - */ - -/** - * GCR_DATA_ERROR: - * - * The #GError domain for data parsing errors. - */ - -G_LOCK_DEFINE_STATIC (modules); -static GList *all_modules = NULL; -static gboolean initialized_modules = FALSE; - -G_LOCK_DEFINE_STATIC (uris); -static gboolean initialized_uris = FALSE; -static gchar *trust_store_uri = NULL; -static gchar **trust_lookup_uris = NULL; - -/* ----------------------------------------------------------------------------- - * ERRORS - */ - -GQuark -gcr_data_error_get_domain (void) -{ - static GQuark domain = 0; - if (domain == 0) - domain = g_quark_from_static_string ("gcr-parser-error"); - return domain; -} - -GQuark -gcr_error_get_domain (void) -{ - static GQuark domain = 0; - if (domain == 0) - domain = g_quark_from_static_string ("gcr-error"); - return domain; -} - -/* ----------------------------------------------------------------------------- - * INITIALIZATION - */ - -void -_gcr_initialize_library (void) -{ - static gint gcr_initialize = 0; - -#if GLIB_CHECK_VERSION (2,29,90) - if (g_atomic_int_add (&gcr_initialize, 1) == 0) -#else - if (g_atomic_int_exchange_and_add (&gcr_initialize, 1) == 0) -#endif - return; - - /* Initialize the libgcrypt library if needed */ - egg_libgcrypt_initialize (); - - _gcr_debug ("initialized library"); -} - -static void -initialize_uris (void) -{ - GPtrArray *uris; - GList *l; - gchar *uri; - gchar *debug; - - g_return_if_fail (initialized_modules); - - if (initialized_uris) - return; - - G_LOCK (uris); - - if (!initialized_uris) { - /* Ask for the global x-trust-store option */ - trust_store_uri = p11_kit_registered_option (NULL, "x-trust-store"); - for (l = all_modules; !trust_store_uri && l != NULL; l = g_list_next (l)) { - trust_store_uri = p11_kit_registered_option (gck_module_get_functions (l->data), - "x-trust-store"); - } - - uris = g_ptr_array_new (); - uri = p11_kit_registered_option (NULL, "x-trust-lookup"); - if (uri != NULL) - g_ptr_array_add (uris, uri); - for (l = all_modules; l != NULL; l = g_list_next (l)) { - uri = p11_kit_registered_option (gck_module_get_functions (l->data), - "x-trust-lookup"); - if (uri != NULL) - g_ptr_array_add (uris, uri); - } - g_ptr_array_add (uris, NULL); - - trust_lookup_uris = (gchar**)g_ptr_array_free (uris, FALSE); - - _gcr_debug ("trust store uri is: %s", trust_store_uri); - debug = g_strjoinv (" ", trust_lookup_uris); - _gcr_debug ("trust lookup uris are: %s", debug); - g_free (debug); - - initialized_uris = TRUE; - } - - G_UNLOCK (uris); -} - -static void -on_initialize_registered (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GError *error = NULL; - GList *results; - - results = gck_modules_initialize_registered_finish (result, &error); - if (error != NULL) { - _gcr_debug ("failed %s", error->message); - g_simple_async_result_take_error (res, error); - - } else { - - G_LOCK (modules); - - if (!initialized_modules) { - all_modules = g_list_concat(all_modules, results); - results = NULL; - initialized_modules = TRUE; - } - - G_UNLOCK (modules); - } - - gck_list_unref_free (results); - - _gcr_debug ("completed initialize of registered modules"); - g_simple_async_result_complete (res); - g_object_unref (res); -} - -/** - * gcr_pkcs11_initialize_async: - * @cancellable: optional cancellable used to cancel the operation - * @callback: callback which will be called when the operation completes - * @user_data: data passed to the callback - * - * Asynchronously initialize the registered PKCS\#11 modules. - */ -void -gcr_pkcs11_initialize_async (GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *res; - - res = g_simple_async_result_new (NULL, callback, user_data, - gcr_pkcs11_initialize_async); - - if (initialized_modules) { - _gcr_debug ("already initialized, no need to async"); - g_simple_async_result_complete_in_idle (res); - } else { - gck_modules_initialize_registered_async (cancellable, - on_initialize_registered, - g_object_ref (res)); - _gcr_debug ("starting initialize of registered modules"); - } - - g_object_unref (res); -} - -/** - * gcr_pkcs11_initialize_finish: - * @result: the asynchronous result - * @error: location to place an error on failure - * - * Complete the asynchronous operation to initialize the registered PKCS\#11 - * modules. - * - * Returns: whether the operation was successful or not. - */ -gboolean -gcr_pkcs11_initialize_finish (GAsyncResult *result, - GError **error) -{ - g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, - gcr_pkcs11_initialize_async), FALSE); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return FALSE; - - return TRUE; -} - -/** - * gcr_pkcs11_initialize: - * @cancellable: optional cancellable used to cancel the operation - * @error: location to place an error on failure - * - * Asynchronously initialize the registered PKCS\#11 modules. - * - * Returns: whether the operation was successful or not. - */ - -gboolean -gcr_pkcs11_initialize (GCancellable *cancellable, - GError **error) -{ - GList *results; - GError *err = NULL; - - if (initialized_modules) - return TRUE; - - results = gck_modules_initialize_registered (cancellable, &err); - if (err == NULL) { - - _gcr_debug ("registered module initialize succeeded: %d modules", - g_list_length (results)); - - G_LOCK (modules); - - if (!initialized_modules) { - all_modules = g_list_concat (all_modules, results); - results = NULL; - initialized_modules = TRUE; - } - - G_UNLOCK (modules); - - } else { - _gcr_debug ("registered module initialize failed: %s", err->message); - g_propagate_error (error, err); - } - - gck_list_unref_free (results); - return (err == NULL); -} - -/** - * gcr_pkcs11_get_modules: - * - * List all the PKCS\#11 modules that are used by the GCR library. - * Each module is a #GckModule object. - * - * When done with the list, free it with gck_list_unref_free(). - * - * Returns: (transfer full) (element-type Gck.Module): a newly allocated list - * of #GckModule objects - */ -GList* -gcr_pkcs11_get_modules (void) -{ - g_return_val_if_fail (initialized_modules, NULL); - if (!all_modules) - _gcr_debug ("no modules loaded"); - return gck_list_ref_copy (all_modules); -} - -/** - * gcr_pkcs11_set_modules: - * @modules: (element-type Gck.Module): a list of #GckModule - * - * Set the list of PKCS\#11 modules that are used by the GCR library. - * Each module in the list is a #GckModule object. - * - * It is not normally necessary to call this function. The available - * PKCS\#11 modules installed on the system are automatically loaded - * by the GCR library. - */ -void -gcr_pkcs11_set_modules (GList *modules) -{ - GList *l; - - for (l = modules; l; l = g_list_next (l)) - g_return_if_fail (GCK_IS_MODULE (l->data)); - - modules = gck_list_ref_copy (modules); - gck_list_unref_free (all_modules); - all_modules = modules; - initialized_modules = TRUE; -} - -/** - * gcr_pkcs11_add_module: - * @module: a #GckModule - * - * Add a #GckModule to the list of PKCS\#11 modules that are used by the - * GCR library. - * - * It is not normally necessary to call this function. The available - * PKCS\#11 modules installed on the system are automatically loaded - * by the GCR library. - */ -void -gcr_pkcs11_add_module (GckModule *module) -{ - g_return_if_fail (GCK_IS_MODULE (module)); - all_modules = g_list_append (all_modules, g_object_ref (module)); -} - -/** - * gcr_pkcs11_add_module_from_file: - * @module_path: the full file path of the PKCS\#11 module - * @unused: unused - * @error: a #GError or NULL - * - * Initialize a PKCS\#11 module and add it to the modules that are - * used by the GCR library. Note that is an error to initialize the same - * PKCS\#11 module twice. - * - * It is not normally necessary to call this function. The available - * PKCS\#11 modules installed on the system are automatically loaded - * by the GCR library. - * - * Returns: whether the module was sucessfully added. - */ -gboolean -gcr_pkcs11_add_module_from_file (const gchar *module_path, gpointer unused, - GError **error) -{ - GckModule *module; - GError *err = NULL; - - g_return_val_if_fail (module_path, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - module = gck_module_initialize (module_path, NULL, &err); - if (module == NULL) { - _gcr_debug ("initializing module failed: %s: %s", - module_path, err->message); - g_propagate_error (error, err); - return FALSE; - } - - gcr_pkcs11_add_module (module); - - _gcr_debug ("initialized and added module: %s", module_path); - g_object_unref (module); - return TRUE; -} - -/** - * gcr_pkcs11_get_trust_store_slot: - * - * Selects an appropriate PKCS\#11 slot to store trust assertions. The slot - * to use is normally configured automatically by the system. - * - * When done with the #GckSlot, use g_object_unref() to release it. - * - * Returns: (transfer full): the #GckSlot to use for trust assertions. - */ -GckSlot * -gcr_pkcs11_get_trust_store_slot (void) -{ - GckSlot *slot; - GError *error = NULL; - - g_return_val_if_fail (initialized_modules, NULL); - - initialize_uris (); - slot = gck_modules_token_for_uri (all_modules, trust_store_uri, &error); - if (!slot) { - if (error) { - g_warning ("error finding slot to store trust assertions: %s: %s", - trust_store_uri, egg_error_message (error)); - g_clear_error (&error); - } else { - _gcr_debug ("no trust store slot found"); - } - } - - return slot; -} - -/** - * gcr_pkcs11_get_trust_lookup_slots: - * - * List all the PKCS\#11 slots that are used by the GCR library for lookup - * of trust assertions. Each slot is a #GckSlot object. - * - * When done with the list, free it with gck_list_unref_free(). - * - * Returns: (transfer full) (element-type Gck.Slot): a list of #GckSlot objects - * to use for lookup of trust. - */ -GList* -gcr_pkcs11_get_trust_lookup_slots (void) -{ - GList *results = NULL; - GError *error = NULL; - gchar **uri; - - g_return_val_if_fail (initialized_modules, NULL); - initialize_uris (); - - for (uri = trust_lookup_uris; uri && *uri; ++uri) { - results = g_list_concat (results, gck_modules_tokens_for_uri (all_modules, *uri, &error)); - if (error != NULL) { - g_warning ("error finding slot for trust assertions: %s: %s", - *uri, egg_error_message (error)); - g_clear_error (&error); - } - } - - if (results == NULL) - _gcr_debug ("no trust lookup slots found"); - - return results; -} - -/** - * gcr_pkcs11_get_trust_store_uri: - * - * Get the PKCS\#11 URI that is used to identify which slot to use for - * storing trust storage. - * - * Returns: (allow-none): the uri which identifies trust storage slot - */ -const gchar* -gcr_pkcs11_get_trust_store_uri (void) -{ - initialize_uris (); - return trust_store_uri; -} - -/** - * gcr_pkcs11_set_trust_store_uri: - * @pkcs11_uri: (allow-none): the uri which identifies trust storage slot - * - * Set the PKCS\#11 URI that is used to identify which slot to use for - * storing trust assertions. - * - * It is not normally necessary to call this function. The relevant - * PKCS\#11 slot is automatically configured by the GCR library. - */ -void -gcr_pkcs11_set_trust_store_uri (const gchar *pkcs11_uri) -{ - G_LOCK (uris); - - g_free (trust_store_uri); - trust_store_uri = g_strdup (pkcs11_uri); - initialized_uris = TRUE; - - G_UNLOCK (uris); -} - - -/** - * gcr_pkcs11_get_trust_lookup_uris: - * - * Get the PKCS\#11 URIs that are used to identify which slots to use for - * lookup trust assertions. - * - * Returns: (allow-none) (transfer none): the uri which identifies trust storage slot - */ -const gchar ** -gcr_pkcs11_get_trust_lookup_uris (void) -{ - initialize_uris (); - return (const gchar **)trust_lookup_uris; -} - -/** - * gcr_pkcs11_set_trust_lookup_uris: - * @pkcs11_uris: (allow-none): the uris which identifies trust lookup slots - * - * Set the PKCS\#11 URIs that are used to identify which slots to use for - * lookup of trust assertions. - * - * It is not normally necessary to call this function. The relevant - * PKCS\#11 slots are automatically configured by the GCR library. - */ -void -gcr_pkcs11_set_trust_lookup_uris (const gchar **pkcs11_uris) -{ - G_LOCK (uris); - - g_strfreev (trust_lookup_uris); - trust_lookup_uris = g_strdupv ((gchar**)pkcs11_uris); - initialized_uris = TRUE; - - G_UNLOCK (uris); -} diff --git a/gcr/gcr-library.h b/gcr/gcr-library.h deleted file mode 100644 index 617a580b..00000000 --- a/gcr/gcr-library.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef GCR_LIBRARY_H_ -#define GCR_LIBRARY_H_ - -#include "gcr-types.h" - -#include <glib.h> - -void gcr_pkcs11_initialize_async (GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean gcr_pkcs11_initialize_finish (GAsyncResult *result, - GError **error); - -gboolean gcr_pkcs11_initialize (GCancellable *cancellable, - GError **error); - -GList* gcr_pkcs11_get_modules (void); - -void gcr_pkcs11_set_modules (GList *modules); - -void gcr_pkcs11_add_module (GckModule *module); - -gboolean gcr_pkcs11_add_module_from_file (const gchar *module_path, - gpointer unused, - GError **error); - -GList* gcr_pkcs11_get_trust_lookup_slots (void); - -GckSlot* gcr_pkcs11_get_trust_store_slot (void); - -const gchar** gcr_pkcs11_get_trust_lookup_uris (void); - -void gcr_pkcs11_set_trust_lookup_uris (const gchar **pkcs11_uris); - -const gchar* gcr_pkcs11_get_trust_store_uri (void); - -void gcr_pkcs11_set_trust_store_uri (const gchar *pkcs11_uri); - -#endif /* GCR_LIBRARY_H_ */ diff --git a/gcr/gcr-list-selector-private.h b/gcr/gcr-list-selector-private.h deleted file mode 100644 index 5f73e0b7..00000000 --- a/gcr/gcr-list-selector-private.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef __GCR_LIST_SELECTOR_PRIVATE_H__ -#define __GCR_LIST_SELECTOR_PRIVATE_H__ - -#include "gcr-types.h" -#include "gcr-list-selector.h" -#include "gcr-live-search.h" - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -void _gcr_list_selector_set_live_search (GcrListSelector *self, - GcrLiveSearch *search); - -G_END_DECLS - -#endif /* __GCR_LIST_SELECTOR_PRIVATE_H__ */ diff --git a/gcr/gcr-list-selector.c b/gcr/gcr-list-selector.c deleted file mode 100644 index 87d354ea..00000000 --- a/gcr/gcr-list-selector.c +++ /dev/null @@ -1,456 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-collection-model.h" -#include "gcr-internal.h" -#include "gcr-list-selector.h" -#include "gcr-list-selector-private.h" -#include "gcr-live-search.h" - -#include <glib/gi18n-lib.h> - -#include <string.h> - -/** - * SECTION:gcr-list-selector - * @title: GcrListSelector - * @short_description: A selector widget to one or more certificates from a list. - * - * The #GcrListSelector can be used to select one or more certificates or keys. - * Live search is available for quick filtering. - */ - -/** - * GcrListSelector: - * - * A list selector widget. - */ - -/** - * GcrListSelectorClass: - * - * The class for #GcrListSelector. - */ - -enum { - PROP_0, - PROP_COLLECTION -}; - -struct _GcrListSelectorPrivate { - GcrCollection *collection; - GcrCollectionModel *model; - - GtkTreeModelFilter *filter; - GtkWidget *search_widget; -}; - -G_DEFINE_TYPE (GcrListSelector, gcr_list_selector, GTK_TYPE_TREE_VIEW); - -static gboolean -object_is_visible (GcrListSelector *self, GObject *object) -{ - gchar *text; - gboolean visible; - - if (g_object_class_find_property (G_OBJECT_GET_CLASS (object), "search-text")) - g_object_get (object, "search-text", &text, NULL); - else - g_object_get (object, "label", &text, NULL); - - visible = _gcr_live_search_match (GCR_LIVE_SEARCH (self->pv->search_widget), text); - g_free (text); - - return visible; -} - -static gboolean -on_tree_filter_visible_func (GtkTreeModel *model, GtkTreeIter *iter, - gpointer user_data) -{ - GcrListSelector *self = GCR_LIST_SELECTOR (user_data); - GObject *object; - - if (self->pv->search_widget == NULL || - !gtk_widget_get_visible (self->pv->search_widget)) - return TRUE; - - object = gcr_collection_model_object_for_iter (self->pv->model, iter); - if (object != NULL) - return object_is_visible (self, object); - - return FALSE; -} - -static gboolean -on_tree_view_start_search (GtkTreeView *view, gpointer user_data) -{ - GcrListSelector *self = GCR_LIST_SELECTOR (view); - - if (self->pv->search_widget == NULL) - return FALSE; - - if (gtk_widget_get_visible (self->pv->search_widget)) - gtk_widget_grab_focus (self->pv->search_widget); - else - gtk_widget_show (self->pv->search_widget); - - return TRUE; -} - -static void -on_search_widget_text_notify (GcrLiveSearch *search, GParamSpec *pspec, - gpointer user_data) -{ - GcrListSelector *self = GCR_LIST_SELECTOR (user_data); -#if 0 - GtkTreeViewColumn *focus_column; - GtkTreeModel *model; - GtkTreeIter iter; - GtkTreePath *path; - gboolean set_cursor = FALSE; -#endif - - gtk_tree_model_filter_refilter (self->pv->filter); - -#if 0 - /* Set cursor on the first object. */ - - model = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); - gtk_tree_view_get_cursor (GTK_TREE_VIEW (view), &path, &focus_column); - - if (path == NULL) { - path = gtk_tree_path_new_from_string ("0"); - set_cursor = TRUE; - } - - if (set_cursor) { - /* FIXME: Workaround for GTK bug #621651, we have to make sure - * the path is valid. */ - if (gtk_tree_model_get_iter (model, &iter, path)) { - gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), path, - focus_column, FALSE); - } - } - - gtk_tree_path_free (path); -#endif -} - -static void -on_search_widget_activate (GtkWidget *search, gpointer user_data) -{ - GcrListSelector *self = GCR_LIST_SELECTOR (user_data); - GtkTreePath *path; - GtkTreeViewColumn *focus_column; - - gtk_tree_view_get_cursor (GTK_TREE_VIEW (self), &path, &focus_column); - if (path != NULL) { - gtk_tree_view_row_activated (GTK_TREE_VIEW (self), path, focus_column); - gtk_tree_path_free (path); - - gtk_widget_hide (search); - } -} - -static gboolean -on_search_widget_key_navigation (GtkWidget *search, GdkEvent *event, gpointer user_data) -{ - GcrListSelector *self = GCR_LIST_SELECTOR (user_data); - GdkEvent *new_event; - gboolean ret = FALSE; - - new_event = gdk_event_copy (event); - gtk_widget_grab_focus (GTK_WIDGET (self)); - ret = gtk_widget_event (GTK_WIDGET (self), new_event); - gtk_widget_grab_focus (search); - - gdk_event_free (new_event); - - return ret; -} - -static void -on_check_column_toggled (GtkCellRendererToggle *cell, gchar *path, gpointer user_data) -{ - GcrListSelector *self = GCR_LIST_SELECTOR (user_data); - GtkTreeIter iter, model_iter; - - g_assert (path != NULL); - - if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (self->pv->filter), &iter, path)) { - gtk_tree_model_filter_convert_iter_to_child_iter (self->pv->filter, &model_iter, &iter); - gcr_collection_model_toggle_selected (self->pv->model, &model_iter); - } -} - -static void -gcr_list_selector_constructed (GObject *object) -{ - GcrListSelector *self = GCR_LIST_SELECTOR (object); - GtkCellRenderer *cell; - GtkTreeViewColumn *column; - guint column_id; - - G_OBJECT_CLASS (gcr_list_selector_parent_class)->constructed (object); - - gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self), FALSE); - - self->pv->model = gcr_collection_model_new (self->pv->collection, - "icon", G_TYPE_ICON, - "markup", G_TYPE_STRING, - NULL); - - self->pv->filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new ( - GTK_TREE_MODEL (self->pv->model), NULL)); - gtk_tree_model_filter_set_visible_func (self->pv->filter, - on_tree_filter_visible_func, self, NULL); - - gtk_tree_view_set_model (GTK_TREE_VIEW (self), GTK_TREE_MODEL (self->pv->filter)); - - /* The check */ - - cell = gtk_cell_renderer_toggle_new (); - g_signal_connect (cell, "toggled", G_CALLBACK (on_check_column_toggled), self); - - column_id = gcr_collection_model_column_for_selected (self->pv->model); - column = gtk_tree_view_column_new_with_attributes ("", cell, "active", column_id, NULL); - gtk_tree_view_column_set_resizable (column, FALSE); - gtk_tree_view_append_column (GTK_TREE_VIEW (self), column); - - column = gtk_tree_view_column_new (); - - /* The icon */ - cell = gtk_cell_renderer_pixbuf_new (); - g_object_set (cell, "stock-size", GTK_ICON_SIZE_DND, NULL); - gtk_tree_view_column_pack_start (column, cell, FALSE); - gtk_tree_view_column_add_attribute (column, cell, "gicon", 0); - - /* The markup */ - cell = gtk_cell_renderer_text_new (); - gtk_tree_view_column_pack_start (column, cell, TRUE); - gtk_tree_view_column_add_attribute (column, cell, "markup", 1); - - gtk_tree_view_append_column (GTK_TREE_VIEW (self), column); -} - -static void -gcr_list_selector_init (GcrListSelector *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_LIST_SELECTOR, GcrListSelectorPrivate); -} - -static void -gcr_list_selector_dispose (GObject *obj) -{ - GcrListSelector *self = GCR_LIST_SELECTOR (obj); - - if (self->pv->filter) - g_object_unref (self->pv->filter); - self->pv->filter = NULL; - - if (self->pv->model) - g_object_unref (self->pv->model); - self->pv->model = NULL; - - if (self->pv->collection) - g_object_unref (self->pv->collection); - self->pv->collection = NULL; - - _gcr_list_selector_set_live_search (self, NULL); - - G_OBJECT_CLASS (gcr_list_selector_parent_class)->dispose (obj); -} - -static void -gcr_list_selector_finalize (GObject *obj) -{ - GcrListSelector *self = GCR_LIST_SELECTOR (obj); - - g_assert (!self->pv->collection); - g_assert (!self->pv->model); - - G_OBJECT_CLASS (gcr_list_selector_parent_class)->finalize (obj); -} - -static void -gcr_list_selector_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrListSelector *self = GCR_LIST_SELECTOR (obj); - - switch (prop_id) { - case PROP_COLLECTION: - g_return_if_fail (!self->pv->collection); - self->pv->collection = g_value_dup_object (value); - g_return_if_fail (self->pv->collection); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_list_selector_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrListSelector *self = GCR_LIST_SELECTOR (obj); - - switch (prop_id) { - case PROP_COLLECTION: - g_value_set_object (value, gcr_list_selector_get_collection (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_list_selector_class_init (GcrListSelectorClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->constructed = gcr_list_selector_constructed; - gobject_class->dispose = gcr_list_selector_dispose; - gobject_class->finalize = gcr_list_selector_finalize; - gobject_class->set_property = gcr_list_selector_set_property; - gobject_class->get_property = gcr_list_selector_get_property; - - g_type_class_add_private (gobject_class, sizeof (GcrListSelectorPrivate)); - - /** - * GcrListSelector:collection: - * - * The collection which contains the objects to display in the selector. - */ - g_object_class_install_property (gobject_class, PROP_COLLECTION, - g_param_spec_object ("collection", "Collection", "Collection to select from", - GCR_TYPE_COLLECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_list_selector_new: - * @collection: The collection that contains the objects to display - * - * Create a new #GcrListSelector. - * - * Returns: (transfer full): a newly allocated selector, which should be - * released with g_object_unref() - */ -GcrListSelector * -gcr_list_selector_new (GcrCollection *collection) -{ - return g_object_new (GCR_TYPE_LIST_SELECTOR, - "collection", collection, - NULL); -} - -/** - * gcr_list_selector_get_collection: - * @self: The selector - * - * Get the collection that this selector is displaying objects from. - * - * Returns: (transfer none): The collection, owned by the selector. - */ -GcrCollection * -gcr_list_selector_get_collection (GcrListSelector *self) -{ - g_return_val_if_fail (GCR_IS_LIST_SELECTOR (self), NULL); - return self->pv->collection; -} - -/** - * gcr_list_selector_get_selected: - * @self: The selector - * - * Get a list of selected objects. - * - * Returns: (transfer container) (element-type GLib.Object): the list of - * selected objects, to be released with g_list_free() - */ -GList* -gcr_list_selector_get_selected (GcrListSelector *self) -{ - g_return_val_if_fail (GCR_IS_LIST_SELECTOR (self), NULL); - return gcr_collection_model_get_selected_objects (self->pv->model); -} - -/** - * gcr_list_selector_set_selected: - * @self: The selector - * @selected: (element-type GLib.Object): the list of objects to select - * - * Select certain objects in the selector. - */ -void -gcr_list_selector_set_selected (GcrListSelector *self, GList *selected) -{ - g_return_if_fail (GCR_IS_LIST_SELECTOR (self)); - gcr_collection_model_set_selected_objects (self->pv->model, selected); -} - - -void -_gcr_list_selector_set_live_search (GcrListSelector *self, GcrLiveSearch *search) -{ - g_return_if_fail (GCR_IS_LIST_SELECTOR (self)); - - /* remove old handlers if old search was not null */ - if (self->pv->search_widget != NULL) { - g_signal_handlers_disconnect_by_func (self, on_tree_view_start_search, NULL); - - g_signal_handlers_disconnect_by_func (self->pv->search_widget, - on_search_widget_text_notify, self); - g_signal_handlers_disconnect_by_func (self->pv->search_widget, - on_search_widget_activate, self); - g_signal_handlers_disconnect_by_func (self->pv->search_widget, - on_search_widget_key_navigation, self); - g_object_unref (self->pv->search_widget); - self->pv->search_widget = NULL; - } - - /* connect handlers if new search is not null */ - if (search != NULL) { - self->pv->search_widget = g_object_ref (search); - - g_signal_connect (self, "start-interactive-search", - G_CALLBACK (on_tree_view_start_search), NULL); - - g_signal_connect (self->pv->search_widget, "notify::text", - G_CALLBACK (on_search_widget_text_notify), self); - g_signal_connect (self->pv->search_widget, "activate", - G_CALLBACK (on_search_widget_activate), self); - g_signal_connect (self->pv->search_widget, "key-navigation", - G_CALLBACK (on_search_widget_key_navigation), self); - } -} diff --git a/gcr/gcr-list-selector.h b/gcr/gcr-list-selector.h deleted file mode 100644 index e109167d..00000000 --- a/gcr/gcr-list-selector.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef __GCR_LIST_SELECTOR_H__ -#define __GCR_LIST_SELECTOR_H__ - -#include "gcr-types.h" - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_LIST_SELECTOR (gcr_list_selector_get_type ()) -#define GCR_LIST_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_LIST_SELECTOR, GcrListSelector)) -#define GCR_LIST_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_LIST_SELECTOR, GcrListSelectorClass)) -#define GCR_IS_LIST_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_LIST_SELECTOR)) -#define GCR_IS_LIST_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_LIST_SELECTOR)) -#define GCR_LIST_SELECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_LIST_SELECTOR, GcrListSelectorClass)) - -typedef struct _GcrListSelector GcrListSelector; -typedef struct _GcrListSelectorClass GcrListSelectorClass; -typedef struct _GcrListSelectorPrivate GcrListSelectorPrivate; - -struct _GcrListSelector { - GtkTreeView parent; - - /*< private >*/ - GcrListSelectorPrivate *pv; -}; - -struct _GcrListSelectorClass { - - /*< private >*/ - GtkTreeViewClass parent_class; -}; - -GType gcr_list_selector_get_type (void); - -GcrListSelector* gcr_list_selector_new (GcrCollection *collection); - -GcrCollection* gcr_list_selector_get_collection (GcrListSelector *self); - -GList* gcr_list_selector_get_selected (GcrListSelector *self); - -void gcr_list_selector_set_selected (GcrListSelector *self, - GList *selected); - -G_END_DECLS - -#endif /* __GCR_LIST_SELECTOR_H__ */ diff --git a/gcr/gcr-live-search.c b/gcr/gcr-live-search.c deleted file mode 100644 index ef1919cb..00000000 --- a/gcr/gcr-live-search.c +++ /dev/null @@ -1,672 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * Copyright (C) 2010 Collabora Ltd. - * Copyright (C) 2007-2010 Nokia Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Felix Kaser <felix.kaser@collabora.co.uk> - * Xavier Claessens <xavier.claessens@collabora.co.uk> - * Claudio Saavedra <csaavedra@igalia.com> - * Stef Walter <stefw@collabora.co.uk> - */ - -/* Code borrowed from Empathy */ - -#include "config.h" - -#include "gcr-live-search.h" -#include "gcr-marshal.h" - -#include <gtk/gtk.h> -#include <gdk/gdkkeysyms.h> - -#include <string.h> - -G_DEFINE_TYPE (GcrLiveSearch, _gcr_live_search, GTK_TYPE_BOX) - -struct _GcrLiveSearchPrivate { - GtkWidget *search_entry; - GtkWidget *hook_widget; - GPtrArray *stripped_words; -}; - -enum { - PROP_0, - PROP_HOOK_WIDGET, - PROP_TEXT -}; - -enum { - ACTIVATE, - KEYNAV, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL]; - -static void on_hook_widget_destroy (GtkWidget *object, gpointer user_data); - -static gunichar -stripped_char (gunichar ch) -{ - gunichar retval = 0; - GUnicodeType utype; -#if GLIB_CHECK_VERSION (2,29,90) - gunichar decomp[4]; -#else - gunichar *decomp; -#endif - gsize dlen; - - utype = g_unichar_type (ch); - - switch (utype) { - case G_UNICODE_CONTROL: - case G_UNICODE_FORMAT: - case G_UNICODE_UNASSIGNED: - case G_UNICODE_NON_SPACING_MARK: -#if GLIB_CHECK_VERSION (2,29,90) - case G_UNICODE_SPACING_MARK: -#else - case G_UNICODE_COMBINING_MARK: -#endif - case G_UNICODE_ENCLOSING_MARK: - /* Ignore those */ - break; - case G_UNICODE_PRIVATE_USE: - case G_UNICODE_SURROGATE: - case G_UNICODE_LOWERCASE_LETTER: - case G_UNICODE_MODIFIER_LETTER: - case G_UNICODE_OTHER_LETTER: - case G_UNICODE_TITLECASE_LETTER: - case G_UNICODE_UPPERCASE_LETTER: - case G_UNICODE_DECIMAL_NUMBER: - case G_UNICODE_LETTER_NUMBER: - case G_UNICODE_OTHER_NUMBER: - case G_UNICODE_CONNECT_PUNCTUATION: - case G_UNICODE_DASH_PUNCTUATION: - case G_UNICODE_CLOSE_PUNCTUATION: - case G_UNICODE_FINAL_PUNCTUATION: - case G_UNICODE_INITIAL_PUNCTUATION: - case G_UNICODE_OTHER_PUNCTUATION: - case G_UNICODE_OPEN_PUNCTUATION: - case G_UNICODE_CURRENCY_SYMBOL: - case G_UNICODE_MODIFIER_SYMBOL: - case G_UNICODE_MATH_SYMBOL: - case G_UNICODE_OTHER_SYMBOL: - case G_UNICODE_LINE_SEPARATOR: - case G_UNICODE_PARAGRAPH_SEPARATOR: - case G_UNICODE_SPACE_SEPARATOR: - default: - ch = g_unichar_tolower (ch); -#if GLIB_CHECK_VERSION (2,29,90) - dlen = g_unichar_fully_decompose (ch, FALSE, decomp, 4); - if (dlen > 0) { -#else - decomp = g_unicode_canonical_decomposition (ch, &dlen); - if (decomp != NULL) { -#endif - retval = decomp[0]; -#if !GLIB_CHECK_VERSION (2,29,90) - g_free (decomp); -#endif - } - } - - return retval; -} - -static void -append_word (GPtrArray **word_array, GString **word) -{ - if (*word != NULL) { - if (*word_array == NULL) - *word_array = g_ptr_array_new_with_free_func (g_free); - g_ptr_array_add (*word_array, g_string_free (*word, FALSE)); - *word = NULL; - } -} - -GPtrArray * -_gcr_live_search_strip_utf8_string (const gchar *string) -{ - GPtrArray *word_array = NULL; - GString *word = NULL; - const gchar *p; - - if (string == NULL || *string == '\0') - return NULL; - - for (p = string; *p != '\0'; p = g_utf8_next_char (p)) { - gunichar sc; - - /* Make the char lower-case, remove its accentuation marks, and ignore it - * if it is just unicode marks */ - sc = stripped_char (g_utf8_get_char (p)); - if (sc == 0) - continue; - - /* If it is not alpha-num, it is separator between words */ - if (!g_unichar_isalnum (sc)) { - append_word (&word_array, &word); - continue; - } - - /* It is alpha-num, append this char to current word, or start new word */ - if (word == NULL) - word = g_string_new (NULL); - g_string_append_unichar (word, sc); - } - - append_word (&word_array, &word); - - return word_array; -} - -static gboolean -live_search_match_prefix (const gchar *string, const gchar *prefix) -{ - const gchar *p; - const gchar *prefix_p; - gboolean next_word = FALSE; - - if (prefix == NULL || prefix[0] == 0) - return TRUE; - - if (string == NULL || *string == '\0') - return FALSE; - - prefix_p = prefix; - for (p = string; *p != '\0'; p = g_utf8_next_char (p)) { - gunichar sc; - - /* Make the char lower-case, remove its accentuation marks, and ignore it - * if it is just unicode marks */ - sc = stripped_char (g_utf8_get_char (p)); - if (sc == 0) - continue; - - /* If we want to go to next word, ignore alpha-num chars */ - if (next_word && g_unichar_isalnum (sc)) - continue; - next_word = FALSE; - - /* Ignore word separators */ - if (!g_unichar_isalnum (sc)) - continue; - - /* If this char does not match prefix_p, go to next word and start again - * from the beginning of prefix */ - if (sc != g_utf8_get_char (prefix_p)) { - next_word = TRUE; - prefix_p = prefix; - continue; - } - - /* prefix_p match, verify to next char. If this was the last of prefix, - * it means it completely machted and we are done. */ - prefix_p = g_utf8_next_char (prefix_p); - if (*prefix_p == '\0') - return TRUE; - } - - return FALSE; -} - -gboolean -_gcr_live_search_match_words (const gchar *string, GPtrArray *words) -{ - guint i; - - if (words == NULL) - return TRUE; - - for (i = 0; i < words->len; i++) - if (!live_search_match_prefix (string, g_ptr_array_index (words, i))) - return FALSE; - - return TRUE; -} - -static gboolean -fire_key_navigation_sig (GcrLiveSearch *self, GdkEventKey *event) -{ - gboolean ret; - - g_signal_emit (self, signals[KEYNAV], 0, event, &ret); - return ret; -} - -static gboolean -on_search_entry_key_pressed (GtkEntry *entry, GdkEventKey *event, gpointer user_data) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (user_data); - - /* if esc key pressed, hide the search */ - if (event->keyval == GDK_KEY_Escape) { - gtk_widget_hide (GTK_WIDGET (self)); - return TRUE; - } - - /* emit key navigation signal, so other widgets can respond to it properly */ - if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down - || event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down) { - return fire_key_navigation_sig (self, event); - } - - if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_End || - event->keyval == GDK_KEY_space) { - /* If the live search is visible, the entry should catch the Home/End - * and space events */ - if (!gtk_widget_get_visible (GTK_WIDGET (self))) { - return fire_key_navigation_sig (self, event); - } - } - - return FALSE; -} - -static void -on_search_entry_text_changed (GtkEntry *entry, gpointer user_data) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (user_data); - const gchar *text; - - text = gtk_entry_get_text (entry); - - if (text == NULL || *text == '\0') - gtk_widget_hide (GTK_WIDGET (self)); - else - gtk_widget_show (GTK_WIDGET (self)); - - if (self->pv->stripped_words != NULL) - g_ptr_array_unref (self->pv->stripped_words); - - self->pv->stripped_words = _gcr_live_search_strip_utf8_string (text); - - g_object_notify (G_OBJECT (self), "text"); -} - -static void -on_search_entry_close_pressed (GtkEntry *entry, GtkEntryIconPosition icon_pos, - GdkEvent *event, gpointer user_data) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (user_data); - gtk_widget_hide (GTK_WIDGET (self)); -} - -static gboolean -on_hook_widget_key_press_event (GtkWidget *widget, GdkEventKey *event, - gpointer user_data) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (user_data); - GdkEvent *new_event; - gboolean ret; - - /* dont forward this event to the entry, else the event is consumed by the - * entry and does not close the window */ - if (!gtk_widget_get_visible (GTK_WIDGET (self)) && - event->keyval == GDK_KEY_Escape) - return FALSE; - - /* do not show the search if CTRL and/or ALT are pressed with a key - * this is needed, because otherwise the CTRL + F accel would not work, - * because the entry consumes it */ - if (event->state & (GDK_MOD1_MASK | GDK_CONTROL_MASK) || - event->keyval == GDK_KEY_Control_L || - event->keyval == GDK_KEY_Control_R) - return FALSE; - - /* dont forward the up/down and Page Up/Down arrow keys to the entry, - * they are needed for navigation in the treeview and are not needed in - * the search entry */ - if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down || - event->keyval == GDK_KEY_Page_Up || event->keyval == GDK_KEY_Page_Down) - return FALSE; - - if (event->keyval == GDK_KEY_Home || event->keyval == GDK_KEY_End || - event->keyval == GDK_KEY_space) { - /* Home/End and space keys have to be forwarded to the entry only if - * the live search is visible (to move the cursor inside the entry). */ - if (!gtk_widget_get_visible (GTK_WIDGET (self))) - return FALSE; - } - - /* realize the widget if it is not realized yet */ - gtk_widget_realize (self->pv->search_entry); - if (!gtk_widget_has_focus (self->pv->search_entry)) { - gtk_widget_grab_focus (self->pv->search_entry); - gtk_editable_set_position (GTK_EDITABLE (self->pv->search_entry), -1); - } - - /* forward the event to the search entry */ - new_event = gdk_event_copy ((GdkEvent *) event); - ret = gtk_widget_event (self->pv->search_entry, new_event); - gdk_event_free (new_event); - - return ret; -} - -static void -on_search_entry_activate (GtkEntry *entry, GcrLiveSearch *self) -{ - g_signal_emit (self, signals[ACTIVATE], 0); -} - -static void -live_search_release_hook_widget (GcrLiveSearch *self) -{ - /* remove old handlers if old source was not null */ - if (self->pv->hook_widget != NULL) { - g_signal_handlers_disconnect_by_func (self->pv->hook_widget, - on_hook_widget_key_press_event, self); - g_signal_handlers_disconnect_by_func (self->pv->hook_widget, - on_hook_widget_destroy, self); - g_object_unref (self->pv->hook_widget); - self->pv->hook_widget = NULL; - } -} - -static void -on_hook_widget_destroy (GtkWidget *object, gpointer user_data) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (user_data); - - /* unref the hook widget and hide search */ - gtk_widget_hide (GTK_WIDGET (self)); - live_search_release_hook_widget (self); -} - -static void -live_search_dispose (GObject *obj) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (obj); - - live_search_release_hook_widget (self); - - G_OBJECT_CLASS (_gcr_live_search_parent_class)->dispose (obj); -} - -static void -live_search_finalize (GObject *obj) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (obj); - - if (self->pv->stripped_words != NULL) - g_ptr_array_unref (self->pv->stripped_words); - - G_OBJECT_CLASS (_gcr_live_search_parent_class)->finalize (obj); -} - -static void -live_search_get_property (GObject *object, guint param_id, - GValue *value, GParamSpec *pspec) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (object); - - switch (param_id) { - case PROP_HOOK_WIDGET: - g_value_set_object (value, _gcr_live_search_get_hook_widget (self)); - break; - case PROP_TEXT: - g_value_set_string (value, _gcr_live_search_get_text (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} - -static void -live_search_set_property (GObject *object, guint param_id, - const GValue *value, GParamSpec *pspec) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (object); - - switch (param_id) { - case PROP_HOOK_WIDGET: - _gcr_live_search_set_hook_widget (self, g_value_get_object (value)); - break; - case PROP_TEXT: - _gcr_live_search_set_text (self, g_value_get_string (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - }; -} - -static void -live_search_unmap (GtkWidget *widget) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (widget); - - GTK_WIDGET_CLASS (_gcr_live_search_parent_class)->unmap (widget); - - /* unmap can happen if a parent gets hidden, in that case we want to hide - * the live search as well, so when it gets mapped again, the live search - * won't be shown. */ - gtk_widget_hide (widget); - - gtk_entry_set_text (GTK_ENTRY (self->pv->search_entry), ""); - gtk_widget_grab_focus (self->pv->hook_widget); -} - -static void -live_search_show (GtkWidget *widget) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (widget); - - if (!gtk_widget_has_focus (self->pv->search_entry)) - gtk_widget_grab_focus (self->pv->search_entry); - - GTK_WIDGET_CLASS (_gcr_live_search_parent_class)->show (widget); -} - -static void -live_search_grab_focus (GtkWidget *widget) -{ - GcrLiveSearch *self = GCR_LIVE_SEARCH (widget); - - if (!gtk_widget_has_focus (self->pv->search_entry)) { - gtk_widget_grab_focus (self->pv->search_entry); - gtk_editable_set_position (GTK_EDITABLE (self->pv->search_entry), -1); - } -} - -static void -_gcr_live_search_class_init (GcrLiveSearchClass *klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; - GParamSpec *param_spec; - - object_class->finalize = live_search_finalize; - object_class->dispose = live_search_dispose; - object_class->get_property = live_search_get_property; - object_class->set_property = live_search_set_property; - - widget_class->unmap = live_search_unmap; - widget_class->show = live_search_show; - widget_class->grab_focus = live_search_grab_focus; - - signals[ACTIVATE] = g_signal_new ("activate", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[KEYNAV] = g_signal_new ("key-navigation", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - 0, - g_signal_accumulator_true_handled, NULL, - _gcr_marshal_BOOLEAN__BOXED, - G_TYPE_BOOLEAN, 1, GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); - - param_spec = g_param_spec_object ("hook-widget", "Live Search Hook Widget", - "The live search catches key-press-events on this widget", - GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_HOOK_WIDGET, param_spec); - - param_spec = g_param_spec_string ("text", "Live Search Text", - "The text of the live search entry", - "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - g_object_class_install_property (object_class, PROP_TEXT, param_spec); - - g_type_class_add_private (klass, sizeof (GcrLiveSearchPrivate)); -} - -static void -_gcr_live_search_init (GcrLiveSearch *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE ((self), GCR_TYPE_LIVE_SEARCH, - GcrLiveSearchPrivate); - - gtk_widget_set_no_show_all (GTK_WIDGET (self), TRUE); - - self->pv->search_entry = gtk_entry_new (); - gtk_entry_set_icon_from_stock (GTK_ENTRY (self->pv->search_entry), - GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLOSE); - gtk_entry_set_icon_activatable (GTK_ENTRY (self->pv->search_entry), - GTK_ENTRY_ICON_SECONDARY, TRUE); - gtk_entry_set_icon_sensitive (GTK_ENTRY (self->pv->search_entry), - GTK_ENTRY_ICON_SECONDARY, TRUE); - gtk_widget_show (self->pv->search_entry); - - gtk_box_pack_start (GTK_BOX (self), self->pv->search_entry, TRUE, TRUE, 0); - - g_signal_connect (self->pv->search_entry, "icon_release", - G_CALLBACK (on_search_entry_close_pressed), self); - g_signal_connect (self->pv->search_entry, "changed", - G_CALLBACK (on_search_entry_text_changed), self); - g_signal_connect (self->pv->search_entry, "key-press-event", - G_CALLBACK (on_search_entry_key_pressed), self); - g_signal_connect (self->pv->search_entry, "activate", - G_CALLBACK (on_search_entry_activate), self); - - self->pv->hook_widget = NULL; -} - -/** - * _gcr_live_search_new: - * @hook: (allow-none): the widget to hook - * - * Returns: (transfer full) (type Gcr.LiveSearch): The new widget - */ -GtkWidget * -_gcr_live_search_new (GtkWidget *hook) -{ - g_return_val_if_fail (hook == NULL || GTK_IS_WIDGET (hook), NULL); - - return g_object_new (GCR_TYPE_LIVE_SEARCH, - "hook-widget", hook, - NULL); -} - -/* public methods */ - -GtkWidget * -_gcr_live_search_get_hook_widget (GcrLiveSearch *self) -{ - g_return_val_if_fail (GCR_IS_LIVE_SEARCH (self), NULL); - - return self->pv->hook_widget; -} - -void -_gcr_live_search_set_hook_widget (GcrLiveSearch *self, GtkWidget *hook) -{ - g_return_if_fail (GCR_IS_LIVE_SEARCH (self)); - g_return_if_fail (hook == NULL || GTK_IS_WIDGET (hook)); - - /* release the actual widget */ - live_search_release_hook_widget (self); - - /* connect handlers if new source is not null */ - if (hook != NULL) { - self->pv->hook_widget = g_object_ref (hook); - g_signal_connect (self->pv->hook_widget, "key-press-event", - G_CALLBACK (on_hook_widget_key_press_event), - self); - g_signal_connect (self->pv->hook_widget, "destroy", - G_CALLBACK (on_hook_widget_destroy), - self); - } -} - -const gchar * -_gcr_live_search_get_text (GcrLiveSearch *self) -{ - g_return_val_if_fail (GCR_IS_LIVE_SEARCH (self), NULL); - - return gtk_entry_get_text (GTK_ENTRY (self->pv->search_entry)); -} - -void -_gcr_live_search_set_text (GcrLiveSearch *self, const gchar *text) -{ - g_return_if_fail (GCR_IS_LIVE_SEARCH (self)); - g_return_if_fail (text != NULL); - - gtk_entry_set_text (GTK_ENTRY (self->pv->search_entry), text); -} - -/** - * _gcr_live_search_match: - * @self: a #GcrLiveSearch - * @string: a string where to search, must be valid UTF-8. - * - * Search if one of the words in @string string starts with the current text - * of @self. - * - * Searching for "aba" in "Abasto" will match, searching in "Moraba" will not, - * and searching in "A tool (abacus)" will do. - * - * The match is not case-sensitive, and regardless of the accentuation marks. - * - * Returns: %TRUE if a match is found, %FALSE otherwise. - * - **/ -gboolean -_gcr_live_search_match (GcrLiveSearch *self, const gchar *string) -{ - g_return_val_if_fail (GCR_IS_LIVE_SEARCH (self), FALSE); - - return _gcr_live_search_match_words (string, self->pv->stripped_words); -} - -gboolean -_gcr_live_search_match_string (const gchar *string, const gchar *prefix) -{ - GPtrArray *words; - gboolean match; - - words = _gcr_live_search_strip_utf8_string (prefix); - match = _gcr_live_search_match_words (string, words); - if (words != NULL) - g_ptr_array_unref (words); - - return match; -} - -GPtrArray * -_gcr_live_search_get_words (GcrLiveSearch *self) -{ - return self->pv->stripped_words; -} diff --git a/gcr/gcr-live-search.h b/gcr/gcr-live-search.h deleted file mode 100644 index cf048fd9..00000000 --- a/gcr/gcr-live-search.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * Copyright (C) 2010 Collabora Ltd. - * Copyright (C) 2007-2010 Nokia Corporation. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Felix Kaser <felix.kaser@collabora.co.uk> - * Xavier Claessens <xavier.claessens@collabora.co.uk> - * Claudio Saavedra <csaavedra@igalia.com> - * Stef Walter <stefw@collabora.co.uk> - */ - -/* Code borrowed from Empathy */ - -#ifndef __GCR_LIVE_SEARCH_H__ -#define __GCR_LIVE_SEARCH_H__ - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_LIVE_SEARCH (_gcr_live_search_get_type ()) -#define GCR_LIVE_SEARCH(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GCR_TYPE_LIVE_SEARCH, GcrLiveSearch)) -#define GCR_LIVE_SEARCH_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GCR_TYPE_LIVE_SEARCH, GcrLiveSearchClass)) -#define GCR_IS_LIVE_SEARCH(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GCR_TYPE_LIVE_SEARCH)) -#define GCR_IS_LIVE_SEARCH_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GCR_TYPE_LIVE_SEARCH)) -#define GCR_LIVE_SEARCH_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GCR_TYPE_LIVE_SEARCH, GcrLiveSearchClass)) - -typedef struct _GcrLiveSearch GcrLiveSearch; -typedef struct _GcrLiveSearchClass GcrLiveSearchClass; -typedef struct _GcrLiveSearchPrivate GcrLiveSearchPrivate; - -struct _GcrLiveSearch { - /*< private >*/ - GtkBox parent; - GcrLiveSearchPrivate *pv; -}; - -struct _GcrLiveSearchClass { - GtkBoxClass parent_class; -}; - -GType _gcr_live_search_get_type (void) G_GNUC_CONST; - -GtkWidget * _gcr_live_search_new (GtkWidget *hook); - -GtkWidget * _gcr_live_search_get_hook_widget (GcrLiveSearch *self); -void _gcr_live_search_set_hook_widget (GcrLiveSearch *self, - GtkWidget *hook); - -const gchar * _gcr_live_search_get_text (GcrLiveSearch *self); -void _gcr_live_search_set_text (GcrLiveSearch *self, - const gchar *text); - -gboolean _gcr_live_search_match (GcrLiveSearch *self, - const gchar *string); - -GPtrArray * _gcr_live_search_strip_utf8_string (const gchar *string); - -gboolean _gcr_live_search_match_words (const gchar *string, - GPtrArray *words); - -GPtrArray * _gcr_live_search_get_words (GcrLiveSearch *self); - -/* Made public for unit tests */ -gboolean _gcr_live_search_match_string (const gchar *string, - const gchar *prefix); - -G_END_DECLS - -#endif /* __GCR_LIVE_SEARCH_H__ */ diff --git a/gcr/gcr-marshal.list b/gcr/gcr-marshal.list deleted file mode 100644 index 5e36589b..00000000 --- a/gcr/gcr-marshal.list +++ /dev/null @@ -1,7 +0,0 @@ -BOOLEAN:INT -BOOLEAN:BOXED -VOID:STRING,BOXED -VOID:BOXED -VOID:STRING -VOID:OBJECT,BOXED -VOID:OBJECT,OBJECT diff --git a/gcr/gcr-memory-icon.c b/gcr/gcr-memory-icon.c deleted file mode 100644 index 39713593..00000000 --- a/gcr/gcr-memory-icon.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-memory-icon.h" - -#include <string.h> - -struct _GcrMemoryIconPrivate { - gpointer data; - gsize n_data; - goffset offset; - gchar *image_type; - GDestroyNotify destroy; -}; - -/* Forward declarations */ -static void _gcr_memory_icon_iface_icon (GIconIface *iface); -static void _gcr_memory_icon_iface_loadable_icon (GLoadableIconIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrMemoryIcon, _gcr_memory_icon, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_ICON, _gcr_memory_icon_iface_icon); - G_IMPLEMENT_INTERFACE (G_TYPE_LOADABLE_ICON, _gcr_memory_icon_iface_loadable_icon); -); - - -static void -_gcr_memory_icon_init (GcrMemoryIcon *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_MEMORY_ICON, GcrMemoryIconPrivate)); -} - -static void -_gcr_memory_icon_finalize (GObject *obj) -{ - GcrMemoryIcon *self = GCR_MEMORY_ICON (obj); - - if (self->pv->destroy) - (self->pv->destroy) (self->pv->data); - g_free (self->pv->image_type); - - G_OBJECT_CLASS (_gcr_memory_icon_parent_class)->finalize (obj); -} - -static void -_gcr_memory_icon_class_init (GcrMemoryIconClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (GcrMemoryIconPrivate)); - - gobject_class->finalize = _gcr_memory_icon_finalize; -} - -static gboolean -_gcr_memory_icon_equal (GIcon *icon1, GIcon *icon2) -{ - GcrMemoryIcon *one = GCR_MEMORY_ICON (icon1); - GcrMemoryIcon *two = GCR_MEMORY_ICON (icon2); - - if (icon1 == icon2) - return TRUE; - if (!g_str_equal (one->pv->image_type, two->pv->image_type)) - return FALSE; - if ((one->pv->n_data - one->pv->offset) != (two->pv->n_data - two->pv->offset)) - return FALSE; - return memcmp ((guchar*)one->pv->data + one->pv->offset, - (guchar*)two->pv->data + two->pv->offset, - one->pv->n_data - one->pv->offset) == 0; -} - -static guint -_gcr_memory_icon_hash (GIcon *icon) -{ - GcrMemoryIcon *self = GCR_MEMORY_ICON (icon); - const signed char *p, *end; - guint32 hash; - - hash = g_str_hash (self->pv->image_type); - - /* Adapted from g_str_hash */ - p = self->pv->data; - end = p + self->pv->n_data; - p += self->pv->offset; - while (p < end) - hash = (hash << 5) + hash + *(p++); - - return hash; -} - -static void -_gcr_memory_icon_iface_icon (GIconIface *iface) -{ - iface->equal = _gcr_memory_icon_equal; - iface->hash = _gcr_memory_icon_hash; -} - -static GInputStream * -_gcr_memory_icon_load (GLoadableIcon *icon, int size, gchar **type, - GCancellable *cancellable, GError **error) -{ - GcrMemoryIcon *self = GCR_MEMORY_ICON (icon); - GInputStream *is; - - if (type != NULL) - *type = g_strdup (self->pv->image_type); - - is = g_memory_input_stream_new_from_data ((guchar*)self->pv->data + self->pv->offset, - self->pv->n_data, NULL); - - /* - * Hold a reference to this object from the stream, so that we can rely - * on the data hanging around. - */ - g_object_set_data_full (G_OBJECT (is), "back-reference", g_object_ref (self), - g_object_unref); - - return is; -} - -static void -_gcr_memory_icon_load_async (GLoadableIcon *icon, int size, GCancellable *cancellable, - GAsyncReadyCallback callback, gpointer user_data) -{ - GSimpleAsyncResult *res; - - res = g_simple_async_result_new (G_OBJECT (icon), callback, user_data, - _gcr_memory_icon_load_async); - - g_simple_async_result_complete_in_idle (res); - g_object_unref (res); -} - -static GInputStream* -_gcr_memory_icon_finish (GLoadableIcon *icon, GAsyncResult *res, char **type, - GError **error) -{ - g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (icon), - _gcr_memory_icon_load_async), NULL); - return _gcr_memory_icon_load (icon, 0, type, NULL, error); -} - - -static void -_gcr_memory_icon_iface_loadable_icon (GLoadableIconIface *iface) -{ - iface->load = _gcr_memory_icon_load; - iface->load_async = _gcr_memory_icon_load_async; - iface->load_finish = _gcr_memory_icon_finish; -} - -/** - * _gcr_memory_icon_new: - * @image_type: MIME content-type of the image. - * @data: Data for the image. - * @n_data: Length of data. - * - * Create a new GIcon based on image data in memory. The data will be copied - * by the new icon. - * - * Returns: (transfer full) (type Gcr.MemoryIcon): A newly allocated icon. - */ -GIcon* -_gcr_memory_icon_new (const gchar *image_type, gconstpointer data, gsize n_data) -{ - g_return_val_if_fail (image_type != NULL, NULL); - g_return_val_if_fail (data != NULL, NULL); - g_return_val_if_fail (n_data != 0, NULL); - - return _gcr_memory_icon_new_full (image_type, g_memdup (data, n_data), - n_data, 0, g_free); -} - -/** - * _gcr_memory_icon_new_full: - * @image_type: MIME content-type of the image. - * @data: Data for the image. - * @n_data: Length of data. - * @offset: Offset of the start of the image in @data. - * @destroy: Callback to free or release @data when no longer needed. - * - * Create a new GIcon based on image data in memory. The data will be used - * directly from the @data passed. Use @destroy to control the lifetime of - * the data in memory. - * - * Returns: (transfer full): A newly allocated icon. - */ -GIcon* -_gcr_memory_icon_new_full (const gchar *image_type, gpointer data, gsize n_data, - goffset offset, GDestroyNotify destroy) -{ - GcrMemoryIcon *self; - - g_return_val_if_fail (image_type != NULL, NULL); - g_return_val_if_fail (data != NULL, NULL); - g_return_val_if_fail (offset < n_data, NULL); - - self = g_object_new (GCR_TYPE_MEMORY_ICON, NULL); - self->pv->data = data; - self->pv->n_data = n_data; - self->pv->offset = offset; - self->pv->destroy = destroy; - self->pv->image_type = g_strdup (image_type); - - return G_ICON (self); -} diff --git a/gcr/gcr-memory-icon.h b/gcr/gcr-memory-icon.h deleted file mode 100644 index 71da9e51..00000000 --- a/gcr/gcr-memory-icon.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef GCR_MEMORY_ICON_H -#define GCR_MEMORY_ICON_H - -#include <glib-object.h> -#include <gio/gio.h> - -G_BEGIN_DECLS - -#define GCR_MEMORY_ICON_COLUMNS (_gcr_memory_icon_get_columns ()) -#define GCR_TYPE_MEMORY_ICON (_gcr_memory_icon_get_type ()) -#define GCR_MEMORY_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_MEMORY_ICON, GcrMemoryIcon)) -#define GCR_MEMORY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_MEMORY_ICON, GcrMemoryIconClass)) -#define GCR_IS_MEMORY_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_MEMORY_ICON)) -#define GCR_IS_MEMORY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_MEMORY_ICON)) -#define GCR_MEMORY_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_MEMORY_ICON, GcrMemoryIconClass)) - -typedef struct _GcrMemoryIcon GcrMemoryIcon; -typedef struct _GcrMemoryIconClass GcrMemoryIconClass; -typedef struct _GcrMemoryIconPrivate GcrMemoryIconPrivate; - -struct _GcrMemoryIcon { - /*< private >*/ - GObject parent; - GcrMemoryIconPrivate *pv; -}; - -struct _GcrMemoryIconClass { - GObjectClass parent_class; -}; - -GType _gcr_memory_icon_get_type (void) G_GNUC_CONST; - -GIcon* _gcr_memory_icon_new (const gchar *image_type, - gconstpointer data, - gsize n_data); - -GIcon* _gcr_memory_icon_new_full (const gchar *image_type, - gpointer data, - gsize n_data, - goffset offset, - GDestroyNotify destroy); - -G_END_DECLS - -#endif /* __GCR_MEMORY_ICON_H__ */ diff --git a/gcr/gcr-memory.c b/gcr/gcr-memory.c deleted file mode 100644 index 04d216d9..00000000 --- a/gcr/gcr-memory.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "egg/egg-secure-memory.h" - -#include <glib.h> - -/* ----------------------------------------------------------------------------- - * MEMORY - */ - -static gboolean do_warning = TRUE; -#define WARNING "couldn't allocate secure memory to keep passwords " \ - "and or keys from being written to the disk" - -#define ABORTMSG "The GNOME_KEYRING_PARANOID environment variable was set. " \ - "Exiting..." - -static G_LOCK_DEFINE (memory_lock); - -/* - * These are called from egg-secure-memory.c to provide appropriate - * locking for memory between threads - */ - -void -egg_memory_lock (void) -{ - G_LOCK (memory_lock); -} - -void -egg_memory_unlock (void) -{ - G_UNLOCK (memory_lock); -} - -void* -egg_memory_fallback (void *p, size_t sz) -{ - const gchar *env; - - /* We were asked to free memory */ - if (!sz) { - g_free (p); - return NULL; - } - - /* We were asked to allocate */ - if (!p) { - if (do_warning) { - g_message (WARNING); - do_warning = FALSE; - } - - env = g_getenv ("GNOME_KEYRING_PARANOID"); - if (env && *env) - g_error (ABORTMSG); - - return g_malloc0 (sz); - } - - /* - * Reallocation is a bit of a gray area, as we can be asked - * by external libraries (like libgcrypt) to reallocate a - * non-secure block into secure memory. We cannot satisfy - * this request (as we don't know the size of the original - * block) so we just try our best here. - */ - - return g_realloc (p, sz); -} diff --git a/gcr/gcr-menu-button.c b/gcr/gcr-menu-button.c deleted file mode 100644 index 044d6d3b..00000000 --- a/gcr/gcr-menu-button.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright (C) 2011 Alexander Larsson <alexl@redhat.com> - * Copyright (C) 2011 Collabora Ltd. - * - * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-menu-button.h" - -enum { - PROP_0, - PROP_LABEL, - PROP_MENU -}; - -struct _GcrMenuButtonPrivate { - GtkMenu *menu; - gboolean popup_in_progress; - gchar *label; -}; - -G_DEFINE_TYPE (GcrMenuButton, _gcr_menu_button, GTK_TYPE_TOGGLE_BUTTON); - -static void -_gcr_menu_button_init (GcrMenuButton *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_MENU_BUTTON, - GcrMenuButtonPrivate)); -} - -static void -_gcr_menu_button_constructed (GObject *obj) -{ - GcrMenuButton *self = GCR_MENU_BUTTON (obj); - GtkWidget *label_widget; - GtkWidget *arrow; - GtkWidget *grid; - - G_OBJECT_CLASS (_gcr_menu_button_parent_class)->constructed (obj); - - gtk_button_set_focus_on_click (GTK_BUTTON (self), FALSE); - - label_widget = gtk_label_new (self->pv->label); - arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); - grid = gtk_grid_new (); - - gtk_orientable_set_orientation (GTK_ORIENTABLE (grid), GTK_ORIENTATION_HORIZONTAL); - gtk_container_add (GTK_CONTAINER (grid), label_widget); - gtk_container_add (GTK_CONTAINER (grid), arrow); - gtk_grid_set_row_spacing (GTK_GRID (grid), 3); - gtk_widget_set_hexpand (grid, TRUE); - gtk_widget_set_halign (grid, GTK_ALIGN_CENTER); - - gtk_container_add (GTK_CONTAINER (self), grid); -} - -static void -_gcr_menu_button_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GcrMenuButton *self = GCR_MENU_BUTTON (obj); - - switch (prop_id) { - case PROP_MENU: - g_value_set_object (value, _gcr_menu_button_get_menu (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_menu_button_set_property (GObject *obj, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GcrMenuButton *self = GCR_MENU_BUTTON (obj); - - switch (prop_id) { - case PROP_LABEL: - self->pv->label = g_value_dup_string (value); - break; - case PROP_MENU: - _gcr_menu_button_set_menu (self, g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_menu_button_finalize (GObject *obj) -{ - GcrMenuButton *self = GCR_MENU_BUTTON (obj); - - _gcr_menu_button_set_menu (self, NULL); - g_free (self->pv->label); - - G_OBJECT_CLASS (_gcr_menu_button_parent_class)->finalize (obj); -} - - -static void -on_menu_position (GtkMenu *menu, - gint *x, - gint *y, - gboolean *push_in, - gpointer user_data) -{ - GcrMenuButton *self = GCR_MENU_BUTTON (user_data); - GtkWidget *widget = GTK_WIDGET (self); - GtkAllocation allocation; - GtkRequisition menu_req; - GdkRectangle monitor; - GdkWindow *window; - GtkWidget *toplevel; - GdkScreen *screen; - gint monitor_num; - gint sx = 0; - gint sy = 0; - - g_return_if_fail (x != NULL); - g_return_if_fail (y != NULL); - g_return_if_fail (push_in != NULL); - - gtk_widget_get_allocation (widget, &allocation); - - if (!gtk_widget_get_has_window (widget)) { - sx += allocation.x; - sy += allocation.y; - } - - window = gtk_widget_get_window (widget); - gdk_window_get_root_coords (window, sx, sy, &sx, &sy); - - gtk_widget_get_preferred_size (GTK_WIDGET (menu), NULL, &menu_req); - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) - *x = sx; - else - *x = sx + allocation.width - menu_req.width; - *y = sy; - - screen = gtk_widget_get_screen (widget); - monitor_num = gdk_screen_get_monitor_at_window (screen, window); - if (monitor_num < 0) - monitor_num = 0; - gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); - - if (*x < monitor.x) - *x = monitor.x; - else if (*x + menu_req.width > monitor.x + monitor.width) - *x = monitor.x + monitor.width - menu_req.width; - - if (monitor.y + monitor.height - *y - allocation.height >= menu_req.height) - *y += allocation.height; - else if (*y - monitor.y >= menu_req.height) - *y -= menu_req.height; - else if (monitor.y + monitor.height - *y - allocation.height > *y - monitor.y) - *y += allocation.height; - else - *y -= menu_req.height; - - gtk_menu_set_monitor (menu, monitor_num); - - toplevel = gtk_widget_get_parent (GTK_WIDGET (menu)); - if (GTK_IS_WINDOW (toplevel) && gtk_widget_get_visible (toplevel)) - gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU); - - *push_in = FALSE; -} - -static void -_gcr_menu_button_toggled (GtkToggleButton *togglebutton) -{ - GcrMenuButton *self = GCR_MENU_BUTTON (togglebutton); - GtkStyleContext *context; - - context = gtk_widget_get_style_context (GTK_WIDGET (self)); - if (gtk_toggle_button_get_active (togglebutton)) { - if (!self->pv->popup_in_progress) - gtk_menu_popup (self->pv->menu, NULL, NULL, - on_menu_position, self, 1, - gtk_get_current_event_time ()); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENUBAR); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_MENUITEM); - } else { - gtk_style_context_remove_class (context, GTK_STYLE_CLASS_MENUBAR); - gtk_style_context_remove_class (context, GTK_STYLE_CLASS_MENUITEM); - gtk_menu_popdown (self->pv->menu); - } - - gtk_widget_reset_style (GTK_WIDGET (self)); -} - -static gboolean -_gcr_menu_button_press_event (GtkWidget *widget, - GdkEventButton *event) -{ - GcrMenuButton *self = GCR_MENU_BUTTON (widget); - GtkWidget *ewidget; - - ewidget = gtk_get_event_widget ((GdkEvent *)event); - if (ewidget != widget || gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) - return FALSE; - - gtk_menu_popup (self->pv->menu, NULL, NULL, on_menu_position, self, - 1, gtk_get_current_event_time ()); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE); - self->pv->popup_in_progress = TRUE; - return TRUE; -} - -static gboolean -_gcr_menu_button_release_event (GtkWidget *widget, - GdkEventButton *event) -{ - GcrMenuButton *self = GCR_MENU_BUTTON (widget); - gboolean popup_in_progress_saved; - GtkWidget *ewidget; - - popup_in_progress_saved = self->pv->popup_in_progress; - self->pv->popup_in_progress = FALSE; - - ewidget = gtk_get_event_widget ((GdkEvent *)event); - - if (ewidget == widget && !popup_in_progress_saved && - gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) { - gtk_menu_popdown (self->pv->menu); - return TRUE; - } - - if (ewidget != widget) { - gtk_menu_popdown (self->pv->menu); - return TRUE; - } - - return FALSE; -} - -static gboolean -_gcr_menu_button_draw (GtkWidget *widget, - cairo_t *cr) -{ - GTK_WIDGET_GET_CLASS (widget)->draw (widget, cr); - return FALSE; -} - -static void -_gcr_menu_button_class_init (GcrMenuButtonClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GtkToggleButtonClass *toggle_class = GTK_TOGGLE_BUTTON_CLASS (klass); - GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); - - gobject_class->constructed = _gcr_menu_button_constructed; - gobject_class->get_property = _gcr_menu_button_get_property; - gobject_class->set_property = _gcr_menu_button_set_property; - gobject_class->finalize = _gcr_menu_button_finalize; - - widget_class->button_press_event = _gcr_menu_button_press_event; - widget_class->button_release_event = _gcr_menu_button_release_event; - widget_class->draw = _gcr_menu_button_draw; - - toggle_class->toggled = _gcr_menu_button_toggled; - - g_type_class_add_private (klass, sizeof (GcrMenuButtonPrivate)); - - g_object_class_install_property (gobject_class, PROP_LABEL, - g_param_spec_string ("label", "Label", "Label for the button", - "", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (gobject_class, PROP_MENU, - g_param_spec_object ("menu", "Menu", "Menu for the button", - GTK_TYPE_MENU, G_PARAM_READWRITE)); - -} - -/** - * _gcr_menu_button_new: - * @label: (allow-none): the label - * - * Returns: (transfer full) (type Gcr.MenuButton): the new menu button - */ -GtkWidget * -_gcr_menu_button_new (const gchar *label) -{ - return g_object_new (GCR_TYPE_MENU_BUTTON, - "label", label, - NULL); -} - -static void -on_menu_show (GtkWidget *menu, - gpointer user_data) -{ - GcrMenuButton *self = GCR_MENU_BUTTON (user_data); - self->pv->popup_in_progress = TRUE; - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self), TRUE); - self->pv->popup_in_progress = FALSE; -} - -static void -on_menu_hide (GtkWidget *menu, - gpointer user_data) -{ - GcrMenuButton *self = GCR_MENU_BUTTON (user_data); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self), FALSE); -} - -static void -on_menu_detach (GtkWidget *attach_widget, - GtkMenu *menu) -{ - -} - -GtkMenu * -_gcr_menu_button_get_menu (GcrMenuButton *self) -{ - g_return_val_if_fail (GCR_IS_MENU_BUTTON (self), NULL); - return self->pv->menu; -} - -void -_gcr_menu_button_set_menu (GcrMenuButton *self, - GtkMenu *menu) -{ - g_return_if_fail (GCR_IS_MENU_BUTTON (self)); - g_return_if_fail (menu == NULL || GTK_IS_MENU (menu)); - - if (menu == self->pv->menu) - return; - - if (self->pv->menu != NULL) { - g_signal_handlers_disconnect_by_func (self->pv->menu, on_menu_show, self); - g_signal_handlers_disconnect_by_func (self->pv->menu, on_menu_hide, self); - gtk_menu_detach (self->pv->menu); - g_object_unref (self->pv->menu); - } - - self->pv->menu = menu; - - if (self->pv->menu != NULL) { - g_object_ref (self->pv->menu); - g_signal_connect (self->pv->menu, "show", G_CALLBACK (on_menu_show), self); - g_signal_connect (self->pv->menu, "hide", G_CALLBACK (on_menu_hide), self); - gtk_menu_attach_to_widget (self->pv->menu, GTK_WIDGET (self), on_menu_detach); - } - - g_object_notify (G_OBJECT (self), "menu"); -} diff --git a/gcr/gcr-menu-button.h b/gcr/gcr-menu-button.h deleted file mode 100644 index 02dbb9cf..00000000 --- a/gcr/gcr-menu-button.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef GCR_MENU_BUTTON_H -#define GCR_MENU_BUTTON_H - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_MENU_BUTTON (_gcr_menu_button_get_type ()) -#define GCR_MENU_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_MENU_BUTTON, GcrMenuButton)) -#define GCR_MENU_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_MENU_BUTTON, GcrMenuButtonClass)) -#define GCR_IS_MENU_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_MENU_BUTTON)) -#define GCR_IS_MENU_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_MENU_BUTTON)) -#define GCR_MENU_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_MENU_BUTTON, GcrMenuButtonClass)) - -typedef struct _GcrMenuButton GcrMenuButton; -typedef struct _GcrMenuButtonClass GcrMenuButtonClass; -typedef struct _GcrMenuButtonPrivate GcrMenuButtonPrivate; - -struct _GcrMenuButton { - GtkToggleButton parent; - GcrMenuButtonPrivate *pv; -}; - -struct _GcrMenuButtonClass { - GtkToggleButtonClass parent; -}; - -GType _gcr_menu_button_get_type (void); - -GtkWidget * _gcr_menu_button_new (const gchar *label); - -GtkMenu * _gcr_menu_button_get_menu (GcrMenuButton *self); - -void _gcr_menu_button_set_menu (GcrMenuButton *self, - GtkMenu *menu); -G_END_DECLS - -#endif /* GCR_MENU_BUTTON_H */ diff --git a/gcr/gcr-mkoids b/gcr/gcr-mkoids deleted file mode 100644 index 47d10953..00000000 --- a/gcr/gcr-mkoids +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/sh - -set -euf - -generate_header () -{ - echo "/* WARNING: file is autogenerated */" - echo "" - echo "#include <glib.h>" - echo "" - echo "#ifndef ${UPPER}_OIDS_" - echo "#define ${UPPER}_OIDS_" - echo "" - echo "void _${LOWER}_oids_init (void);" - - while read name oid; do - if [ -n "$name" ]; then - echo "GQuark ${UPPER}_OID_${name};" - fi - done - - echo "" - echo "#endif /* ${UPPER}_OIDS_ */" -} - -generate_source () -{ - echo "/* WARNING: file is autogenerated */" - echo "" - echo "#include \"$HEADER\"" - echo "" - - echo "void" - echo "_${LOWER}_oids_init (void)" - echo "{" - echo " static volatile gsize initialized = 0;" - echo " if (g_once_init_enter (&initialized)) {" - - while read name oid; do - if [ -n "$name" ]; then - echo " ${UPPER}_OID_${name} = g_quark_from_static_string (\"${oid}\");" - fi - done - - echo " g_once_init_leave (&initialized, 1);" - echo " }" - echo "}" -} - -UPPER="PREFIX" -LOWER="prefix" - -while getopts 'c:h:p:' arg; do - case $arg in - p) - UPPER=$(echo "$OPTARG" | tr '[:lower:]' '[:upper:]') - LOWER=$(echo "$OPTARG" | tr '[:upper:]' '[:lower:]') - ;; - c) - SOURCE="$OPTARG" - ;; - h) - HEADER="$OPTARG" - ;; - *) - echo "gcr-mkoids: invalid argument: $arg" >&2 - exit 2 - ;; - esac -done - -shift $(expr $OPTIND - 1) -if [ $# -ne 1 ]; then - echo "gcr-mkoids: specify input file on command line" - exit 2 -fi - -INPUT="$1" - -if [ -n "$HEADER" ]; then - generate_header < $INPUT > $HEADER -fi -if [ -n "$SOURCE" ]; then - generate_source < $INPUT > $SOURCE -fi diff --git a/gcr/gcr-oids.list b/gcr/gcr-oids.list deleted file mode 100644 index 552c6017..00000000 --- a/gcr/gcr-oids.list +++ /dev/null @@ -1,22 +0,0 @@ -BASIC_CONSTRAINTS 2.5.29.19 -EXTENDED_KEY_USAGE 2.5.29.37 -SUBJECT_KEY_IDENTIFIER 2.5.29.14 -KEY_USAGE 2.5.29.15 -SUBJECT_ALT_NAME 2.5.29.17 - -PKIX1_RSA 1.2.840.113549.1.1.1 -PKIX1_DSA 1.2.840.10040.4.1 - -PKCS7_DATA 1.2.840.113549.1.7.1 -PKCS7_SIGNED_DATA 1.2.840.113549.1.7.2 -PKCS7_ENCRYPTED_DATA 1.2.840.113549.1.7.6 -PKCS9_ATTRIBUTE_FRIENDLY 1.2.840.113549.1.9.20 -PKCS9_ATTRIBUTE_LOCAL_KEY_ID 1.2.840.113549.1.9.21 -PKCS12_BAG_PKCS8_KEY 1.2.840.113549.1.12.10.1.1 -PKCS12_BAG_PKCS8_ENCRYPTED_KEY 1.2.840.113549.1.12.10.1.2 -PKCS12_BAG_CERTIFICATE 1.2.840.113549.1.12.10.1.3 -PKCS12_BAG_CRL 1.2.840.113549.1.12.10.1.4 - - -ALT_NAME_XMPP_ADDR 1.3.6.1.5.5.7.8.5 -ALT_NAME_DNS_SRV 1.3.6.1.5.5.7.8.7 diff --git a/gcr/gcr-openpgp.c b/gcr/gcr-openpgp.c deleted file mode 100644 index 7ae5c477..00000000 --- a/gcr/gcr-openpgp.c +++ /dev/null @@ -1,1304 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-openpgp.h" -#include "gcr-internal.h" -#include "gcr-record.h" -#include "gcr-types.h" - -#include "egg/egg-hex.h" - -#include <gcrypt.h> - -#include <string.h> - -typedef enum { - OPENPGP_PKT_RESERVED = 0, - OPENPGP_PKT_PUBKEY_ENC = 1, - OPENPGP_PKT_SIGNATURE = 2, - OPENPGP_PKT_ONEPASS_SIG = 4, - OPENPGP_PKT_SECRET_KEY = 5, - OPENPGP_PKT_PUBLIC_KEY = 6, - OPENPGP_PKT_SECRET_SUBKEY = 7, - OPENPGP_PKT_COMPRESSED = 8, - OPENPGP_PKT_MARKER = 10, - OPENPGP_PKT_LITERAL = 11, - OPENPGP_PKT_RING_TRUST = 12, - OPENPGP_PKT_USER_ID = 13, - OPENPGP_PKT_PUBLIC_SUBKEY = 14, - OPENPGP_PKT_OLD_COMMENT = 16, - OPENPGP_PKT_ATTRIBUTE = 17, - OPENPGP_PKT_MDC = 19 -} OpenpgpPktType; - -typedef enum { - OPENPGP_SIG_CREATION = 2, - OPENPGP_SIG_EXPIRY = 3, - OPENPGP_SIG_EXPORTABLE = 4, - OPENPGP_SIG_TRUST = 5, - OPENPGP_SIG_REGULAR_EXPRESSION = 6, - OPENPGP_SIG_REVOCABLE = 7, - OPENPGP_SIG_KEY_EXPIRY = 9, - OPENPGP_SIG_SYMMETRIC_ALGOS = 11, - OPENPGP_SIG_REVOCATION_KEY = 12, - OPENPGP_SIG_ISSUER = 16, - OPENPGP_SIG_NOTATION_DATA = 20, - OPENPGP_SIG_HASH_ALGOS = 21, - OPENPGP_SIG_COMPRESSION_ALGOS = 22, - OPENPGP_SIG_KEYSERVER_PREFS = 23, - OPENPGP_SIG_PREFERRED_KEYSERVER = 24, - OPENPGP_SIG_PRIMARY_USERID = 25, - OPENPGP_SIG_POLICY_URI = 26, - OPENPGP_SIG_KEY_FLAGS = 27, - OPENPGP_SIG_SIGNER_USERID = 28, - OPENPGP_SIG_REVOCATION_REASON = 29, - OPENPGP_SIG_FEATURES = 30, - OPENPGP_SIG_TARGET = 31, - OPENPGP_SIG_EMBEDDED_SIGNATURE = 32, -} OpenpgpSigPacket; - -static gboolean -read_byte (const guchar **at, - const guchar *end, - guint8 *result) -{ - g_assert (at); - if (*at == end) - *at = NULL; - if (*at == NULL) - return FALSE; - if (result) - *result = *(*at); - (*at)++; - return TRUE; -} - -static gboolean -read_bytes (const guchar **at, - const guchar *end, - gpointer buffer, - gsize length) -{ - g_assert (at); - if (*at + length > end) - *at = NULL; - if (*at == NULL) - return FALSE; - if (buffer != NULL) - memcpy (buffer, *at, length); - (*at) += length; - return TRUE; -} - -static gboolean -read_uint32 (const guchar **at, - const guchar *end, - guint32 *value) -{ - guchar buf[4]; - g_assert (at); - if (!read_bytes (at, end, buf, 4)) - return FALSE; - if (value) - *value = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; - return TRUE; -} - -static gboolean -read_uint16 (const guchar **at, - const guchar *end, - guint16 *value) -{ - guchar buf[2]; - g_assert (at); - if (!read_bytes (at, end, buf, 2)) - return FALSE; - if (value) - *value = buf[0] << 8 | buf[1]; - return TRUE; -} - -static gboolean -read_mpi (const guchar **at, - const guchar *end, - guint16 *bits, - guchar **value) -{ - gsize bytes; - guint16 b; - g_assert (at); - if (!bits) - bits = &b; - if (!read_uint16 (at, end, bits)) - return FALSE; - bytes = (*bits + 7) / 8; - if (bytes == 0) - return FALSE; - if (value) - *value = g_malloc (bytes); - if (!read_bytes (at, end, value ? *value : NULL, bytes)) { - if (value) - g_free (*value); - return FALSE; - } - return TRUE; -} - -static gboolean -read_new_length (const guchar **at, - const guchar *end, - gsize *pkt_len) -{ - guint8 c, c1; - guint32 val; - - if (!read_byte (at, end, &c)) - return FALSE; - if (c < 192) { - *pkt_len = c; - } else if (c >= 192 && c <= 223) { - if (!read_byte (at, end, &c1)) - return FALSE; - *pkt_len = ((c - 192) << 8) + c1 + 192; - } else if (c == 255) { - if (!read_uint32 (at, end, &val)) - return FALSE; - *pkt_len = val; - } else { - /* We don't support partial length */ - return FALSE; - } - - return TRUE; -} - -static gboolean -read_old_length (const guchar **at, - const guchar *end, - guchar ctb, - gsize *pkt_len) -{ - gsize llen = ctb & 0x03; - guint16 v16; - guint32 v32; - guint8 c; - - if (llen == 0) { - if (!read_byte (at, end, &c)) - return FALSE; - *pkt_len = c; - } else if (llen == 1) { - if (!read_uint16 (at, end, &v16)) - return FALSE; - *pkt_len = v16; - } else if (llen == 2) { - if (!read_uint32 (at, end, &v32)) - return FALSE; - *pkt_len = v32; - } else { - *pkt_len = end - *at; - } - - return TRUE; -} - -static GcrDataError -read_openpgp_packet (const guchar **at, - const guchar *end, - guint8 *pkt_type, - gsize *length) -{ - gboolean new_ctb; - guint8 ctb; - gboolean ret; - - if (!read_byte (at, end, &ctb)) - return GCR_ERROR_UNRECOGNIZED; - if (!(ctb & 0x80)) - return GCR_ERROR_UNRECOGNIZED; - - /* RFC2440 packet format. */ - if (ctb & 0x40) { - *pkt_type = ctb & 0x3f; - new_ctb = TRUE; - - /* the old RFC1991 packet format. */ - } else { - *pkt_type = ctb & 0x3f; - *pkt_type >>= 2; - new_ctb = FALSE; - } - - if (*pkt_type > 63) - return GCR_ERROR_UNRECOGNIZED; - - if (new_ctb) - ret = read_new_length (at, end, length); - else - ret = read_old_length (at, end, ctb, length); - if (!ret) - return GCR_ERROR_UNRECOGNIZED; - - if ((*at) + *length > end) - return GCR_ERROR_FAILURE; - - return GCR_SUCCESS; -} - -static gchar * -hash_user_id_or_attribute (const guchar *beg, - const guchar *end) -{ - guint8 digest[20] = { 0, }; - - g_assert (beg != NULL); - g_assert (end > beg); - - gcry_md_hash_buffer (GCRY_MD_RMD160, digest, beg, end - beg); - return egg_hex_encode_full (digest, sizeof (digest), TRUE, 0, 0); -} - -static gboolean -parse_v3_rsa_bits_and_keyid (const guchar **at, - const guchar *end, - guint16 *bits, - gchar **keyid) -{ - guchar *n; - gsize bytes; - - g_assert (bits); - g_assert (keyid); - - /* Read in the modulus */ - if (!read_mpi (at, end, bits, &n)) - return FALSE; - - /* Last 64-bits of modulus are keyid */ - bytes = (*bits + 7) / 8; - if (bytes < 8) { - g_free (n); - return FALSE; - } - - *keyid = egg_hex_encode_full (n + (bytes - 8), 8, TRUE, 0, 0); - return TRUE; -} - -static gchar * -hash_v4_keyid (const guchar *data, - const guchar *end, - gchar **fingerprint) -{ - gcry_md_hd_t mdh; - gcry_error_t gcry; - guchar header[3]; - guint8 *digest; - gchar *keyid; - gsize len; - - /* - * Both primary and subkeys use the public key tag byte - * 0x99 to construct the hash. So we skip over that here. - */ - - g_assert (data != NULL); - g_assert (end > data); - - len = end - data; - g_return_val_if_fail (len < G_MAXUSHORT, NULL); - - header[0] = 0x99; - header[1] = len >> 8 & 0xff; - header[2] = len & 0xff; - - gcry = gcry_md_open (&mdh, GCRY_MD_SHA1, 0); - g_return_val_if_fail (gcry == 0, NULL); - - gcry_md_write (mdh, header, 3); - gcry_md_write (mdh, data, len); - - digest = gcry_md_read (mdh, 0); - keyid = egg_hex_encode_full (digest + 12, 8, TRUE, 0, 0); - if (fingerprint) - *fingerprint = egg_hex_encode_full (digest, 20, TRUE, 0, 0); - gcry_md_close (mdh); - - return keyid; -} - -static gboolean -parse_v4_algo_bits (const guchar **at, - const guchar *end, - guint8 algo, - guint16 *bits) -{ - switch (algo) { - case GCR_OPENPGP_ALGO_RSA: - case GCR_OPENPGP_ALGO_RSA_E: - case GCR_OPENPGP_ALGO_RSA_S: - if (!read_mpi (at, end, bits, NULL) || - !read_mpi (at, end, NULL, NULL)) - return FALSE; - return TRUE; - case GCR_OPENPGP_ALGO_DSA: - if (!read_mpi (at, end, bits, NULL) || - !read_mpi (at, end, NULL, NULL) || - !read_mpi (at, end, NULL, NULL) || - !read_mpi (at, end, NULL, NULL)) - return FALSE; - return TRUE; - case GCR_OPENPGP_ALGO_ELG_E: - if (!read_mpi (at, end, bits, NULL) || - !read_mpi (at, end, NULL, NULL) || - !read_mpi (at, end, NULL, NULL)) - return FALSE; - return TRUE; - default: /* Unsupported key */ - return FALSE; - } -} - -static const gchar * -default_caps_for_algo (guint8 algo) -{ - switch (algo) { - case GCR_OPENPGP_ALGO_RSA: - return "cse"; - case GCR_OPENPGP_ALGO_RSA_E: - return "e"; - case GCR_OPENPGP_ALGO_RSA_S: - return "s"; - case GCR_OPENPGP_ALGO_ELG_E: - return "e"; - case GCR_OPENPGP_ALGO_DSA: - return "sca"; - default: - return ""; - } -} - -static gboolean -parse_public_key_or_subkey (GQuark schema, - guint n_columns, - const guchar *beg, - const guchar **at, - const guchar *end, - GcrOpenpgpParseFlags flags, - GPtrArray *records) -{ - gchar *keyid; - GcrRecord *record; - guint8 version; - guint32 timestamp; - guint16 ndays = 0; - guint8 algo; - guint16 bits; - gulong expiry; - gchar *fingerprint; - const guchar *data; - - /* Start of actual key data in packet */ - data = *at; - - /* First byte is version */ - if (!read_byte (at, end, &version)) - return FALSE; - if (version < 2 || version > 4) - return FALSE; - - /* Next a 4 byte create date */ - if (!read_uint32 (at, end, ×tamp)) - return FALSE; - /* If version 2 or 3, validity days comes next */ - if (version < 4) { - if (!read_uint16 (at, end, &ndays)) - return FALSE; - } - - /* Algorithm */ - if (!read_byte (at, end, &algo)) - return FALSE; - - /* For version 2 and 3, only RSA, keyid is low 64-bits of modulus */ - if (version < 4) { - if (!parse_v3_rsa_bits_and_keyid (at, end, &bits, &keyid)) - return FALSE; - - /* For version 4 */ - } else { - if (!parse_v4_algo_bits (at, end, algo, &bits)) - return FALSE; - keyid = hash_v4_keyid (data, *at, &fingerprint); - } - - record = _gcr_record_new (schema, n_columns, ':'); - _gcr_record_set_uint (record, GCR_RECORD_KEY_BITS, bits); - _gcr_record_set_uint (record, GCR_RECORD_KEY_ALGO, algo); - _gcr_record_take_raw (record, GCR_RECORD_KEY_KEYID, keyid); - _gcr_record_set_ulong (record, GCR_RECORD_KEY_TIMESTAMP, timestamp); - if (schema != GCR_RECORD_SCHEMA_SEC && schema != GCR_RECORD_SCHEMA_SSB) - _gcr_record_set_raw (record, GCR_RECORD_PUB_CAPS, default_caps_for_algo (algo)); - - if (ndays > 0) { - expiry = (gulong)timestamp + ((gulong)ndays * 86400); - _gcr_record_set_ulong (record, GCR_RECORD_KEY_EXPIRY, expiry); - } - - g_ptr_array_add (records, record); - - if (fingerprint && (schema == GCR_RECORD_SCHEMA_PUB || schema == GCR_RECORD_SCHEMA_SEC)) { - record = _gcr_record_new (GCR_RECORD_SCHEMA_FPR, GCR_RECORD_FPR_MAX, ':'); - _gcr_record_take_raw (record, GCR_RECORD_FPR_FINGERPRINT, fingerprint); - g_ptr_array_add (records, record); - fingerprint = NULL; - } - - g_free (fingerprint); - return TRUE; -} - -static gboolean -parse_secret_key_or_subkey (GQuark schema, - const guchar *beg, - const guchar **at, - const guchar *end, - GcrOpenpgpParseFlags flags, - GPtrArray *records) -{ - /* - * Identical to a public key, with extra crap after it. The - * extra crap is hard to parse and doesn't add anything to - * the records, so just skip over it. - * - * Also don't print out trust, that doesn't make sense for - * secret keys. - */ - - if (!parse_public_key_or_subkey (schema, GCR_RECORD_SEC_MAX, - beg, at, end, flags, records)) - return FALSE; - - *at = end; - return TRUE; -} - -static gboolean -parse_user_id (const guchar *beg, - const guchar **at, - const guchar *end, - GcrOpenpgpParseFlags flags, - GPtrArray *records) -{ - gchar *string; - GcrRecord *record; - gchar *fingerprint; - - g_assert (at); - if (!*at || !end || *at > end) - return FALSE; - - string = g_strndup ((gchar *)*at, end - *at); - - fingerprint = hash_user_id_or_attribute (*at, end); - record = _gcr_record_new (GCR_RECORD_SCHEMA_UID, GCR_RECORD_UID_MAX, ':'); - _gcr_record_take_raw (record, GCR_RECORD_UID_FINGERPRINT, fingerprint); - _gcr_record_set_string (record, GCR_RECORD_UID_USERID, string); - g_free (string); - - g_ptr_array_add (records, record); - - *at = end; - return TRUE; -} - -static gboolean -parse_user_attribute_packet (const guchar *beg, - const guchar **at, - const guchar *end, - guchar subpkt_type, - GPtrArray *records) -{ - GcrRecord *record; - gchar *fingerprint; - - record = _gcr_record_new (GCR_RECORD_SCHEMA_XA1, GCR_RECORD_XA1_MAX, ':'); - _gcr_record_set_uint (record, GCR_RECORD_XA1_LENGTH, end - *at); - _gcr_record_set_uint (record, GCR_RECORD_XA1_TYPE, subpkt_type); - fingerprint = hash_user_id_or_attribute (*at, end); - _gcr_record_take_raw (record, GCR_RECORD_XA1_FINGERPRINT, fingerprint); - _gcr_record_set_base64 (record, GCR_RECORD_XA1_DATA, *at, end - *at); - - g_ptr_array_add (records, record); - - *at = end; - return TRUE; -} - -static gboolean -parse_user_attribute (const guchar *beg, - const guchar **at, - const guchar *end, - GcrOpenpgpParseFlags flags, - GPtrArray *records) -{ - gsize subpkt_len; - guint count = 0; - const guchar *start; - const guchar *subpkt_beg; - guint8 subpkt_type; - gchar *fingerprint; - gchar *string; - GcrRecord *record; - - start = *at; - while (*at != end) { - subpkt_beg = *at; - - if (!read_new_length (at, end, &subpkt_len) || - !read_byte (at, end, &subpkt_type)) - return FALSE; - - count++; - - if (flags & GCR_OPENPGP_PARSE_ATTRIBUTES) { - if (!parse_user_attribute_packet (subpkt_beg, at, - *at + (subpkt_len - 1), - subpkt_type, records)) - return FALSE; - - /* We already progressed one extra byte for the subpkt_type */ - } else { - *at += (subpkt_len - 1); - } - } - - fingerprint = hash_user_id_or_attribute (start, end); - string = g_strdup_printf ("%d %d", count, (guint)(*at - start)); - record = _gcr_record_new (GCR_RECORD_SCHEMA_UAT, GCR_RECORD_UAT_MAX, ':'); - _gcr_record_take_raw (record, GCR_RECORD_UAT_FINGERPRINT, fingerprint); - _gcr_record_take_raw (record, GCR_RECORD_UAT_COUNT_SIZE, string); - - g_ptr_array_add (records, record); - return TRUE; -} - -static gboolean -skip_signature_mpis (const guchar **at, - const guchar *end, - guint8 algo) -{ - switch (algo) { - - /* RSA signature value */ - case GCR_OPENPGP_ALGO_RSA: - return read_mpi (at, end, NULL, NULL); - - /* DSA values r and s */ - case GCR_OPENPGP_ALGO_DSA: - return read_mpi (at, end, NULL, NULL) && - read_mpi (at, end, NULL, NULL); - default: - return FALSE; - } -} - -static gboolean -parse_v3_signature (const guchar **at, - const guchar *end, - GcrOpenpgpParseFlags flags, - GPtrArray *records) -{ - guchar keyid[8]; - guint8 sig_type; - guint8 sig_len; - guint32 sig_time; - guint8 key_algo; - guint8 hash_algo; - guint16 left_bits; - GcrRecord *record; - gchar *value; - - if (!read_byte (at, end, &sig_len) || sig_len != 5) - return FALSE; - - if (!read_byte (at, end, &sig_type) || - !read_uint32 (at, end, &sig_time) || - !read_bytes (at, end, keyid, 8) || - !read_byte (at, end, &key_algo) || - !read_byte (at, end, &hash_algo) || - !read_uint16 (at, end, &left_bits) || - !skip_signature_mpis (at, end, key_algo)) - return FALSE; - - if (flags & GCR_OPENPGP_PARSE_SIGNATURES) { - record = _gcr_record_new (GCR_RECORD_SCHEMA_SIG, GCR_RECORD_SIG_MAX, ':'); - _gcr_record_set_uint (record, GCR_RECORD_SIG_ALGO, key_algo); - value = egg_hex_encode_full (keyid, sizeof (keyid), TRUE, 0, 0); - _gcr_record_take_raw (record, GCR_RECORD_SIG_KEYID, value); - _gcr_record_set_ulong (record, GCR_RECORD_SIG_TIMESTAMP, sig_time); - value = g_strdup_printf ("%02xx", (guint)sig_type); - _gcr_record_take_raw (record, GCR_RECORD_SIG_CLASS, value); - g_ptr_array_add (records, record); - } - - return TRUE; -} - -typedef struct { - gulong key_expiry; - gboolean exportable; - gboolean primary; - guint8 key_flags; - GcrRecord *revocation; -} SigSubpacket; - -static gboolean -parse_v4_signature_revocation (const guchar **at, - const guchar *end, - GcrRecord *revocation) -{ - guchar fingerprint[20]; - gchar *value; - guint8 klass; - guint8 algo; - - if (!read_byte (at, end, &klass) || - !read_byte (at, end, &algo) || - !read_bytes (at, end, fingerprint, 20)) - return FALSE; - - _gcr_record_set_uint (revocation, GCR_RECORD_RVK_ALGO, algo); - value = egg_hex_encode_full (fingerprint, 20, TRUE, 0, 0); - _gcr_record_take_raw (revocation, GCR_RECORD_RVK_FINGERPRINT, value); - value = g_strdup_printf ("%02X", (guint)klass); - _gcr_record_take_raw (revocation, GCR_RECORD_RVK_CLASS, value); - - return TRUE; -} - -static gboolean -parse_v4_signature_subpacket (const guchar **at, - const guchar *end, - guint8 sub_type, - GcrRecord *record, - SigSubpacket *subpkt) -{ - guchar keyid[8]; - guint32 when; - guint8 byte; - gboolean critical; - gchar *value; - - critical = (sub_type & 0x80) ? TRUE : FALSE; - sub_type &= ~0xC0; - - switch (sub_type) { - case OPENPGP_SIG_CREATION: - if (!read_uint32 (at, end, &when)) - return FALSE; - _gcr_record_set_ulong (record, GCR_RECORD_SIG_TIMESTAMP, when); - return TRUE; - case OPENPGP_SIG_ISSUER: - if (!read_bytes (at, end, keyid, 8)) - return FALSE; - value = egg_hex_encode_full (keyid, 8, TRUE, 0, 0); - _gcr_record_take_raw (record, GCR_RECORD_SIG_KEYID, value); - return TRUE; - case OPENPGP_SIG_KEY_EXPIRY: - if (!read_uint32 (at, end, &when)) - return FALSE; - subpkt->key_expiry = when; - return TRUE; - case OPENPGP_SIG_EXPIRY: - if (!read_uint32 (at, end, &when)) - return FALSE; - _gcr_record_set_ulong (record, GCR_RECORD_SIG_EXPIRY, when); - return TRUE; - case OPENPGP_SIG_EXPORTABLE: - if (!read_byte (at, end, &byte)) - return FALSE; - if (byte != 0 && byte != 1) - return FALSE; - subpkt->exportable = (byte == 0 ? FALSE : TRUE); - return TRUE; - - case OPENPGP_SIG_PRIMARY_USERID: - if (!read_byte (at, end, &byte)) - return FALSE; - if (byte != 0 && byte != 1) - return FALSE; - subpkt->primary = byte; - return TRUE; - - case OPENPGP_SIG_KEY_FLAGS: - if (!read_byte (at, end, &byte)) - return FALSE; - *at = end; /* N octets of flags */ - subpkt->key_flags = byte; - return TRUE; - - case OPENPGP_SIG_SIGNER_USERID: - value = g_strndup ((gchar *)*at, end - *at); - _gcr_record_set_string (record, GCR_RECORD_SIG_USERID, value); - g_free (value); - return TRUE; - - case OPENPGP_SIG_REVOCATION_KEY: - _gcr_record_free (subpkt->revocation); - subpkt->revocation = _gcr_record_new (GCR_RECORD_SCHEMA_RVK, GCR_RECORD_RVK_MAX, ':'); - return parse_v4_signature_revocation (at, end, subpkt->revocation); - - /* Ignored */ - case OPENPGP_SIG_SYMMETRIC_ALGOS: - case OPENPGP_SIG_HASH_ALGOS: - case OPENPGP_SIG_COMPRESSION_ALGOS: - case OPENPGP_SIG_REVOCABLE: - case OPENPGP_SIG_TRUST: - case OPENPGP_SIG_REGULAR_EXPRESSION: - case OPENPGP_SIG_NOTATION_DATA: - case OPENPGP_SIG_KEYSERVER_PREFS: - case OPENPGP_SIG_PREFERRED_KEYSERVER: - case OPENPGP_SIG_POLICY_URI: - case OPENPGP_SIG_REVOCATION_REASON: - case OPENPGP_SIG_FEATURES: - case OPENPGP_SIG_TARGET: - case OPENPGP_SIG_EMBEDDED_SIGNATURE: - *at = end; - return TRUE; - - /* Unrecognized */ - default: - /* Critical, but not recognized */ - if (critical) - return FALSE; - *at = end; - return TRUE; - } - -} - -static gboolean -parse_v4_signature_subpackets (const guchar **at, - const guchar *end, - GcrRecord *record, - SigSubpacket *subpkt) -{ - gsize length; - guint8 sub_type; - const guchar *stop; - - while (*at != end) { - if (!read_new_length (at, end, &length) || - !read_byte (at, end, &sub_type) || - length == 0) - return FALSE; - - /* The length includes the sub_type */ - length--; - stop = *at + length; - if (stop > end) - return FALSE; - - /* Actually parse the sub packets */ - if (!parse_v4_signature_subpacket (at, stop, sub_type, record, subpkt)) - return FALSE; - if (*at != stop) - return FALSE; - } - - return TRUE; -} - -static GcrRecord * -uid_or_uat_find_for_self_signature (GPtrArray *records, - guint8 sig_type) -{ - GcrRecord *record; - GQuark schema; - - if (records->len == 0) - return NULL; - - switch (sig_type) { - /* Generic certification of a key or userid */ - case 0x10: case 0x11: case 0x12: case 0x13: - record = records->pdata[records->len - 1]; - schema = _gcr_record_get_schema (record); - if (schema == GCR_RECORD_SCHEMA_UID || - schema == GCR_RECORD_SCHEMA_UAT) - return record; - return NULL; - - default: - return NULL; - } - -} - -static GcrRecord * -key_or_sub_find_for_self_signature (GPtrArray *records, - guint8 sig_type, - const gchar *keyid) -{ - GcrRecord *record; - const gchar *check; - GQuark schema; - gint i; - - if (records->len == 0) - return NULL; - - switch (sig_type) { - /* Generic certification of a key or userid */ - case 0x10: case 0x11: case 0x12: case 0x13: - for (i = records->len - 1; i >= 0; i--) { - record = records->pdata[i]; - schema = _gcr_record_get_schema (record); - if (schema == GCR_RECORD_SCHEMA_PUB || schema == GCR_RECORD_SCHEMA_SEC) { - check = _gcr_record_get_raw (record, GCR_RECORD_KEY_KEYID); - return (check != NULL && g_str_equal (check, keyid)) ? record : NULL; - } - } - return NULL; - - /* (Primary) Subkey Binding Signature */ - case 0x18: case 0x19: - record = records->pdata[records->len - 1]; - schema = _gcr_record_get_schema (record); - if (schema == GCR_RECORD_SCHEMA_SUB) - return record; - return NULL; - - default: - return NULL; - } -} - -static void -pub_or_sub_set_key_caps (GcrRecord *record, - guint8 key_flags) -{ - GString *string; - GQuark schema; - - schema = _gcr_record_get_schema (record); - if (schema == GCR_RECORD_SCHEMA_SEC || schema == GCR_RECORD_SCHEMA_SSB) - return; - - string = g_string_sized_new (8); - if (key_flags & 0x02) - g_string_append_c (string, 's'); - if (key_flags & 0x01) - g_string_append_c (string, 'c'); - if (key_flags & 0x04 || key_flags & 0x08) - g_string_append_c (string, 'e'); - if (key_flags & 0x20) - g_string_append_c (string, 'a'); - - _gcr_record_take_raw (record, GCR_RECORD_PUB_CAPS, - g_string_free (string, FALSE)); -} - -static gboolean -parse_v4_signature (const guchar **at, - const guchar *end, - GcrOpenpgpParseFlags flags, - GPtrArray *records) -{ - guint8 sig_type; - guint8 key_algo; - guint8 hash_algo; - guint16 hashed_len; - guint16 unhashed_len; - guint16 left_bits; - GcrRecord *record; - GcrRecord *key, *uid; - const gchar *keyid; - gchar *value; - const guchar *stop; - gulong timestamp; - - /* Information to transfer back onto the key record */ - SigSubpacket subpkt = { 0, }; - subpkt.exportable = 1; - - if (!read_byte (at, end, &sig_type) || - !read_byte (at, end, &key_algo) || - !read_byte (at, end, &hash_algo) || - !read_uint16 (at, end, &hashed_len)) - return FALSE; - - /* Hashed subpackets which we use */ - record = _gcr_record_new (GCR_RECORD_SCHEMA_SIG, GCR_RECORD_SIG_MAX, ':'); - stop = *at + hashed_len; - if (stop > end || - !parse_v4_signature_subpackets (at, stop, record, &subpkt)) { - _gcr_record_free (record); - _gcr_record_free (subpkt.revocation); - return FALSE; - } - - /* Includes unhashed subpackets, which we skip over */ - if (!read_uint16 (at, end, &unhashed_len)) { - _gcr_record_free (record); - _gcr_record_free (subpkt.revocation); - return FALSE; - } - - stop = *at + unhashed_len; - if (stop > end || - !parse_v4_signature_subpackets (at, stop, record, &subpkt) || - !read_uint16 (at, end, &left_bits) || - !skip_signature_mpis (at, end, key_algo)) { - _gcr_record_free (record); - _gcr_record_free (subpkt.revocation); - return FALSE; - } - - if (subpkt.revocation) { - g_ptr_array_add (records, subpkt.revocation); - subpkt.revocation = NULL; - } - - /* Fill in information on previous key or subkey */ - keyid = _gcr_record_get_raw (record, GCR_RECORD_SIG_KEYID); - key = key_or_sub_find_for_self_signature (records, sig_type, keyid); - if (key != NULL) { - if (subpkt.key_expiry != 0) { - if (_gcr_record_get_ulong (key, GCR_RECORD_KEY_TIMESTAMP, ×tamp)) - _gcr_record_set_ulong (key, GCR_RECORD_KEY_EXPIRY, timestamp + subpkt.key_expiry); - } - if (subpkt.key_flags != 0) - pub_or_sub_set_key_caps (key, subpkt.key_flags); - } - - if (key && _gcr_record_get_schema (key) == GCR_RECORD_SCHEMA_PUB) { - uid = uid_or_uat_find_for_self_signature (records, sig_type); - if (uid != NULL) { - if (_gcr_record_get_ulong (record, GCR_RECORD_SIG_TIMESTAMP, ×tamp)) - _gcr_record_set_ulong (uid, GCR_RECORD_UID_TIMESTAMP, timestamp); - } - } - - if (flags & GCR_OPENPGP_PARSE_SIGNATURES) { - _gcr_record_set_uint (record, GCR_RECORD_SIG_ALGO, key_algo); - value = g_strdup_printf ("%02x%s", (guint)sig_type, - subpkt.exportable ? "x" : "l"); - _gcr_record_take_raw (record, GCR_RECORD_SIG_CLASS, value); - g_ptr_array_add (records, record); - } else { - _gcr_record_free (record); - } - - return TRUE; -} - -static gboolean -parse_signature (const guchar *beg, - const guchar **at, - const guchar *end, - GcrOpenpgpParseFlags flags, - GPtrArray *records) -{ - guint8 version; - - if (!read_byte (at, end, &version)) - return FALSE; - - if (version == 3) - return parse_v3_signature (at, end, flags, records); - else if (version == 4) - return parse_v4_signature (at, end, flags, records); - else - return FALSE; -} - -static GcrDataFormat -parse_openpgp_packet (const guchar *beg, - const guchar *at, - const guchar *end, - guint8 pkt_type, - GcrOpenpgpParseFlags flags, - GPtrArray *records) -{ - gboolean ret; - - switch (pkt_type) { - case OPENPGP_PKT_PUBLIC_KEY: - ret = parse_public_key_or_subkey (GCR_RECORD_SCHEMA_PUB, GCR_RECORD_PUB_MAX, - beg, &at, end, flags, records); - break; - case OPENPGP_PKT_PUBLIC_SUBKEY: - ret = parse_public_key_or_subkey (GCR_RECORD_SCHEMA_SUB, GCR_RECORD_PUB_MAX, - beg, &at, end, flags, records); - break; - case OPENPGP_PKT_USER_ID: - ret = parse_user_id (beg, &at, end, flags, records); - break; - case OPENPGP_PKT_ATTRIBUTE: - ret = parse_user_attribute (beg, &at, end, flags, records); - break; - case OPENPGP_PKT_SIGNATURE: - ret = parse_signature (beg, &at, end, flags, records); - break; - case OPENPGP_PKT_SECRET_KEY: - ret = parse_secret_key_or_subkey (GCR_RECORD_SCHEMA_SEC, - beg, &at, end, flags, records); - break; - case OPENPGP_PKT_SECRET_SUBKEY: - ret = parse_secret_key_or_subkey (GCR_RECORD_SCHEMA_SSB, - beg, &at, end, flags, records); - break; - - /* Stuff we don't want to be meddling with right now */ - case OPENPGP_PKT_RING_TRUST: - return GCR_SUCCESS; - - /* Ignore packets we don't understand */ - default: - return GCR_SUCCESS; - } - - /* Key packet had extra data */ - if (ret == TRUE && at != end) - ret = FALSE; - - return ret ? GCR_SUCCESS : GCR_ERROR_FAILURE; -} - -static void -append_key_capabilities (GString *string, - const gchar *caps) -{ - guint i; - gchar cap; - - for (i = 0; caps[i] != 0; i++) { - cap = g_ascii_toupper (caps[i]); - if (!strchr (string->str, cap)) - g_string_append_c (string, cap); - } -} - -static void -normalize_capabilities (GPtrArray *records) -{ - GString *string; - GQuark schema; - const gchar *caps; - guint i; - - /* Gather the capabilities of all subkeys into the primary key */ - string = g_string_new (_gcr_record_get_raw (records->pdata[0], GCR_RECORD_PUB_CAPS)); - for (i = 0; i < records->len; i++) { - schema = _gcr_record_get_schema (records->pdata[i]); - if (schema == GCR_RECORD_SCHEMA_PUB || schema == GCR_RECORD_SCHEMA_SUB) { - caps = _gcr_record_get_raw (records->pdata[i], GCR_RECORD_PUB_CAPS); - append_key_capabilities (string, caps); - } - } - _gcr_record_take_raw (records->pdata[0], GCR_RECORD_PUB_CAPS, - g_string_free (string, FALSE)); -} - -static gboolean -check_key_expiry (GcrRecord *record) -{ - gulong expiry; - time_t current; - - if (_gcr_record_get_ulong (record, GCR_RECORD_KEY_EXPIRY, &expiry)) { - if (expiry == 0) - return FALSE; - current = time (NULL); - if (current > expiry) - return TRUE; - } - - return FALSE; -} - -static void -normalize_key_records (GPtrArray *records) -{ - GQuark schema; - guchar trust = 0; - const gchar *prev; - gboolean force = FALSE; - guint i; - - if (records->len == 0) - return; - - schema = _gcr_record_get_schema (records->pdata[0]); - if (schema == GCR_RECORD_SCHEMA_PUB) { - - if (check_key_expiry (records->pdata[0])) { - trust = 'e'; - force = TRUE; - - /* Mark public keys as unknown trust */ - } else { - normalize_capabilities (records); - trust = 'o'; - force = FALSE; - } - - /* Ownertrust unknown, new to system */ - _gcr_record_set_char (records->pdata[0], GCR_RECORD_KEY_OWNERTRUST, 'o'); - - } else if (schema == GCR_RECORD_SCHEMA_SEC) { - - /* Trust doesn't make sense for secret keys */ - trust = 0; - force = FALSE; - } - - - /* Setup default trust if necessary */ - if (trust != 0) { - for (i = 0; i < records->len; i++) { - if (!force) { - prev = _gcr_record_get_raw (records->pdata[i], GCR_RECORD_TRUST); - if (prev != NULL && prev[0]) - continue; - } - schema = _gcr_record_get_schema (records->pdata[i]); - if (schema != GCR_RECORD_SCHEMA_SIG && schema != GCR_RECORD_SCHEMA_FPR) - _gcr_record_set_char (records->pdata[i], GCR_RECORD_TRUST, trust); - } - } -} - -typedef struct { - GcrOpenpgpCallback callback; - gpointer user_data; - guint count; - GPtrArray *records; -} openpgp_parse_closure; - -static void -openpgp_parse_free (gpointer data) -{ - openpgp_parse_closure *closure = data; - g_ptr_array_unref (closure->records); - g_free (closure); -} - -static void -maybe_emit_openpgp_block (openpgp_parse_closure *closure, - const guchar *block, - const guchar *end) -{ - gsize length; - GPtrArray *records; - - if (block == NULL || block == end) - return; - - g_assert (end != NULL); - g_assert (end > block); - - length = end - block; - closure->count++; - - records = closure->records; - closure->records = g_ptr_array_new_with_free_func (_gcr_record_free); - - if (closure->callback) - (closure->callback) (records, block, length, closure->user_data); - - g_ptr_array_unref (records); -} - -guint -_gcr_openpgp_parse (gconstpointer data, - gsize n_data, - GcrOpenpgpParseFlags flags, - GcrOpenpgpCallback callback, - gpointer user_data) -{ - openpgp_parse_closure *closure; - const guchar *at; - const guchar *beg; - const guchar *end; - const guchar *block; - guint8 pkt_type; - GcrDataError res; - gsize length; - gboolean new_key; - guint ret; - - g_return_val_if_fail (data != NULL, 0); - - /* For libgcrypt */ - _gcr_initialize_library (); - - at = data; - end = at + n_data; - block = NULL; - - closure = g_new0 (openpgp_parse_closure, 1); - closure->callback = callback; - closure->user_data = user_data; - closure->records = g_ptr_array_new_with_free_func (_gcr_record_free); - - while (at != NULL && at != end) { - beg = at; - res = read_openpgp_packet (&at, end, &pkt_type, &length); - - if (res == GCR_SUCCESS) { - new_key = (pkt_type == OPENPGP_PKT_PUBLIC_KEY || - pkt_type == OPENPGP_PKT_SECRET_KEY); - if (flags & GCR_OPENPGP_PARSE_KEYS && new_key) - normalize_key_records (closure->records); - /* Start of a new set of packets, per key */ - if (!(flags & GCR_OPENPGP_PARSE_KEYS) || new_key) { - maybe_emit_openpgp_block (closure, block, beg); - block = beg; - } - if (!(flags & GCR_OPENPGP_PARSE_NO_RECORDS)) - parse_openpgp_packet (beg, at, at + length, pkt_type, - flags, closure->records); - } - - if (res != GCR_SUCCESS) { - if (block != NULL && block != beg) - maybe_emit_openpgp_block (closure, block, beg); - block = NULL; - break; - } - - at += length; - } - - if (flags & GCR_OPENPGP_PARSE_KEYS) - normalize_key_records (closure->records); - maybe_emit_openpgp_block (closure, block, at); - ret = closure->count; - openpgp_parse_free (closure); - return ret; -} diff --git a/gcr/gcr-openpgp.h b/gcr/gcr-openpgp.h deleted file mode 100644 index 31fd2956..00000000 --- a/gcr/gcr-openpgp.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_H_INSIDE__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> can be included directly." -#endif - -#ifndef __GCR_OPENPGP_H__ -#define __GCR_OPENPGP_H__ - -#include <glib.h> - -#include <gck/gck.h> - -typedef enum { - GCR_OPENPGP_ALGO_RSA = 1, - GCR_OPENPGP_ALGO_RSA_E = 2, - GCR_OPENPGP_ALGO_RSA_S = 3, - GCR_OPENPGP_ALGO_ELG_E = 16, - GCR_OPENPGP_ALGO_DSA = 17 -} GcrOpenpgpAlgo; - -typedef enum { - GCR_OPENPGP_PARSE_NONE = 0, - GCR_OPENPGP_PARSE_KEYS = 1 << 1, - GCR_OPENPGP_PARSE_NO_RECORDS = 1 << 2, - GCR_OPENPGP_PARSE_SIGNATURES = 1 << 3, - GCR_OPENPGP_PARSE_ATTRIBUTES = 1 << 4, -} GcrOpenpgpParseFlags; - -G_BEGIN_DECLS - -typedef void (*GcrOpenpgpCallback) (GPtrArray *records, - const guchar *outer, - gsize n_outer, - gpointer user_data); - -guint _gcr_openpgp_parse (gconstpointer data, - gsize n_data, - GcrOpenpgpParseFlags flags, - GcrOpenpgpCallback callback, - gpointer user_data); - -G_END_DECLS - -#endif /* __GCR_OPENPGP_H__ */ diff --git a/gcr/gcr-openssh.c b/gcr/gcr-openssh.c deleted file mode 100644 index e285465c..00000000 --- a/gcr/gcr-openssh.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-openssh.h" -#include "gcr-internal.h" -#include "gcr-types.h" - -#include "egg/egg-buffer.h" -#include "egg/egg-decimal.h" - -#include "pkcs11/pkcs11.h" - -#include <string.h> - -typedef struct { - GcrOpensshPubCallback callback; - gpointer user_data; -} OpensshPubClosure; - -static void -skip_spaces (const gchar ** line, - gsize *n_line) -{ - while (*n_line > 0 && (*line)[0] == ' ') { - (*line)++; - (*n_line)--; - } -} - -static gboolean -next_word (const gchar **line, - gsize *n_line, - const gchar **word, - gsize *n_word) -{ - const gchar *beg; - const gchar *end; - const gchar *at; - gboolean quotes; - - skip_spaces (line, n_line); - - if (!*n_line) { - *word = NULL; - *n_word = 0; - return FALSE; - } - - beg = at = *line; - end = beg + *n_line; - quotes = FALSE; - - do { - switch (*at) { - case '"': - quotes = !quotes; - at++; - break; - case ' ': - if (!quotes) - end = at; - else - at++; - break; - default: - at++; - break; - } - } while (at < end); - - *word = beg; - *n_word = end - beg; - (*line) += *n_word; - (*n_line) -= *n_word; - return TRUE; -} - -static gboolean -match_word (const gchar *word, - gsize n_word, - const gchar *matches) -{ - gsize len = strlen (matches); - if (len != n_word) - return FALSE; - return memcmp (word, matches, n_word) == 0; -} - -static gulong -keytype_to_algo (const gchar *algo, - gsize length) -{ - if (!algo) - return G_MAXULONG; - else if (match_word (algo, length, "ssh-rsa")) - return CKK_RSA; - else if (match_word (algo, length, "ssh-dss")) - return CKK_DSA; - return G_MAXULONG; -} - -static gboolean -read_decimal_mpi (const gchar *decimal, - gsize n_decimal, - GckAttributes *attrs, - gulong attribute_type) -{ - gpointer data; - gsize n_data; - - data = egg_decimal_decode (decimal, n_decimal, &n_data); - if (data == NULL) - return FALSE; - - gck_attributes_add_data (attrs, attribute_type, data, n_data); - return TRUE; -} - -static gint -atoin (const char *p, gint digits) -{ - gint ret = 0, base = 1; - while(--digits >= 0) { - if (p[digits] < '0' || p[digits] > '9') - return -1; - ret += (p[digits] - '0') * base; - base *= 10; - } - return ret; -} - -static GcrDataError -parse_v1_public_line (const gchar *line, - gsize length, - GcrOpensshPubCallback callback, - gpointer user_data) -{ - const gchar *word_bits, *word_exponent, *word_modulus, *word_options, *outer; - gsize len_bits, len_exponent, len_modulus, len_options, n_outer; - GckAttributes *attrs; - gchar *label, *options; - gint bits; - - g_assert (line); - - outer = line; - n_outer = length; - options = NULL; - label = NULL; - - /* Eat space at the front */ - skip_spaces (&line, &length); - - /* Blank line or comment */ - if (length == 0 || line[0] == '#') - return GCR_ERROR_UNRECOGNIZED; - - /* - * If the line starts with a digit, then no options: - * - * 2048 35 25213680043....93533757 Label - * - * If the line doesn't start with a digit, then have options: - * - * option,option 2048 35 25213680043....93533757 Label - */ - if (g_ascii_isdigit (line[0])) { - word_options = NULL; - len_options = 0; - } else { - if (!next_word (&line, &length, &word_options, &len_options)) - return GCR_ERROR_UNRECOGNIZED; - } - - if (!next_word (&line, &length, &word_bits, &len_bits) || - !next_word (&line, &length, &word_exponent, &len_exponent) || - !next_word (&line, &length, &word_modulus, &len_modulus)) - return GCR_ERROR_UNRECOGNIZED; - - bits = atoin (word_bits, len_bits); - if (bits <= 0) - return GCR_ERROR_UNRECOGNIZED; - - attrs = gck_attributes_new (); - - if (!read_decimal_mpi (word_exponent, len_exponent, attrs, CKA_PUBLIC_EXPONENT) || - !read_decimal_mpi (word_modulus, len_modulus, attrs, CKA_MODULUS)) { - gck_attributes_unref (attrs); - return GCR_ERROR_UNRECOGNIZED; - } - - gck_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_RSA); - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY); - - skip_spaces (&line, &length); - if (length > 0) { - label = g_strndup (line, length); - g_strstrip (label); - gck_attributes_add_string (attrs, CKA_LABEL, label); - } - - if (word_options) - options = g_strndup (word_options, len_options); - - if (callback != NULL) - (callback) (attrs, label, options, outer, n_outer, user_data); - - gck_attributes_unref (attrs); - g_free (options); - g_free (label); - return GCR_SUCCESS; -} - -static gboolean -read_buffer_mpi (EggBuffer *buffer, - gsize *offset, - GckAttributes *attrs, - gulong attribute_type) -{ - const guchar *data; - gsize len; - - if (!egg_buffer_get_byte_array (buffer, *offset, offset, &data, &len)) - return FALSE; - - gck_attributes_add_data (attrs, attribute_type, data, len); - return TRUE; -} - -static GckAttributes * -read_v2_public_dsa (EggBuffer *buffer, - gsize *offset) -{ - GckAttributes *attrs; - - attrs = gck_attributes_new (); - - if (!read_buffer_mpi (buffer, offset, attrs, CKA_PRIME) || - !read_buffer_mpi (buffer, offset, attrs, CKA_SUBPRIME) || - !read_buffer_mpi (buffer, offset, attrs, CKA_BASE) || - !read_buffer_mpi (buffer, offset, attrs, CKA_VALUE)) { - gck_attributes_unref (attrs); - return NULL; - } - - gck_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_DSA); - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY); - - return attrs; -} - -static GckAttributes * -read_v2_public_rsa (EggBuffer *buffer, - gsize *offset) -{ - GckAttributes *attrs; - - attrs = gck_attributes_new (); - - if (!read_buffer_mpi (buffer, offset, attrs, CKA_PUBLIC_EXPONENT) || - !read_buffer_mpi (buffer, offset, attrs, CKA_MODULUS)) { - gck_attributes_unref (attrs); - return NULL; - } - - gck_attributes_add_ulong (attrs, CKA_KEY_TYPE, CKK_RSA); - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_PUBLIC_KEY); - - return attrs; -} - -static GckAttributes * -read_v2_public_key (gulong algo, - gconstpointer data, - gsize n_data) -{ - GckAttributes *attrs; - EggBuffer buffer; - gsize offset; - gchar *stype; - int alg; - - egg_buffer_init_static (&buffer, data, n_data); - offset = 0; - - /* The string algorithm */ - if (!egg_buffer_get_string (&buffer, offset, &offset, - &stype, (EggBufferAllocator)g_realloc)) - return NULL; - - alg = keytype_to_algo (stype, stype ? strlen (stype) : 0); - g_free (stype); - - if (alg != algo) { - g_message ("invalid or mis-matched algorithm in ssh public key: %s", stype); - egg_buffer_uninit (&buffer); - return NULL; - } - - switch (algo) { - case CKK_RSA: - attrs = read_v2_public_rsa (&buffer, &offset); - break; - case CKK_DSA: - attrs = read_v2_public_dsa (&buffer, &offset); - break; - default: - g_assert_not_reached (); - break; - } - - egg_buffer_uninit (&buffer); - return attrs; -} - -static GckAttributes * -decode_v2_public_key (gulong algo, - const gchar *data, - gsize n_data) -{ - GckAttributes *attrs; - gpointer decoded; - gsize n_decoded; - guint save; - gint state; - - /* Decode the base64 key */ - save = state = 0; - decoded = g_malloc (n_data * 3 / 4); - n_decoded = g_base64_decode_step ((gchar*)data, n_data, decoded, &state, &save); - - if (!n_decoded) { - g_free (decoded); - return NULL; - } - - /* Parse the actual key */ - attrs = read_v2_public_key (algo, decoded, n_decoded); - - g_free (decoded); - - return attrs; -} - -static GcrDataError -parse_v2_public_line (const gchar *line, - gsize length, - GcrOpensshPubCallback callback, - gpointer user_data) -{ - const gchar *word_options, *word_algo, *word_key; - gsize len_options, len_algo, len_key; - GckAttributes *attrs; - gchar *options; - gchar *label = NULL; - const gchar *outer = line; - gsize n_outer = length; - gulong algo; - - g_assert (line); - - /* Eat space at the front */ - skip_spaces (&line, &length); - - /* Blank line or comment */ - if (length == 0 || line[0] == '#') - return GCR_ERROR_UNRECOGNIZED; - - if (!next_word (&line, &length, &word_algo, &len_algo)) - return GCR_ERROR_UNRECOGNIZED; - - /* - * If the first word is not the algorithm, then we have options: - * - * option,option ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAI...EAz8Ji= Label here - * - * If the first word is the algorithm, then we have no options: - * - * ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAI...EAz8Ji= Label here - */ - algo = keytype_to_algo (word_algo, len_algo); - if (algo == G_MAXULONG) { - word_options = word_algo; - len_options = len_algo; - if (!next_word (&line, &length, &word_algo, &len_algo)) - return GCR_ERROR_UNRECOGNIZED; - algo = keytype_to_algo (word_algo, len_algo); - if (algo == G_MAXULONG) - return GCR_ERROR_UNRECOGNIZED; - } else { - word_options = NULL; - len_options = 0; - } - - /* Must have at least two words */ - if (!next_word (&line, &length, &word_key, &len_key)) - return GCR_ERROR_FAILURE; - - attrs = decode_v2_public_key (algo, word_key, len_key); - if (attrs == NULL) - return GCR_ERROR_FAILURE; - - if (word_options) - options = g_strndup (word_options, len_options); - else - options = NULL; - - /* The remainder of the line is the label */ - skip_spaces (&line, &length); - if (length > 0) { - label = g_strndup (line, length); - g_strstrip (label); - gck_attributes_add_string (attrs, CKA_LABEL, label); - } - - if (callback != NULL) - (callback) (attrs, label, options, outer, n_outer, user_data); - - gck_attributes_unref (attrs); - g_free (options); - g_free (label); - return GCR_SUCCESS; -} - -guint -_gcr_openssh_pub_parse (gconstpointer data, - gsize n_data, - GcrOpensshPubCallback callback, - gpointer user_data) -{ - const gchar *line; - const gchar *end; - gsize length; - gboolean last; - GcrDataError res; - guint num_parsed; - - g_return_val_if_fail (data, FALSE); - - line = data; - length = n_data; - last = FALSE; - num_parsed = 0; - - for (;;) { - end = memchr (line, '\n', length); - if (end == NULL) { - end = line + length; - last = TRUE; - } - - if (line != end) { - res = parse_v2_public_line (line, end - line, callback, user_data); - if (res == GCR_ERROR_UNRECOGNIZED) - res = parse_v1_public_line (line, end - line, callback, user_data); - if (res == GCR_SUCCESS) - num_parsed++; - } - - if (last) - break; - - end++; - length -= (end - line); - line = end; - } - - return num_parsed; -} diff --git a/gcr/gcr-openssh.h b/gcr/gcr-openssh.h deleted file mode 100644 index 2fdac2a1..00000000 --- a/gcr/gcr-openssh.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_H_INSIDE__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> can be included directly." -#endif - -#ifndef __GCR_OPENSSH_H__ -#define __GCR_OPENSSH_H__ - -#include <glib.h> - -#include <gck/gck.h> - -G_BEGIN_DECLS - -typedef void (*GcrOpensshPubCallback) (GckAttributes *attrs, - const gchar *label, - const gchar *options, - const gchar *outer, - gsize n_outer, - gpointer user_data); - -guint _gcr_openssh_pub_parse (gconstpointer data, - gsize n_data, - GcrOpensshPubCallback callback, - gpointer user_data); - -G_END_DECLS - -#endif /* __GCR_OPENSSH_H__ */ diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c deleted file mode 100644 index ffcdd091..00000000 --- a/gcr/gcr-parser.c +++ /dev/null @@ -1,2934 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gck/gck.h" - -#include "gcr-internal.h" -#include "gcr-marshal.h" -#include "gcr-oids.h" -#include "gcr-openpgp.h" -#include "gcr-openssh.h" -#include "gcr-parser.h" -#include "gcr-record.h" -#include "gcr-types.h" - -#include "egg/egg-armor.h" -#include "egg/egg-asn1x.h" -#include "egg/egg-asn1-defs.h" -#include "egg/egg-dn.h" -#include "egg/egg-openssl.h" -#include "egg/egg-secure-memory.h" -#include "egg/egg-symkey.h" - -#include <glib/gi18n-lib.h> - -#include <stdlib.h> -#include <gcrypt.h> - -/** - * SECTION:gcr-parser - * @title: GcrParser - * @short_description: Parser for certificate and key files - * - * A #GcrParser can parse various certificate and key files such as OpenSSL - * PEM files, DER encoded certifictes, PKCS\#8 keys and so on. Each various - * format is identified by a value in the #GcrDataFormat enumeration. - * - * In order to parse data, a new parser is created with gcr_parser_new() and - * then the GcrParser::authenticate and GcrParser::parsed signals should be - * connected to. Data is then fed to the parser via gcr_parser_parse_data() - * or gcr_parser_parse_stream(). - * - * During the GcrParsed::parsed signal the attributes that make up the currently - * parsed item can be retrieved using the gcr_parser_get_parsed_attributes() - * function. - */ - -/** - * GcrParser: - * - * A parser for parsing various types of files or data. - */ - -/** - * GcrParsed: - * - * A parsed item parsed by a #GcrParser. - */ - -/** - * GcrParserClass: - * @parent_class: The parent class - * @authenticate: The default handler for the authenticate signal. - * @parsed: The default handler for the parsed signal. - * - * The class for #GcrParser - */ - -/** - * GCR_DATA_ERROR: - * - * A domain for data errors with codes from #GcrDataError - */ - -/** - * GcrDataError - * @GCR_ERROR_FAILURE: Failed to parse or serialize the data - * @GCR_ERROR_UNRECOGNIZED: The data was unrecognized or unsupported - * @GCR_ERROR_CANCELLED: The operation was cancelled - * @GCR_ERROR_LOCKED: The data was encrypted or locked and could not be unlocked. - * - * Values responding to error codes for parsing and serializing data. - */ - -enum { - PROP_0, - PROP_PARSED_LABEL, - PROP_PARSED_ATTRIBUTES, - PROP_PARSED_DESCRIPTION -}; - -enum { - AUTHENTICATE, - PARSED, - LAST_SIGNAL -}; - -#define SUCCESS 0 - -static guint signals[LAST_SIGNAL] = { 0 }; - -struct _GcrParsed { - gint refs; - GckAttributes *attrs; - const gchar *description; - gchar *label; - gpointer data; - gsize n_data; - gboolean sensitive; - GDestroyNotify destroy_func; - GcrDataFormat format; - struct _GcrParsed *next; -}; - -struct _GcrParserPrivate { - GTree *specific_formats; - gboolean normal_formats; - GPtrArray *passwords; - GcrParsed *parsed; -}; - -G_DEFINE_TYPE (GcrParser, gcr_parser, G_TYPE_OBJECT); - -typedef struct { - gint ask_state; - gint seen; -} PasswordState; - -#define PASSWORD_STATE_INIT { 0, 0 } - -typedef struct _ParserFormat { - gint format_id; - gint (*function) (GcrParser *self, const guchar *data, gsize n_data); -} ParserFormat; - -/* Forward declarations */ -static const ParserFormat parser_normal[]; -static const ParserFormat parser_formats[]; -static ParserFormat* parser_format_lookup (gint format_id); - -EGG_SECURE_DECLARE (parser); - -/* ----------------------------------------------------------------------------- - * QUARK DEFINITIONS - */ - -/* - * PEM STRINGS - * The xxxxx in: ----- BEGIN xxxxx ------ - */ - -static GQuark PEM_CERTIFICATE; -static GQuark PEM_RSA_PRIVATE_KEY; -static GQuark PEM_DSA_PRIVATE_KEY; -static GQuark PEM_ANY_PRIVATE_KEY; -static GQuark PEM_ENCRYPTED_PRIVATE_KEY; -static GQuark PEM_PRIVATE_KEY; -static GQuark PEM_PKCS7; -static GQuark PEM_PKCS12; - -static GQuark ARMOR_PGP_PUBLIC_KEY_BLOCK; -static GQuark ARMOR_PGP_PRIVATE_KEY_BLOCK; - -static void -init_quarks (void) -{ - static volatile gsize quarks_inited = 0; - - _gcr_oids_init (); - - if (g_once_init_enter (&quarks_inited)) { - - #define QUARK(name, value) \ - name = g_quark_from_static_string(value) - - QUARK (PEM_CERTIFICATE, "CERTIFICATE"); - QUARK (PEM_PRIVATE_KEY, "PRIVATE KEY"); - QUARK (PEM_RSA_PRIVATE_KEY, "RSA PRIVATE KEY"); - QUARK (PEM_DSA_PRIVATE_KEY, "DSA PRIVATE KEY"); - QUARK (PEM_ANY_PRIVATE_KEY, "ANY PRIVATE KEY"); - QUARK (PEM_ENCRYPTED_PRIVATE_KEY, "ENCRYPTED PRIVATE KEY"); - QUARK (PEM_PKCS7, "PKCS7"); - QUARK (PEM_PKCS12, "PKCS12"); - QUARK (ARMOR_PGP_PRIVATE_KEY_BLOCK, "PGP PRIVATE KEY BLOCK"); - QUARK (ARMOR_PGP_PUBLIC_KEY_BLOCK, "PGP PUBLIC KEY BLOCK"); - - #undef QUARK - - g_once_init_leave (&quarks_inited, 1); - } -} - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -static void -parsed_attribute (GcrParsed *parsed, - CK_ATTRIBUTE_TYPE type, - gconstpointer data, - gsize n_data) -{ - g_assert (parsed != NULL); - g_assert (parsed->attrs != NULL); - gck_attributes_add_data (parsed->attrs, type, data, n_data); -} - -static gboolean -parsed_asn1_number (GcrParsed *parsed, - GNode *asn, - const gchar *part, - CK_ATTRIBUTE_TYPE type) -{ - const guchar *value; - gsize n_value; - - g_assert (asn); - g_assert (parsed); - - value = egg_asn1x_get_integer_as_usg (egg_asn1x_node (asn, part, NULL), &n_value); - if (value == NULL) - return FALSE; - - parsed_attribute (parsed, type, value, n_value); - return TRUE; -} - -static gboolean -parsed_asn1_element (GcrParsed *parsed, - GNode *asn, - const gchar *part, - CK_ATTRIBUTE_TYPE type) -{ - const guchar *value; - gsize n_value; - - g_assert (asn); - g_assert (parsed); - - value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, part, NULL), &n_value); - if (value == NULL) - return FALSE; - - parsed_attribute (parsed, type, value, n_value); - return TRUE; -} - -static void -parsed_ulong_attribute (GcrParsed *parsed, - CK_ATTRIBUTE_TYPE type, - gulong value) -{ - g_assert (parsed != NULL); - g_assert (parsed->attrs != NULL); - gck_attributes_add_ulong (parsed->attrs, type, value); -} - -static void -parsed_boolean_attribute (GcrParsed *parsed, - CK_ATTRIBUTE_TYPE type, - gboolean value) -{ - g_assert (parsed != NULL); - g_assert (parsed->attrs != NULL); - gck_attributes_add_boolean (parsed->attrs, type, value); -} - - -static void -parsing_block (GcrParsed *parsed, - gint format, - gconstpointer data, - gsize n_data) -{ - g_assert (parsed != NULL); - g_assert (data != NULL); - g_assert (n_data != 0); - g_assert (format); - g_assert (parsed->data == NULL); - g_assert (parsed->destroy_func == NULL); - - parsed->format = format; - parsed->data = (gpointer)data; - parsed->n_data = n_data; -} - -static void -parsed_description (GcrParsed *parsed, - CK_OBJECT_CLASS klass) -{ - g_assert (parsed != NULL); - switch (klass) { - case CKO_PRIVATE_KEY: - parsed->description = _("Private Key"); - break; - case CKO_CERTIFICATE: - parsed->description = _("Certificate"); - break; - case CKO_PUBLIC_KEY: - parsed->description = _("Public Key"); - break; - case CKO_GCR_GNUPG_RECORDS: - parsed->description = _("PGP Key"); - break; - default: - parsed->description = NULL; - break; - } -} - -static void -parsing_object (GcrParsed *parsed, - CK_OBJECT_CLASS klass) -{ - g_assert (parsed != NULL); - g_assert (parsed->attrs == NULL); - - if (parsed->sensitive) - parsed->attrs = gck_attributes_new_full ((GckAllocator)egg_secure_realloc); - else - parsed->attrs = gck_attributes_new (); - gck_attributes_add_ulong (parsed->attrs, CKA_CLASS, klass); - parsed_description (parsed, klass); -} - -static void -parsed_attributes (GcrParsed *parsed, - GckAttributes *attrs) -{ - gulong klass; - - g_assert (parsed != NULL); - g_assert (attrs != NULL); - g_assert (parsed->attrs == NULL); - - parsed->attrs = gck_attributes_ref (attrs); - if (gck_attributes_find_ulong (attrs, CKA_CLASS, &klass)) - parsed_description (parsed, klass); -} - -static void -parsed_label (GcrParsed *parsed, - const gchar *label) -{ - g_assert (parsed != NULL); - g_assert (parsed->label == NULL); - parsed->label = g_strdup (label); -} - -static GcrParsed * -push_parsed (GcrParser *self, - gboolean sensitive) -{ - GcrParsed *parsed = g_new0 (GcrParsed, 1); - parsed->refs = 0; - parsed->sensitive = sensitive; - parsed->next = self->pv->parsed; - self->pv->parsed = parsed; - return parsed; -} - -static void -pop_parsed (GcrParser *self, - GcrParsed *parsed) -{ - g_assert (parsed == self->pv->parsed); - - self->pv->parsed = parsed->next; - - gck_attributes_unref (parsed->attrs); - g_free (parsed->label); - g_free (parsed); -} - -static gint -enum_next_password (GcrParser *self, PasswordState *state, const gchar **password) -{ - gboolean result; - - /* - * Next passes we look through all the passwords that the parser - * has seen so far. This is because different parts of a encrypted - * container (such as PKCS#12) often use the same password even - * if with different algorithms. - * - * If we didn't do this and the user chooses enters a password, - * but doesn't save it, they would get prompted for the same thing - * over and over, dumb. - */ - - /* Look in our list of passwords */ - if (state->seen < self->pv->passwords->len) { - g_assert (state->seen >= 0); - *password = g_ptr_array_index (self->pv->passwords, state->seen); - ++state->seen; - return SUCCESS; - } - - /* Fire off all the parsed property signals so anyone watching can update their state */ - g_object_notify (G_OBJECT (self), "parsed-description"); - g_object_notify (G_OBJECT (self), "parsed-attributes"); - g_object_notify (G_OBJECT (self), "parsed-label"); - - g_signal_emit (self, signals[AUTHENTICATE], 0, state->ask_state, &result); - ++state->ask_state; - - if (!result) - return GCR_ERROR_CANCELLED; - - /* Return any passwords added */ - if (state->seen < self->pv->passwords->len) { - g_assert (state->seen >= 0); - *password = g_ptr_array_index (self->pv->passwords, state->seen); - ++state->seen; - return SUCCESS; - } - - return GCR_ERROR_LOCKED; -} - -static void -parsed_fire (GcrParser *self, - GcrParsed *parsed) -{ - g_assert (GCR_IS_PARSER (self)); - g_assert (parsed != NULL); - g_assert (parsed == self->pv->parsed); - - g_object_notify (G_OBJECT (self), "parsed-description"); - g_object_notify (G_OBJECT (self), "parsed-attributes"); - g_object_notify (G_OBJECT (self), "parsed-label"); - - g_signal_emit (self, signals[PARSED], 0); -} - -/* ----------------------------------------------------------------------------- - * RSA PRIVATE KEY - */ - -static gint -parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data) -{ - gint res = GCR_ERROR_UNRECOGNIZED; - GNode *asn = NULL; - gulong version; - GcrParsed *parsed; - - parsed = push_parsed (self, TRUE); - - asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPrivateKey", data, n_data); - if (!asn) - goto done; - - parsing_block (parsed, GCR_FORMAT_DER_PRIVATE_KEY_RSA, data, n_data); - parsing_object (parsed, CKO_PRIVATE_KEY); - parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_RSA); - parsed_boolean_attribute (parsed, CKA_PRIVATE, CK_TRUE); - res = GCR_ERROR_FAILURE; - - if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), &version)) - goto done; - - /* We only support simple version */ - if (version != 0) { - res = GCR_ERROR_UNRECOGNIZED; - g_message ("unsupported version of RSA key: %lu", version); - goto done; - } - - if (!parsed_asn1_number (parsed, asn, "modulus", CKA_MODULUS) || - !parsed_asn1_number (parsed, asn, "publicExponent", CKA_PUBLIC_EXPONENT) || - !parsed_asn1_number (parsed, asn, "privateExponent", CKA_PRIVATE_EXPONENT) || - !parsed_asn1_number (parsed, asn, "prime1", CKA_PRIME_1) || - !parsed_asn1_number (parsed, asn, "prime2", CKA_PRIME_2) || - !parsed_asn1_number (parsed, asn, "coefficient", CKA_COEFFICIENT)) - goto done; - - parsed_fire (self, parsed); - res = SUCCESS; - -done: - egg_asn1x_destroy (asn); - if (res == GCR_ERROR_FAILURE) - g_message ("invalid RSA key"); - - pop_parsed (self, parsed); - return res; -} - -/* ----------------------------------------------------------------------------- - * DSA PRIVATE KEY - */ - -static gint -parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data) -{ - gint ret = GCR_ERROR_UNRECOGNIZED; - GNode *asn = NULL; - GcrParsed *parsed; - - parsed = push_parsed (self, TRUE); - - asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivateKey", data, n_data); - if (!asn) - goto done; - - parsing_block (parsed, GCR_FORMAT_DER_PRIVATE_KEY_DSA, data, n_data); - parsing_object (parsed, CKO_PRIVATE_KEY); - parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_DSA); - parsed_boolean_attribute (parsed, CKA_PRIVATE, CK_TRUE); - ret = GCR_ERROR_FAILURE; - - if (!parsed_asn1_number (parsed, asn, "p", CKA_PRIME) || - !parsed_asn1_number (parsed, asn, "q", CKA_SUBPRIME) || - !parsed_asn1_number (parsed, asn, "g", CKA_BASE) || - !parsed_asn1_number (parsed, asn, "priv", CKA_VALUE)) - goto done; - - parsed_fire (self, parsed); - ret = SUCCESS; - -done: - egg_asn1x_destroy (asn); - if (ret == GCR_ERROR_FAILURE) - g_message ("invalid DSA key"); - - pop_parsed (self, parsed); - return ret; -} - -static gint -parse_der_private_key_dsa_parts (GcrParser *self, const guchar *keydata, gsize n_keydata, - const guchar *params, gsize n_params) -{ - gint ret = GCR_ERROR_UNRECOGNIZED; - GNode *asn_params = NULL; - GNode *asn_key = NULL; - GcrParsed *parsed; - - parsed = push_parsed (self, TRUE); - - asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params, n_params); - asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivatePart", keydata, n_keydata); - if (!asn_params || !asn_key) - goto done; - - parsing_object (parsed, CKO_PRIVATE_KEY); - parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_DSA); - parsed_boolean_attribute (parsed, CKA_PRIVATE, CK_TRUE); - ret = GCR_ERROR_FAILURE; - - if (!parsed_asn1_number (parsed, asn_params, "p", CKA_PRIME) || - !parsed_asn1_number (parsed, asn_params, "q", CKA_SUBPRIME) || - !parsed_asn1_number (parsed, asn_params, "g", CKA_BASE) || - !parsed_asn1_number (parsed, asn_key, NULL, CKA_VALUE)) - goto done; - - parsed_fire (self, parsed); - ret = SUCCESS; - -done: - egg_asn1x_destroy (asn_key); - egg_asn1x_destroy (asn_params); - if (ret == GCR_ERROR_FAILURE) - g_message ("invalid DSA key"); - - pop_parsed (self, parsed); - return ret; -} - -/* ----------------------------------------------------------------------------- - * PRIVATE KEY - */ - -static gint -parse_der_private_key (GcrParser *self, const guchar *data, gsize n_data) -{ - gint res; - - res = parse_der_private_key_rsa (self, data, n_data); - if (res == GCR_ERROR_UNRECOGNIZED) - res = parse_der_private_key_dsa (self, data, n_data); - - return res; -} - -/* ----------------------------------------------------------------------------- - * PKCS8 - */ - -static gint -parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data) -{ - gint ret; - CK_KEY_TYPE key_type; - GQuark key_algo; - const guchar *keydata; - gsize n_keydata; - const guchar *params; - gsize n_params; - GNode *asn = NULL; - GcrParsed *parsed; - - parsed = push_parsed (self, TRUE); - ret = GCR_ERROR_UNRECOGNIZED; - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-PrivateKeyInfo", data, n_data); - if (!asn) - goto done; - - parsing_block (parsed, GCR_FORMAT_DER_PKCS8_PLAIN, data, n_data); - ret = GCR_ERROR_FAILURE; - key_type = GCK_INVALID; - - key_algo = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "privateKeyAlgorithm", "algorithm", NULL)); - if (!key_algo) - goto done; - else if (key_algo == GCR_OID_PKIX1_RSA) - key_type = CKK_RSA; - else if (key_algo == GCR_OID_PKIX1_DSA) - key_type = CKK_DSA; - - if (key_type == GCK_INVALID) { - ret = GCR_ERROR_UNRECOGNIZED; - goto done; - } - - keydata = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "privateKey", NULL), &n_keydata); - if (!keydata) - goto done; - - params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL), &n_params); - - ret = SUCCESS; - -done: - if (ret == SUCCESS) { - switch (key_type) { - case CKK_RSA: - ret = parse_der_private_key_rsa (self, keydata, n_keydata); - break; - case CKK_DSA: - /* Try the normal sane format */ - ret = parse_der_private_key_dsa (self, keydata, n_keydata); - - /* Otherwise try the two part format that everyone seems to like */ - if (ret == GCR_ERROR_UNRECOGNIZED && params && n_params) - ret = parse_der_private_key_dsa_parts (self, keydata, n_keydata, - params, n_params); - break; - default: - g_message ("invalid or unsupported key type in PKCS#8 key"); - ret = GCR_ERROR_UNRECOGNIZED; - break; - }; - - } else if (ret == GCR_ERROR_FAILURE) { - g_message ("invalid PKCS#8 key"); - } - - egg_asn1x_destroy (asn); - pop_parsed (self, parsed); - return ret; -} - -static gint -parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data) -{ - PasswordState pstate = PASSWORD_STATE_INIT; - GNode *asn = NULL; - gcry_cipher_hd_t cih = NULL; - gcry_error_t gcry; - gint ret, r; - GQuark scheme; - guchar *crypted = NULL; - const guchar *params; - gsize n_crypted, n_params; - const gchar *password; - GcrParsed *parsed; - gint l; - - parsed = push_parsed (self, FALSE); - ret = GCR_ERROR_UNRECOGNIZED; - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo", data, n_data); - if (!asn) - goto done; - - parsing_block (parsed, GCR_FORMAT_DER_PKCS8_ENCRYPTED, data, n_data); - ret = GCR_ERROR_FAILURE; - - /* Figure out the type of encryption */ - scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL)); - if (!scheme) - goto done; - - params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), &n_params); - - /* Loop to try different passwords */ - for (;;) { - - g_assert (cih == NULL); - - r = enum_next_password (self, &pstate, &password); - if (r != SUCCESS) { - ret = r; - break; - } - - /* Parse the encryption stuff into a cipher. */ - if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih)) - break; - - crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedData", NULL), egg_secure_realloc, &n_crypted); - if (!crypted) - break; - - gcry = gcry_cipher_decrypt (cih, crypted, n_crypted, NULL, 0); - gcry_cipher_close (cih); - cih = NULL; - - if (gcry != 0) { - g_warning ("couldn't decrypt pkcs8 data: %s", gcry_strerror (gcry)); - break; - } - - /* Unpad the DER data */ - l = egg_asn1x_element_length (crypted, n_crypted); - if (l > 0) - n_crypted = l; - - /* Try to parse the resulting key */ - r = parse_der_pkcs8_plain (self, crypted, n_crypted); - egg_secure_free (crypted); - crypted = NULL; - - if (r != GCR_ERROR_UNRECOGNIZED) { - ret = r; - break; - } - - /* We assume unrecognized data, is a bad encryption key */ - } - -done: - if (cih) - gcry_cipher_close (cih); - egg_asn1x_destroy (asn); - egg_secure_free (crypted); - - pop_parsed (self, parsed); - return ret; -} - -static gint -parse_der_pkcs8 (GcrParser *self, const guchar *data, gsize n_data) -{ - gint ret; - - ret = parse_der_pkcs8_plain (self, data, n_data); - if (ret == GCR_ERROR_UNRECOGNIZED) - ret = parse_der_pkcs8_encrypted (self, data, n_data); - - return ret; -} - -/* ----------------------------------------------------------------------------- - * CERTIFICATE - */ - -static gint -parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data) -{ - gchar *name = NULL; - GcrParsed *parsed; - GNode *node; - GNode *asn; - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data); - if (asn == NULL) - return GCR_ERROR_UNRECOGNIZED; - - parsed = push_parsed (self, FALSE); - - parsing_block (parsed, GCR_FORMAT_DER_CERTIFICATE_X509, data, n_data); - parsing_object (parsed, CKO_CERTIFICATE); - parsed_ulong_attribute (parsed, CKA_CERTIFICATE_TYPE, CKC_X_509); - - node = egg_asn1x_node (asn, "tbsCertificate", NULL); - g_return_val_if_fail (node != NULL, GCR_ERROR_FAILURE); - - if (gcr_parser_get_parsed_label (self) == NULL) - name = egg_dn_read_part (egg_asn1x_node (node, "subject", "rdnSequence", NULL), "CN"); - - if (name != NULL) { - parsed_label (parsed, name); - g_free (name); - } - - parsed_attribute (parsed, CKA_VALUE, data, n_data); - parsed_asn1_element (parsed, node, "subject", CKA_SUBJECT); - parsed_asn1_element (parsed, node, "issuer", CKA_ISSUER); - parsed_asn1_number (parsed, node, "serialNumber", CKA_SERIAL_NUMBER); - parsed_fire (self, parsed); - - egg_asn1x_destroy (asn); - - pop_parsed (self, parsed); - return SUCCESS; -} - -/* ----------------------------------------------------------------------------- - * PKCS7 - */ - -static gint -handle_pkcs7_signed_data (GcrParser *self, const guchar *data, gsize n_data) -{ - GNode *asn = NULL; - GNode *node; - gint ret; - const guchar *certificate; - gsize n_certificate; - int i; - - ret = GCR_ERROR_UNRECOGNIZED; - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-SignedData", data, n_data); - if (!asn) - goto done; - - ret = GCR_ERROR_FAILURE; - - for (i = 0; TRUE; ++i) { - - node = egg_asn1x_node (asn, "certificates", i + 1, NULL); - - /* No more certificates? */ - if (node == NULL) - break; - - certificate = egg_asn1x_get_raw_element (node, &n_certificate); - - ret = parse_der_certificate (self, certificate, n_certificate); - if (ret != SUCCESS) - goto done; - } - - /* TODO: Parse out all the CRLs */ - - ret = SUCCESS; - -done: - egg_asn1x_destroy (asn); - return ret; -} - -static gint -parse_der_pkcs7 (GcrParser *self, const guchar *data, gsize n_data) -{ - GNode *asn = NULL; - GNode *node; - gint ret; - const guchar* content = NULL; - gsize n_content; - GQuark oid; - GcrParsed *parsed; - - parsed = push_parsed (self, FALSE); - ret = GCR_ERROR_UNRECOGNIZED; - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-ContentInfo", data, n_data); - if (!asn) - goto done; - - parsing_block (parsed, GCR_FORMAT_DER_PKCS7, data, n_data); - ret = GCR_ERROR_FAILURE; - - node = egg_asn1x_node (asn, "contentType", NULL); - if (!node) - goto done; - - oid = egg_asn1x_get_oid_as_quark (node); - g_return_val_if_fail (oid, GCR_ERROR_FAILURE); - - /* Outer most one must just be plain data */ - if (oid != GCR_OID_PKCS7_SIGNED_DATA) { - g_message ("unsupported outer content type in pkcs7: %s", g_quark_to_string (oid)); - goto done; - } - - content = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "content", NULL), &n_content); - if (!content) - goto done; - - ret = handle_pkcs7_signed_data (self, content, n_content); - -done: - egg_asn1x_destroy (asn); - pop_parsed (self, parsed); - return ret; -} - -/* ----------------------------------------------------------------------------- - * PKCS12 - */ - -static GNode * -decode_pkcs12_asn1_accepting_invalid_crap (const ASN1_ARRAY_TYPE *defs, - const gchar *identifier, - gconstpointer data, - gsize n_data) -{ - GNode *asn; - - /* - * Because PKCS#12 files, the bags specifically, are notorious for - * being crappily constructed and are often break rules such as DER - * sorting order etc.. we parse the DER in a non-strict fashion. - * - * The rules in DER are designed for X.509 certificates, so there is - * only one way to represent a given certificate (although they fail - * at that as well). But with PKCS#12 we don't have such high - * requirements, and we can slack off on our validation. - */ - - asn = egg_asn1x_create (defs, identifier); - g_return_val_if_fail (asn != NULL, NULL); - - /* Passing FALSE as the strictness argument */ - if (!egg_asn1x_decode_no_validate (asn, data, n_data) || - !egg_asn1x_validate (asn, FALSE)) { - egg_asn1x_destroy (asn); - asn = NULL; - } - - return asn; -} - -static gint -handle_pkcs12_cert_bag (GcrParser *self, const guchar *data, gsize n_data) -{ - GNode *asn = NULL; - GNode *asn_content = NULL; - guchar *certificate = NULL; - const guchar *element; - gsize n_certificate, n_element; - gint ret; - - ret = GCR_ERROR_UNRECOGNIZED; - asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, - "pkcs-12-CertBag", - data, n_data); - if (!asn) - goto done; - - ret = GCR_ERROR_FAILURE; - - element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "certValue", NULL), &n_element); - if (!element) - goto done; - - asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", element, n_element); - if (!asn_content) - goto done; - - certificate = egg_asn1x_get_string_as_raw (asn_content, NULL, &n_certificate); - if (!certificate) - goto done; - - ret = parse_der_certificate (self, certificate, n_certificate); - -done: - egg_asn1x_destroy (asn_content); - egg_asn1x_destroy (asn); - g_free (certificate); - return ret; -} - -static gchar * -parse_pkcs12_bag_friendly_name (GNode *asn) -{ - guint count, i; - GQuark oid; - GNode *node; - gconstpointer element; - gsize n_element; - GNode *asn_str; - gchar *result; - - if (asn == NULL) - return NULL; - - count = egg_asn1x_count (asn); - for (i = 1; i <= count; i++) { - oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, i, "type", NULL)); - if (oid == GCR_OID_PKCS9_ATTRIBUTE_FRIENDLY) { - node = egg_asn1x_node (asn, i, "values", 1, NULL); - if (node != NULL) { - element = egg_asn1x_get_raw_element (node, &n_element); - asn_str = egg_asn1x_create_and_decode (pkix_asn1_tab, "BMPString", - element, n_element); - if (asn_str) { - result = egg_asn1x_get_bmpstring_as_utf8 (asn_str); - egg_asn1x_destroy (asn_str); - return result; - } - } - } - } - - return NULL; -} - -static gint -handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data) -{ - GNode *asn = NULL; - gint ret, r; - guint count = 0; - GQuark oid; - const guchar *element; - gchar *friendly; - gsize n_element; - guint i; - GcrParsed *parsed; - - ret = GCR_ERROR_UNRECOGNIZED; - - asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, - "pkcs-12-SafeContents", - data, n_data); - if (!asn) - goto done; - - ret = GCR_ERROR_FAILURE; - - /* Get the number of elements in this bag */ - count = egg_asn1x_count (asn); - - /* - * Now inside each bag are multiple elements. Who comes up - * with this stuff? - */ - for (i = 1; i <= count; i++) { - - oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, i, "bagId", NULL)); - if (!oid) - goto done; - - element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, i, "bagValue", NULL), &n_element); - if (!element) - goto done; - - parsed = push_parsed (self, FALSE); - - friendly = parse_pkcs12_bag_friendly_name (egg_asn1x_node (asn, i, "bagAttributes", NULL)); - if (friendly != NULL) - parsed_label (parsed, friendly); - - /* A normal unencrypted key */ - if (oid == GCR_OID_PKCS12_BAG_PKCS8_KEY) { - r = parse_der_pkcs8_plain (self, element, n_element); - - /* A properly encrypted key */ - } else if (oid == GCR_OID_PKCS12_BAG_PKCS8_ENCRYPTED_KEY) { - r = parse_der_pkcs8_encrypted (self, element, n_element); - - /* A certificate */ - } else if (oid == GCR_OID_PKCS12_BAG_CERTIFICATE) { - r = handle_pkcs12_cert_bag (self, element, n_element); - - /* TODO: GCR_OID_PKCS12_BAG_CRL */ - } else { - r = GCR_ERROR_UNRECOGNIZED; - } - - pop_parsed (self, parsed); - - if (r == GCR_ERROR_FAILURE || - r == GCR_ERROR_CANCELLED || - r == GCR_ERROR_LOCKED) { - ret = r; - goto done; - } - } - - ret = SUCCESS; - -done: - egg_asn1x_destroy (asn); - return ret; -} - -static gint -handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data) -{ - PasswordState pstate = PASSWORD_STATE_INIT; - GNode *asn = NULL; - gcry_cipher_hd_t cih = NULL; - gcry_error_t gcry; - guchar *crypted = NULL; - const guchar *params; - gsize n_params, n_crypted; - const gchar *password; - GQuark scheme; - gint ret, r; - gint l; - - ret = GCR_ERROR_UNRECOGNIZED; - - asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, - "pkcs-7-EncryptedData", - data, n_data); - if (!asn) - goto done; - - ret = GCR_ERROR_FAILURE; - - /* Check the encryption schema OID */ - scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "algorithm", NULL)); - if (!scheme) - goto done; - - params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "parameters", NULL), &n_params); - if (!params) - goto done; - - /* Loop to try different passwords */ - for (;;) { - - g_assert (cih == NULL); - - r = enum_next_password (self, &pstate, &password); - if (r != SUCCESS) { - ret = r; - goto done; - } - - /* Parse the encryption stuff into a cipher. */ - if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih)) { - ret = GCR_ERROR_FAILURE; - goto done; - } - - crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedContentInfo", "encryptedContent", NULL), - egg_secure_realloc, &n_crypted); - if (!crypted) - goto done; - - gcry = gcry_cipher_decrypt (cih, crypted, n_crypted, NULL, 0); - gcry_cipher_close (cih); - cih = NULL; - - if (gcry != 0) { - g_warning ("couldn't decrypt pkcs7 data: %s", gcry_strerror (gcry)); - goto done; - } - - /* Unpad the DER data */ - l = egg_asn1x_element_length (crypted, n_crypted); - if (l > 0) - n_crypted = l; - - /* Try to parse the resulting key */ - r = handle_pkcs12_bag (self, crypted, n_crypted); - egg_secure_free (crypted); - crypted = NULL; - - if (r != GCR_ERROR_UNRECOGNIZED) { - ret = r; - break; - } - - /* We assume unrecognized data is a bad encryption key */ - } - -done: - if (cih) - gcry_cipher_close (cih); - egg_asn1x_destroy (asn); - egg_secure_free (crypted); - return ret; -} - -static gint -handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data) -{ - GNode *asn = NULL; - GNode *asn_content = NULL; - gint ret, r; - const guchar *bag; - guchar *content = NULL; - gsize n_bag, n_content; - GQuark oid; - guint i; - GNode *node; - - ret = GCR_ERROR_UNRECOGNIZED; - - asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, - "pkcs-12-AuthenticatedSafe", - data, n_data); - if (!asn) - goto done; - - ret = GCR_ERROR_FAILURE; - - /* - * Inside each PKCS12 safe there are multiple bags. - */ - for (i = 0; TRUE; ++i) { - node = egg_asn1x_node (asn, i + 1, "contentType", NULL); - - /* All done? no more bags */ - if (!node) - break; - - oid = egg_asn1x_get_oid_as_quark (node); - - node = egg_asn1x_node (asn, i + 1, "content", NULL); - if (!node) - goto done; - - bag = egg_asn1x_get_raw_element (node, &n_bag); - g_return_val_if_fail (bag, ret); - - /* A non encrypted bag, just parse */ - if (oid == GCR_OID_PKCS7_DATA) { - - egg_asn1x_destroy (asn_content); - asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, - "pkcs-7-Data", - bag, n_bag); - if (!asn_content) - goto done; - - g_free (content); - content = egg_asn1x_get_string_as_raw (asn_content, NULL, &n_content); - if (!content) - goto done; - - r = handle_pkcs12_bag (self, content, n_content); - - /* Encrypted data first needs decryption */ - } else if (oid == GCR_OID_PKCS7_ENCRYPTED_DATA) { - r = handle_pkcs12_encrypted_bag (self, bag, n_bag); - - /* Hmmmm, not sure what this is */ - } else { - g_warning ("unrecognized type of safe content in pkcs12: %s", g_quark_to_string (oid)); - r = GCR_ERROR_UNRECOGNIZED; - } - - if (r == GCR_ERROR_FAILURE || - r == GCR_ERROR_CANCELLED || - r == GCR_ERROR_LOCKED) { - ret = r; - goto done; - } - } - - ret = SUCCESS; - -done: - egg_asn1x_destroy (asn); - egg_asn1x_destroy (asn_content); - g_free (content); - return ret; -} - -static gint -verify_pkcs12_safe (GcrParser *self, - GNode *asn, - gconstpointer content, - gsize n_content) -{ - PasswordState pstate = PASSWORD_STATE_INIT; - const gchar *password; - gcry_md_hd_t mdh = NULL; - const guchar *mac_digest; - gsize mac_len; - guchar *digest = NULL; - gsize n_digest; - GQuark algorithm; - GNode *mac_data; - gconstpointer params; - gsize n_params; - int ret, r; - - ret = GCR_ERROR_FAILURE; - - /* - * The MAC is optional (and outside the encryption no less). I wonder - * what the designers (ha) of PKCS#12 were trying to achieve - */ - - mac_data = egg_asn1x_node (asn, "macData", NULL); - if (mac_data == NULL) - return SUCCESS; - - algorithm = egg_asn1x_get_oid_as_quark (egg_asn1x_node (mac_data, "mac", - "digestAlgorithm", "algorithm", NULL)); - if (!algorithm) - goto done; - - params = egg_asn1x_get_raw_element (mac_data, &n_params); - if (!params) - goto done; - - digest = egg_asn1x_get_string_as_raw (egg_asn1x_node (mac_data, "mac", "digest", NULL), NULL, &n_digest); - if (!digest) - goto done; - - /* Loop to try different passwords */ - for (;;) { - g_assert (mdh == NULL); - - r = enum_next_password (self, &pstate, &password); - if (r != SUCCESS) { - ret = r; - goto done; - } - - /* Parse the encryption stuff into a cipher. */ - if (!egg_symkey_read_mac (algorithm, password, -1, params, n_params, - &mdh, &mac_len)) { - ret = GCR_ERROR_FAILURE; - goto done; - } - - /* If not the right length, then that's really broken */ - if (mac_len != n_digest) { - r = GCR_ERROR_FAILURE; - - } else { - gcry_md_write (mdh, content, n_content); - mac_digest = gcry_md_read (mdh, 0); - g_return_val_if_fail (mac_digest, GCR_ERROR_FAILURE); - r = memcmp (mac_digest, digest, n_digest) == 0 ? SUCCESS : GCR_ERROR_LOCKED; - } - - gcry_md_close (mdh); - mdh = NULL; - - if (r != GCR_ERROR_LOCKED) { - ret = r; - break; - } - } - -done: - if (mdh) - gcry_md_close (mdh); - g_free (digest); - return ret; - -} - -static gint -parse_der_pkcs12 (GcrParser *self, const guchar *data, gsize n_data) -{ - GNode *asn = NULL; - GNode *asn_content = NULL; - gint ret; - const guchar* element = NULL; - guchar *content = NULL; - gsize n_element, n_content; - GQuark oid; - GcrParsed *parsed; - - parsed = push_parsed (self, FALSE); - ret = GCR_ERROR_UNRECOGNIZED; - - asn = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-12-PFX", - data, n_data); - if (!asn) - goto done; - - parsing_block (parsed, GCR_FORMAT_DER_PKCS12, data, n_data); - - oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "authSafe", "contentType", NULL)); - if (!oid) - goto done; - - /* Outer most one must just be plain data */ - if (oid != GCR_OID_PKCS7_DATA) { - g_message ("unsupported safe content type in pkcs12: %s", g_quark_to_string (oid)); - goto done; - } - - element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "authSafe", "content", NULL), &n_element); - if (!element) - goto done; - - asn_content = decode_pkcs12_asn1_accepting_invalid_crap (pkix_asn1_tab, "pkcs-7-Data", - element, n_element); - if (!asn_content) - goto done; - - content = egg_asn1x_get_string_as_raw (asn_content, g_realloc, &n_content); - if (!content) - goto done; - - ret = verify_pkcs12_safe (self, asn, content, n_content); - if (ret == SUCCESS) - ret = handle_pkcs12_safe (self, content, n_content); - -done: - g_free (content); - egg_asn1x_destroy (asn_content); - egg_asn1x_destroy (asn); - pop_parsed (self, parsed); - return ret; -} - - -/* ----------------------------------------------------------------------------- - * OPENPGP - */ - -static void -on_openpgp_packet (GPtrArray *records, - const guchar *outer, - gsize n_outer, - gpointer user_data) -{ - GcrParser *self = GCR_PARSER (user_data); - GcrParsed *parsed; - gchar *string; - - /* - * If it's an openpgp packet that doesn't contain a key, then - * just ignore it here. - */ - if (records->len == 0) - return; - - parsed = push_parsed (self, FALSE); - - /* All we can do is the packet bounds */ - parsing_block (parsed, GCR_FORMAT_OPENPGP_PACKET, outer, n_outer); - parsing_object (parsed, CKO_GCR_GNUPG_RECORDS); - string = _gcr_records_format (records); - parsed_attribute (parsed, CKA_VALUE, string, strlen (string)); - parsed_fire (self, parsed); - pop_parsed (self, parsed); - - g_free (string); -} - -static gint -parse_openpgp_packets (GcrParser *self, - const guchar *data, - gsize n_data) -{ - gint num_parsed; - - num_parsed = _gcr_openpgp_parse (data, n_data, - GCR_OPENPGP_PARSE_KEYS | - GCR_OPENPGP_PARSE_ATTRIBUTES | - GCR_OPENPGP_PARSE_SIGNATURES, - on_openpgp_packet, self); - - if (num_parsed == 0) - return GCR_ERROR_UNRECOGNIZED; - return SUCCESS; -} - -/* ----------------------------------------------------------------------------- - * ARMOR PARSING - */ - -static gboolean -formats_for_armor_type (GQuark armor_type, - gint *inner_format, - gint *outer_format) -{ - gint dummy; - if (!inner_format) - inner_format = &dummy; - if (!outer_format) - outer_format = &dummy; - - if (armor_type == PEM_RSA_PRIVATE_KEY) { - *inner_format = GCR_FORMAT_DER_PRIVATE_KEY_RSA; - *outer_format = GCR_FORMAT_PEM_PRIVATE_KEY_RSA; - } else if (armor_type == PEM_DSA_PRIVATE_KEY) { - *inner_format = GCR_FORMAT_DER_PRIVATE_KEY_DSA; - *outer_format = GCR_FORMAT_PEM_PRIVATE_KEY_DSA; - } else if (armor_type == PEM_ANY_PRIVATE_KEY) { - *inner_format = GCR_FORMAT_DER_PRIVATE_KEY; - *outer_format = GCR_FORMAT_PEM_PRIVATE_KEY; - } else if (armor_type == PEM_PRIVATE_KEY) { - *inner_format = GCR_FORMAT_DER_PKCS8_PLAIN; - *outer_format = GCR_FORMAT_PEM_PKCS8_PLAIN; - } else if (armor_type == PEM_ENCRYPTED_PRIVATE_KEY) { - *inner_format = GCR_FORMAT_DER_PKCS8_ENCRYPTED; - *outer_format = GCR_FORMAT_PEM_PKCS8_ENCRYPTED; - } else if (armor_type == PEM_CERTIFICATE) { - *inner_format = GCR_FORMAT_DER_CERTIFICATE_X509; - *outer_format = GCR_FORMAT_PEM_CERTIFICATE_X509; - } else if (armor_type == PEM_PKCS7) { - *inner_format = GCR_FORMAT_DER_PKCS7; - *outer_format = GCR_FORMAT_PEM_PKCS7; - } else if (armor_type == PEM_PKCS12) { - *inner_format = GCR_FORMAT_DER_PKCS12; - *outer_format = GCR_FORMAT_PEM_PKCS12; - } else if (armor_type == ARMOR_PGP_PRIVATE_KEY_BLOCK) { - *inner_format = GCR_FORMAT_OPENPGP_PACKET; - *outer_format = GCR_FORMAT_OPENPGP_ARMOR; - } else if (armor_type == ARMOR_PGP_PUBLIC_KEY_BLOCK) { - *inner_format = GCR_FORMAT_OPENPGP_PACKET; - *outer_format = GCR_FORMAT_OPENPGP_ARMOR; - } else { - return FALSE; - } - - return TRUE; -} - -static gint -handle_plain_pem (GcrParser *self, - gint format_id, - gint want_format, - const guchar *data, - gsize n_data) -{ - ParserFormat *format; - - if (want_format != 0 && want_format != format_id) - return GCR_ERROR_UNRECOGNIZED; - - format = parser_format_lookup (format_id); - if (format == NULL) - return GCR_ERROR_UNRECOGNIZED; - - return (format->function) (self, data, n_data); -} - -static gint -handle_encrypted_pem (GcrParser *self, - gint format_id, - gint want_format, - GHashTable *headers, - const guchar *data, - gsize n_data) -{ - PasswordState pstate = PASSWORD_STATE_INIT; - const gchar *password; - guchar *decrypted; - gsize n_decrypted; - const gchar *val; - gboolean ret; - gint res; - gint l; - - g_assert (GCR_IS_PARSER (self)); - g_assert (headers); - - val = g_hash_table_lookup (headers, "DEK-Info"); - if (!val) { - g_message ("missing encryption header"); - return GCR_ERROR_FAILURE; - } - - res = GCR_ERROR_FAILURE; - for (;;) { - - res = enum_next_password (self, &pstate, &password); - if (res != SUCCESS) - break; - - decrypted = NULL; - n_decrypted = 0; - - /* Decrypt, this will result in garble if invalid password */ - ret = egg_openssl_decrypt_block (val, password, -1, data, n_data, - &decrypted, &n_decrypted); - if (!ret) { - res = GCR_ERROR_FAILURE; - break; - } - - g_assert (decrypted); - - /* Unpad the DER data */ - l = egg_asn1x_element_length (decrypted, n_decrypted); - if (l > 0) - n_decrypted = l; - - /* Try to parse */ - res = handle_plain_pem (self, format_id, want_format, - decrypted, n_decrypted); - egg_secure_free (decrypted); - - /* Unrecognized is a bad password */ - if (res != GCR_ERROR_UNRECOGNIZED) - break; - } - - return res; -} - -typedef struct { - GcrParser *parser; - gint result; - gint want_format; -} HandlePemArgs; - -static void -handle_pem_data (GQuark type, - const guchar *data, - gsize n_data, - const gchar *outer, - gsize n_outer, - GHashTable *headers, - gpointer user_data) -{ - HandlePemArgs *args = (HandlePemArgs*)user_data; - gint res = GCR_ERROR_FAILURE; - gboolean encrypted = FALSE; - const gchar *val; - gint inner_format; - gint outer_format; - GcrParsed *parsed; - - /* Something already failed to parse */ - if (args->result == GCR_ERROR_FAILURE) - return; - - if (!formats_for_armor_type (type, &inner_format, &outer_format)) - return; - - parsed = push_parsed (args->parser, FALSE); - - /* Fill in information necessary for prompting */ - parsing_block (parsed, outer_format, outer, n_outer); - - /* See if it's encrypted PEM all openssl like*/ - if (headers) { - val = g_hash_table_lookup (headers, "Proc-Type"); - if (val && strcmp (val, "4,ENCRYPTED") == 0) - encrypted = TRUE; - } - - if (encrypted) - res = handle_encrypted_pem (args->parser, inner_format, - args->want_format, headers, - data, n_data); - else - res = handle_plain_pem (args->parser, inner_format, - args->want_format, data, n_data); - - pop_parsed (args->parser, parsed); - - if (res != GCR_ERROR_UNRECOGNIZED) { - if (args->result == GCR_ERROR_UNRECOGNIZED) - args->result = res; - else if (res > args->result) - args->result = res; - } -} - -static gint -handle_pem_format (GcrParser *self, gint subformat, const guchar *data, gsize n_data) -{ - HandlePemArgs ctx = { self, GCR_ERROR_UNRECOGNIZED, subformat }; - guint found; - - if (n_data == 0) - return GCR_ERROR_UNRECOGNIZED; - - found = egg_armor_parse (data, n_data, handle_pem_data, &ctx); - - if (found == 0) - return GCR_ERROR_UNRECOGNIZED; - - return ctx.result; -} - - -static gint -parse_pem (GcrParser *self, const guchar *data, gsize n_data) -{ - return handle_pem_format (self, 0, data, n_data); -} - -static gint -parse_pem_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data) -{ - return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_RSA, data, n_data); -} - -static gint -parse_pem_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data) -{ - return handle_pem_format (self, GCR_FORMAT_DER_PRIVATE_KEY_DSA, data, n_data); -} - -static gint -parse_pem_certificate (GcrParser *self, const guchar *data, gsize n_data) -{ - return handle_pem_format (self, GCR_FORMAT_DER_CERTIFICATE_X509, data, n_data); -} - -static gint -parse_pem_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data) -{ - return handle_pem_format (self, GCR_FORMAT_DER_PKCS8_PLAIN, data, n_data); -} - -static gint -parse_pem_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data) -{ - return handle_pem_format (self, GCR_FORMAT_DER_PKCS8_ENCRYPTED, data, n_data); -} - -static gint -parse_pem_pkcs7 (GcrParser *self, const guchar *data, gsize n_data) -{ - return handle_pem_format (self, GCR_FORMAT_DER_PKCS7, data, n_data); -} - -static gint -parse_pem_pkcs12 (GcrParser *self, const guchar *data, gsize n_data) -{ - return handle_pem_format (self, GCR_FORMAT_DER_PKCS12, data, n_data); -} - -static gint -parse_openpgp_armor (GcrParser *self, - const guchar *data, - gsize n_data) -{ - return handle_pem_format (self, GCR_FORMAT_OPENPGP_PACKET, data, n_data); -} - -/* ----------------------------------------------------------------------------- - * OPENSSH - */ - -static void -on_openssh_public_key_parsed (GckAttributes *attrs, - const gchar *label, - const gchar *options, - const gchar *outer, - gsize n_outer, - gpointer user_data) -{ - GcrParser *self = GCR_PARSER (user_data); - GcrParsed *parsed; - - parsed = push_parsed (self, FALSE); - parsing_block (parsed, GCR_FORMAT_OPENSSH_PUBLIC, outer, n_outer); - parsed_attributes (parsed, attrs); - parsed_label (parsed, label); - parsed_fire (self, parsed); - pop_parsed (self, parsed); -} - -static gint -parse_openssh_public (GcrParser *self, - const guchar *data, - gsize n_data) -{ - guint num_parsed; - - num_parsed = _gcr_openssh_pub_parse (data, n_data, - on_openssh_public_key_parsed, self); - - if (num_parsed == 0) - return GCR_ERROR_UNRECOGNIZED; - return SUCCESS; -} - -/* ----------------------------------------------------------------------------- - * FORMATS - */ - -/** - * GcrDataFormat: - * @GCR_FORMAT_ALL: Represents all the formats, when enabling or disabling - * @GCR_FORMAT_INVALID: Not a valid format - * @GCR_FORMAT_DER_PRIVATE_KEY: DER encoded private key - * @GCR_FORMAT_DER_PRIVATE_KEY_RSA: DER encoded RSA private key - * @GCR_FORMAT_DER_PRIVATE_KEY_DSA: DER encoded DSA private key - * @GCR_FORMAT_DER_CERTIFICATE_X509: DER encoded X.509 certificate - * @GCR_FORMAT_DER_PKCS7: DER encoded PKCS\#7 container file which can contain certificates - * @GCR_FORMAT_DER_PKCS8: DER encoded PKCS\#8 file which can contain a key - * @GCR_FORMAT_DER_PKCS8_PLAIN: Unencrypted DER encoded PKCS\#8 file which can contain a key - * @GCR_FORMAT_DER_PKCS8_ENCRYPTED: Encrypted DER encoded PKCS\#8 file which can contain a key - * @GCR_FORMAT_DER_PKCS12: DER encoded PKCS\#12 file which can contain certificates and/or keys - * @GCR_FORMAT_OPENSSH_PUBLIC: OpenSSH v1 or v2 public key - * @GCR_FORMAT_OPENPGP_PACKET: OpenPGP key packet(s) - * @GCR_FORMAT_OPENPGP_ARMOR: OpenPGP public or private key armor encoded data - * @GCR_FORMAT_PEM: An OpenSSL style PEM file with unspecified contents - * @GCR_FORMAT_PEM_PRIVATE_KEY: An OpenSSL style PEM file with a private key - * @GCR_FORMAT_PEM_PRIVATE_KEY_RSA: An OpenSSL style PEM file with a private RSA key - * @GCR_FORMAT_PEM_PRIVATE_KEY_DSA: An OpenSSL style PEM file with a private DSA key - * @GCR_FORMAT_PEM_CERTIFICATE_X509: An OpenSSL style PEM file with an X.509 certificate - * @GCR_FORMAT_PEM_PKCS7: An OpenSSL style PEM file containing PKCS\#7 - * @GCR_FORMAT_PEM_PKCS8_PLAIN: Unencrypted OpenSSL style PEM file containing PKCS\#8 - * @GCR_FORMAT_PEM_PKCS8_ENCRYPTED: Encrypted OpenSSL style PEM file containing PKCS\#8 - * @GCR_FORMAT_PEM_PKCS12: An OpenSSL style PEM file containing PKCS\#12 - * - * The various format identifiers. - */ - -/* In order of parsing when no formats specified */ -static const ParserFormat parser_normal[] = { - { GCR_FORMAT_PEM, parse_pem }, - { GCR_FORMAT_DER_PRIVATE_KEY_RSA, parse_der_private_key_rsa }, - { GCR_FORMAT_DER_PRIVATE_KEY_DSA, parse_der_private_key_dsa }, - { GCR_FORMAT_DER_CERTIFICATE_X509, parse_der_certificate }, - { GCR_FORMAT_DER_PKCS7, parse_der_pkcs7 }, - { GCR_FORMAT_DER_PKCS8_PLAIN, parse_der_pkcs8_plain }, - { GCR_FORMAT_DER_PKCS8_ENCRYPTED, parse_der_pkcs8_encrypted }, - { GCR_FORMAT_DER_PKCS12, parse_der_pkcs12 }, - { GCR_FORMAT_OPENSSH_PUBLIC, parse_openssh_public }, - { GCR_FORMAT_OPENPGP_PACKET, parse_openpgp_packets }, - { GCR_FORMAT_OPENPGP_ARMOR, parse_openpgp_armor }, -}; - -/* Must be in format_id numeric order */ -static const ParserFormat parser_formats[] = { - { GCR_FORMAT_DER_PRIVATE_KEY, parse_der_private_key }, - { GCR_FORMAT_DER_PRIVATE_KEY_RSA, parse_der_private_key_rsa }, - { GCR_FORMAT_DER_PRIVATE_KEY_DSA, parse_der_private_key_dsa }, - { GCR_FORMAT_DER_CERTIFICATE_X509, parse_der_certificate }, - { GCR_FORMAT_DER_PKCS7, parse_der_pkcs7 }, - { GCR_FORMAT_DER_PKCS8, parse_der_pkcs8 }, - { GCR_FORMAT_DER_PKCS8_PLAIN, parse_der_pkcs8_plain }, - { GCR_FORMAT_DER_PKCS8_ENCRYPTED, parse_der_pkcs8_encrypted }, - { GCR_FORMAT_DER_PKCS12, parse_der_pkcs12 }, - { GCR_FORMAT_OPENSSH_PUBLIC, parse_openssh_public }, - { GCR_FORMAT_OPENPGP_PACKET, parse_openpgp_packets }, - { GCR_FORMAT_OPENPGP_ARMOR, parse_openpgp_armor }, - { GCR_FORMAT_PEM, parse_pem }, - { GCR_FORMAT_PEM_PRIVATE_KEY_RSA, parse_pem_private_key_rsa }, - { GCR_FORMAT_PEM_PRIVATE_KEY_DSA, parse_pem_private_key_dsa }, - { GCR_FORMAT_PEM_CERTIFICATE_X509, parse_pem_certificate }, - { GCR_FORMAT_PEM_PKCS7, parse_pem_pkcs7 }, - { GCR_FORMAT_PEM_PKCS8_PLAIN, parse_pem_pkcs8_plain }, - { GCR_FORMAT_PEM_PKCS8_ENCRYPTED, parse_pem_pkcs8_encrypted }, - { GCR_FORMAT_PEM_PKCS12, parse_pem_pkcs12 }, -}; - -static int -compar_id_to_parser_format (const void *a, const void *b) -{ - const gint *format_id = a; - const ParserFormat *format = b; - - g_assert (format_id); - g_assert (format); - - if (format->format_id == *format_id) - return 0; - return (*format_id < format->format_id) ? -1 : 1; -} - -static ParserFormat* -parser_format_lookup (gint format_id) -{ - return bsearch (&format_id, parser_formats, G_N_ELEMENTS (parser_formats), - sizeof (parser_formats[0]), compar_id_to_parser_format); -} - -static gint -compare_pointers (gconstpointer a, gconstpointer b) -{ - if (a == b) - return 0; - return a < b ? -1 : 1; -} - -typedef struct _ForeachArgs { - GcrParser *parser; - const guchar *data; - gsize n_data; - gint result; -} ForeachArgs; - -static gboolean -parser_format_foreach (gpointer key, gpointer value, gpointer data) -{ - ForeachArgs *args = data; - ParserFormat *format = key; - gint result; - - g_assert (format); - g_assert (format->function); - g_assert (GCR_IS_PARSER (args->parser)); - - result = (format->function) (args->parser, args->data, args->n_data); - if (result != GCR_ERROR_UNRECOGNIZED) { - args->result = result; - return TRUE; - } - - /* Keep going */ - return FALSE; -} - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - - -static GObject* -gcr_parser_constructor (GType type, guint n_props, GObjectConstructParam *props) -{ - GcrParser *self = GCR_PARSER (G_OBJECT_CLASS (gcr_parser_parent_class)->constructor(type, n_props, props)); - g_return_val_if_fail (self, NULL); - - /* Always try to parse with NULL and empty passwords first */ - gcr_parser_add_password (self, NULL); - gcr_parser_add_password (self, ""); - - return G_OBJECT (self); -} - -static void -gcr_parser_init (GcrParser *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_PARSER, GcrParserPrivate); - self->pv->passwords = g_ptr_array_new (); - self->pv->normal_formats = TRUE; -} - -static void -gcr_parser_dispose (GObject *obj) -{ - GcrParser *self = GCR_PARSER (obj); - gsize i; - - g_assert (!self->pv->parsed); - - for (i = 0; i < self->pv->passwords->len; ++i) - egg_secure_strfree (g_ptr_array_index (self->pv->passwords, i)); - g_ptr_array_set_size (self->pv->passwords, 0); - - G_OBJECT_CLASS (gcr_parser_parent_class)->dispose (obj); -} - -static void -gcr_parser_finalize (GObject *obj) -{ - GcrParser *self = GCR_PARSER (obj); - - g_assert (!self->pv->parsed); - - g_ptr_array_free (self->pv->passwords, TRUE); - self->pv->passwords = NULL; - - G_OBJECT_CLASS (gcr_parser_parent_class)->finalize (obj); -} - -static void -gcr_parser_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_parser_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrParser *self = GCR_PARSER (obj); - - switch (prop_id) { - case PROP_PARSED_ATTRIBUTES: - g_value_set_boxed (value, gcr_parser_get_parsed_attributes (self)); - break; - case PROP_PARSED_LABEL: - g_value_set_string (value, gcr_parser_get_parsed_label (self)); - break; - case PROP_PARSED_DESCRIPTION: - g_value_set_string (value, gcr_parser_get_parsed_description (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_parser_class_init (GcrParserClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gint i; - - gobject_class->constructor = gcr_parser_constructor; - gobject_class->dispose = gcr_parser_dispose; - gobject_class->finalize = gcr_parser_finalize; - gobject_class->set_property = gcr_parser_set_property; - gobject_class->get_property = gcr_parser_get_property; - - /** - * GcrParser:parsed-attributes: - * - * Get the attributes that make up the currently parsed item. This is - * generally only valid during a #GcrParser::parsed signal. - */ - g_type_class_add_private (gobject_class, sizeof (GcrParserPrivate)); - - g_object_class_install_property (gobject_class, PROP_PARSED_ATTRIBUTES, - g_param_spec_boxed ("parsed-attributes", "Parsed Attributes", "Parsed PKCS#11 attributes", - GCK_TYPE_ATTRIBUTES, G_PARAM_READABLE)); - - /** - * GcrParser:parsed-label: - * - * The label of the currently parsed item. This is generally - * only valid during a #GcrParser::parsed signal. - */ - g_object_class_install_property (gobject_class, PROP_PARSED_LABEL, - g_param_spec_string ("parsed-label", "Parsed Label", "Parsed item label", - "", G_PARAM_READABLE)); - - /** - * GcrParser:parsed-description: - * - * The description of the type of the currently parsed item. This is generally - * only valid during a #GcrParser::parsed signal. - */ - g_object_class_install_property (gobject_class, PROP_PARSED_DESCRIPTION, - g_param_spec_string ("parsed-description", "Parsed Description", "Parsed item description", - "", G_PARAM_READABLE)); - - /** - * GcrParser::authenticate: - * @count: The number of times this item has been authenticated. - * - * This signal is emitted when an item needs to be unlocked or decrypted before - * it can be parsed. The @count argument specifies the number of times - * the signal has been emitted for a given item. This can be used to - * display a message saying the previous password was incorrect. - * - * Typically the gcr_parser_add_password() function is called in - * response to this signal. - * - * If %FALSE is returned, then the authentication was not handled. If - * no handlers return %TRUE then the item is not parsed and an error - * with the code %GCR_ERROR_CANCELLED will be raised. - * - * Returns: Whether the authentication was handled. - */ - signals[AUTHENTICATE] = g_signal_new ("authenticate", GCR_TYPE_PARSER, - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrParserClass, authenticate), - g_signal_accumulator_true_handled, NULL, _gcr_marshal_BOOLEAN__INT, - G_TYPE_BOOLEAN, 1, G_TYPE_POINTER); - - /** - * GcrParser::parsed: - * - * This signal is emitted when an item is sucessfully parsed. To access - * the information about the item use the gcr_parser_get_parsed_label(), - * gcr_parser_get_parsed_attributes() and gcr_parser_get_parsed_description() - * functions. - */ - signals[PARSED] = g_signal_new ("parsed", GCR_TYPE_PARSER, - G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GcrParserClass, parsed), - NULL, NULL, g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - init_quarks (); - _gcr_initialize_library (); - - /* Check that the format tables are in order */ - for (i = 1; i < G_N_ELEMENTS (parser_formats); ++i) - g_assert (parser_formats[i].format_id >= parser_formats[i - 1].format_id); -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_parser_new: - * - * Create a new #GcrParser - * - * Returns: (transfer full): a newly allocated #GcrParser - */ -GcrParser * -gcr_parser_new (void) -{ - return g_object_new (GCR_TYPE_PARSER, NULL); -} - -/** - * gcr_parser_add_password: - * @self: The parser - * @password: (allow-none): a password to try - * - * Add a password to the set of passwords to try when parsing locked or encrypted - * items. This is usually called from the GcrParser::authenticate signal. - */ -void -gcr_parser_add_password (GcrParser *self, const gchar *password) -{ - g_return_if_fail (GCR_IS_PARSER (self)); - g_ptr_array_add (self->pv->passwords, egg_secure_strdup (password)); -} - -/** - * gcr_parser_parse_data: - * @self: The parser - * @data: (array length=n_data): the data to parse - * @n_data: The length of the data - * @error: A location to raise an error on failure. - * - * Parse the data. The GcrParser::parsed and GcrParser::authenticate signals - * may fire during the parsing. - * - * Returns: Whether the data was parsed successfully or not. - */ -gboolean -gcr_parser_parse_data (GcrParser *self, - const guchar *data, - gsize n_data, - GError **error) -{ - ForeachArgs args = { self, data, n_data, GCR_ERROR_UNRECOGNIZED }; - const gchar *message = NULL; - gint i; - - g_return_val_if_fail (GCR_IS_PARSER (self), FALSE); - g_return_val_if_fail (data || !n_data, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - if (data && n_data) { - /* Just the specific formats requested */ - if (self->pv->specific_formats) { - g_tree_foreach (self->pv->specific_formats, parser_format_foreach, &args); - - /* All the 'normal' formats */ - } else if (self->pv->normal_formats) { - for (i = 0; i < G_N_ELEMENTS (parser_normal); ++i) { - if (parser_format_foreach ((gpointer)(parser_normal + i), - (gpointer)(parser_normal + i), &args)) - break; - } - } - } - - switch (args.result) { - case SUCCESS: - return TRUE; - case GCR_ERROR_CANCELLED: - message = _("The operation was cancelled"); - break; - case GCR_ERROR_UNRECOGNIZED: - message = _("Unrecognized or unsupported data."); - break; - case GCR_ERROR_FAILURE: - message = _("Could not parse invalid or corrupted data."); - break; - case GCR_ERROR_LOCKED: - message = _("The data is locked"); - break; - default: - g_assert_not_reached (); - break; - }; - - g_set_error_literal (error, GCR_DATA_ERROR, args.result, message); - return FALSE; -} - -/** - * gcr_parser_format_enable: - * @self: The parser - * @format: The format identifier - * - * Enable parsing of the given format. Use %GCR_FORMAT_ALL to enable all the formats. - */ -void -gcr_parser_format_enable (GcrParser *self, - GcrDataFormat format) -{ - const ParserFormat *form; - guint i; - - g_return_if_fail (GCR_IS_PARSER (self)); - - if (!self->pv->specific_formats) - self->pv->specific_formats = g_tree_new (compare_pointers); - - if (format != -1) { - form = parser_format_lookup (format); - g_return_if_fail (form); - g_tree_insert (self->pv->specific_formats, - (gpointer)form, (gpointer)form); - } else { - for (i = 0; i < G_N_ELEMENTS (parser_formats); i++) { - form = &parser_formats[i]; - g_tree_insert (self->pv->specific_formats, (gpointer)form, - (gpointer)form); - } - } -} - -/** - * gcr_parser_format_disable: - * @self: The parser - * @format: The format identifier - * - * Disable parsing of the given format. Use %GCR_FORMAT_ALL to disable all the formats. - */ -void -gcr_parser_format_disable (GcrParser *self, - GcrDataFormat format) -{ - ParserFormat *form; - - g_return_if_fail (GCR_IS_PARSER (self)); - - if (format == -1) { - if (self->pv->specific_formats) - g_tree_destroy (self->pv->specific_formats); - self->pv->specific_formats = NULL; - self->pv->normal_formats = FALSE; - } - - if (!self->pv->specific_formats) - return; - - form = parser_format_lookup (format); - g_return_if_fail (form); - - g_tree_remove (self->pv->specific_formats, form); -} - -/** - * gcr_parser_format_supported: - * @self: The parser - * @format: The format identifier - * - * Check whether the given format is supported by the parser. - * - * Returns: Whether the format is supported. - */ -gboolean -gcr_parser_format_supported (GcrParser *self, - GcrDataFormat format) -{ - g_return_val_if_fail (GCR_IS_PARSER (self), FALSE); - g_return_val_if_fail (format != GCR_FORMAT_ALL, FALSE); - g_return_val_if_fail (format != GCR_FORMAT_INVALID, FALSE); - return parser_format_lookup (format) ? TRUE : FALSE; -} - -/** - * gcr_parser_get_parsed: - * @self: a parser - * - * Get the currently parsed item - * - * Returns: (transfer none): the currently parsed item - */ -GcrParsed * -gcr_parser_get_parsed (GcrParser *self) -{ - g_return_val_if_fail (GCR_IS_PARSER (self), NULL); - return self->pv->parsed; -} - -GType -gcr_parsed_get_type (void) -{ - static volatile gsize initialized = 0; - static GType type = 0; - if (g_once_init_enter (&initialized)) { - type = g_boxed_type_register_static ("GcrParsed", - (GBoxedCopyFunc)gcr_parsed_ref, - (GBoxedFreeFunc)gcr_parsed_unref); - g_once_init_leave (&initialized, 1); - } - return type; -} - -/** - * gcr_parsed_ref: - * @parsed: a parsed item - * - * Add a reference to a parsed item. An item may not be shared across threads - * until it has been referenced at least once. - * - * Returns: (transfer full): the parsed item - */ -GcrParsed * -gcr_parsed_ref (GcrParsed *parsed) -{ - GcrParsed *copy; - - g_return_val_if_fail (parsed != NULL, NULL); - - /* Already had a reference */ -#if GLIB_CHECK_VERSION (2,29,90) - if (g_atomic_int_add (&parsed->refs, 1) >= 1) -#else - if (g_atomic_int_exchange_and_add (&parsed->refs, 1) >= 1) -#endif - return parsed; - - /* If this is the first reference, flatten the stack of parsed */ - copy = g_new0 (GcrParsed, 1); - copy->refs = 1; - copy->label = g_strdup (gcr_parsed_get_label (parsed)); - copy->attrs = gcr_parsed_get_attributes (parsed); - if (copy->attrs) - gck_attributes_ref (copy->attrs); - copy->description = gcr_parsed_get_description (parsed); - copy->next = NULL; - - /* Find the block of data to copy */ - while (parsed != NULL) { - if (parsed->data != NULL) { - if (parsed->sensitive) { - copy->data = egg_secure_alloc (parsed->n_data); - memcpy (copy->data, parsed->data, parsed->n_data); - copy->destroy_func = egg_secure_free; - } else { - copy->data = g_memdup (parsed->data, parsed->n_data); - copy->destroy_func = g_free; - } - copy->n_data = parsed->n_data; - break; - } - parsed = parsed->next; - } - - return copy; -} - -/** - * gcr_parsed_unref: - * @parsed: a parsed item - * - * Unreferences a parsed item which was referenced with gcr_parsed_ref() - */ -void -gcr_parsed_unref (gpointer parsed) -{ - GcrParsed *par = parsed; - - g_return_if_fail (parsed != NULL); - - if (g_atomic_int_dec_and_test (&par->refs)) { - if (par->attrs) - gck_attributes_unref (par->attrs); - g_free (par->label); - if (par->destroy_func) - (par->destroy_func) (par->data); - g_free (par); - } -} - -/** - * gcr_parser_get_parsed_description: - * @self: The parser - * - * Get a description for the type of the currently parsed item. This is generally - * only valid during the GcrParser::parsed signal. - * - * Returns: (allow-none): the description for the current item; this is owned by - * the parser and should not be freed - */ -const gchar* -gcr_parser_get_parsed_description (GcrParser *self) -{ - g_return_val_if_fail (GCR_IS_PARSER (self), NULL); - g_return_val_if_fail (self->pv->parsed != NULL, NULL); - - return gcr_parsed_get_description (self->pv->parsed); -} - -/** - * gcr_parsed_get_description: - * @parsed: a parsed item - * - * Get the descirption for a parsed item. - * - * Returns: (allow-none): the description - */ -const gchar* -gcr_parsed_get_description (GcrParsed *parsed) -{ - while (parsed != NULL) { - if (parsed->description != NULL) - return parsed->description; - parsed = parsed->next; - } - - return NULL; -} - -/** - * gcr_parser_get_parsed_attributes: - * @self: The parser - * - * Get the attributes which make up the currently parsed item. This is generally - * only valid during the GcrParser::parsed signal. - * - * Returns: (transfer none) (allow-none): the attributes for the current item, - * which are owned by the parser and should not be freed - */ -GckAttributes * -gcr_parser_get_parsed_attributes (GcrParser *self) -{ - g_return_val_if_fail (GCR_IS_PARSER (self), NULL); - g_return_val_if_fail (self->pv->parsed != NULL, NULL); - - return gcr_parsed_get_attributes (self->pv->parsed); -} - -/** - * gcr_parsed_get_attributes: - * @parsed: a parsed item - * - * Get the attributes which make up the parsed item. - * - * Returns: (transfer none) (allow-none): the attributes for the item; these - * are owned by the parsed item and should not be freed - */ -GckAttributes * -gcr_parsed_get_attributes (GcrParsed *parsed) -{ - while (parsed != NULL) { - if (parsed->attrs != NULL) - return parsed->attrs; - parsed = parsed->next; - } - - return NULL; -} - -/** - * gcr_parser_get_parsed_label: - * @self: The parser - * - * Get the label of the currently parsed item. This is generally only valid - * during the GcrParser::parsed signal. - * - * Returns: (allow-none): the label of the currently parsed item. The value is - * owned by the parser and should not be freed. - */ -const gchar* -gcr_parser_get_parsed_label (GcrParser *self) -{ - g_return_val_if_fail (GCR_IS_PARSER (self), NULL); - g_return_val_if_fail (self->pv->parsed != NULL, NULL); - - return gcr_parsed_get_label (self->pv->parsed); -} - -/** - * gcr_parsed_get_label: - * @parsed: a parsed item - * - * Get the label for the parsed item. - * - * Returns: (allow-none): the label for the item - */ -const gchar* -gcr_parsed_get_label (GcrParsed *parsed) -{ - while (parsed != NULL) { - if (parsed->label != NULL) - return parsed->label; - parsed = parsed->next; - } - - return NULL; -} - -/** - * gcr_parser_get_parsed_block: - * @self: a parser - * @n_block: a location to place the size of the block - * - * Get the raw data block that represents this parsed object. This is only - * valid during the GcrParser::parsed signal. - * - * Returns: (transfer none) (array length=n_block) (allow-none): the raw data - * block of the currently parsed item; the value is owned by the parser - * and should not be freed - */ -const guchar * -gcr_parser_get_parsed_block (GcrParser *self, - gsize *n_block) -{ - g_return_val_if_fail (GCR_IS_PARSER (self), NULL); - g_return_val_if_fail (n_block != NULL, NULL); - g_return_val_if_fail (self->pv->parsed != NULL, NULL); - - return gcr_parsed_get_data (self->pv->parsed, n_block); -} - -/** - * gcr_parsed_get_data: - * @parsed: a parsed item - * @n_data: location to store size of returned data - * - * Get the raw data block for the parsed item. - * - * Returns: (transfer full) (array length=n_data) (allow-none): the raw data of - * the parsed item, or %NULL - */ -const guchar * -gcr_parsed_get_data (GcrParsed *parsed, - gsize *n_data) -{ - g_return_val_if_fail (n_data != NULL, NULL); - - while (parsed != NULL) { - if (parsed->data != NULL) { - *n_data = parsed->n_data; - return parsed->data; - } - parsed = parsed->next; - } - - *n_data = 0; - return NULL; -} - -/** - * gcr_parser_get_parsed_format: - * @self: a parser - * - * Get the format of the raw data block that represents this parsed object. - * This corresponds with the data returned from gcr_parser_get_parsed_block(). - * - * This is only valid during the GcrParser::parsed signal. - * - * Returns: the data format of the currently parsed item - */ -GcrDataFormat -gcr_parser_get_parsed_format (GcrParser *self) -{ - g_return_val_if_fail (GCR_IS_PARSER (self), 0); - g_return_val_if_fail (self->pv->parsed != NULL, 0); - - return gcr_parsed_get_format (self->pv->parsed); -} - -/** - * gcr_parsed_get_format: - * @parsed: a parsed item - * - * Get the format of the parsed item. - * - * Returns: the data format of the item - */ -GcrDataFormat -gcr_parsed_get_format (GcrParsed *parsed) -{ - while (parsed != NULL) { - if (parsed->data != NULL) - return parsed->format; - parsed = parsed->next; - } - - return 0; -} -/* --------------------------------------------------------------------------------- - * STREAM PARSING - */ - -#define GCR_TYPE_PARSING (gcr_parsing_get_type ()) -#define GCR_PARSING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PARSING, GcrParsing)) -#define GCR_IS_PARSING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PARSING)) - -typedef struct _GcrParsing { - GObjectClass parent; - - GcrParser *parser; - gboolean async; - GCancellable *cancel; - - /* Failure information */ - GError *error; - gboolean complete; - - /* Operation state */ - GInputStream *input; - GByteArray *buffer; - - /* Async callback stuff */ - GAsyncReadyCallback callback; - gpointer user_data; - -} GcrParsing; - -typedef struct _GcrParsingClass { - GObjectClass parent_class; -} GcrParsingClass; - -/* State forward declarations */ -static void state_cancelled (GcrParsing *self, gboolean async); -static void state_failure (GcrParsing *self, gboolean async); -static void state_complete (GcrParsing *self, gboolean async); -static void state_parse_buffer (GcrParsing *self, gboolean async); -static void state_read_buffer (GcrParsing *self, gboolean async); - -/* Other forward declarations */ -static GType gcr_parsing_get_type (void) G_GNUC_CONST; -static void gcr_parsing_async_result_init (GAsyncResultIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrParsing, gcr_parsing, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, gcr_parsing_async_result_init)); - -#define BLOCK 4096 - -static void -next_state (GcrParsing *self, void (*state) (GcrParsing*, gboolean)) -{ - g_assert (GCR_IS_PARSING (self)); - g_assert (state); - - if (self->cancel && g_cancellable_is_cancelled (self->cancel)) - state = state_cancelled; - - (state) (self, self->async); -} - -static void -state_complete (GcrParsing *self, gboolean async) -{ - g_assert (GCR_IS_PARSING (self)); - g_assert (!self->complete); - self->complete = TRUE; - if (async && self->callback != NULL) - (self->callback) (G_OBJECT (self->parser), G_ASYNC_RESULT (self), self->user_data); -} - -static void -state_failure (GcrParsing *self, gboolean async) -{ - g_assert (GCR_IS_PARSING (self)); - g_assert (self->error); - next_state (self, state_complete); -} - -static void -state_cancelled (GcrParsing *self, gboolean async) -{ - g_assert (GCR_IS_PARSING (self)); - if (self->cancel && g_cancellable_is_cancelled (self->cancel)) - g_cancellable_cancel (self->cancel); - if (self->error) - g_error_free (self->error); - self->error = g_error_new_literal (GCR_DATA_ERROR, GCR_ERROR_CANCELLED, _("The operation was cancelled")); - next_state (self, state_failure); -} - -static void -state_parse_buffer (GcrParsing *self, gboolean async) -{ - GError *error = NULL; - gboolean ret; - - g_assert (GCR_IS_PARSING (self)); - g_assert (self->buffer); - - ret = gcr_parser_parse_data (self->parser, self->buffer->data, self->buffer->len, &error); - - if (ret == TRUE) { - next_state (self, state_complete); - } else { - g_propagate_error (&self->error, error); - next_state (self, state_failure); - } -} - -static void -complete_read_buffer (GcrParsing *self, gssize count, GError *error) -{ - g_assert (GCR_IS_PARSING (self)); - g_assert (self->buffer); - - /* A failure */ - if (count == -1) { - g_propagate_error (&self->error, error); - next_state (self, state_failure); - } else { - - g_return_if_fail (count >= 0 && count <= BLOCK); - g_byte_array_set_size (self->buffer, self->buffer->len - (BLOCK - count)); - - /* Finished reading */ - if (count == 0) - next_state (self, state_parse_buffer); - - /* Read the next block */ - else - next_state (self, state_read_buffer); - } - -} - -static void -on_read_buffer (GObject *obj, GAsyncResult *res, gpointer user_data) -{ - GError *error = NULL; - gssize count; - - count = g_input_stream_read_finish (G_INPUT_STREAM (obj), res, &error); - complete_read_buffer (user_data, count, error); -} - -static void -state_read_buffer (GcrParsing *self, gboolean async) -{ - GError *error = NULL; - gssize count; - gsize at; - - g_assert (GCR_IS_PARSING (self)); - g_assert (G_IS_INPUT_STREAM (self->input)); - - if (!self->buffer) - self->buffer = g_byte_array_sized_new (BLOCK); - - at = self->buffer->len; - g_byte_array_set_size (self->buffer, at + BLOCK); - - if (async) { - g_input_stream_read_async (self->input, self->buffer->data + at, - BLOCK, G_PRIORITY_DEFAULT, self->cancel, - on_read_buffer, self); - } else { - count = g_input_stream_read (self->input, self->buffer->data + at, - BLOCK, self->cancel, &error); - complete_read_buffer (self, count, error); - } -} - -static void -gcr_parsing_init (GcrParsing *self) -{ - -} - -static void -gcr_parsing_finalize (GObject *obj) -{ - GcrParsing *self = GCR_PARSING (obj); - - g_object_unref (self->parser); - self->parser = NULL; - - g_object_unref (self->input); - self->input = NULL; - - if (self->cancel) - g_object_unref (self->cancel); - self->cancel = NULL; - - g_clear_error (&self->error); - - if (self->buffer) - g_byte_array_free (self->buffer, TRUE); - self->buffer = NULL; - - G_OBJECT_CLASS (gcr_parsing_parent_class)->finalize (obj); -} - -static void -gcr_parsing_class_init (GcrParsingClass *klass) -{ - G_OBJECT_CLASS (klass)->finalize = gcr_parsing_finalize; -} - -static gpointer -gcr_parsing_real_get_user_data (GAsyncResult *base) -{ - g_return_val_if_fail (GCR_IS_PARSING (base), NULL); - return GCR_PARSING (base)->user_data; -} - -static GObject* -gcr_parsing_real_get_source_object (GAsyncResult *base) -{ - g_return_val_if_fail (GCR_IS_PARSING (base), NULL); - return G_OBJECT (GCR_PARSING (base)->parser); -} - -static void -gcr_parsing_async_result_init (GAsyncResultIface *iface) -{ - iface->get_source_object = gcr_parsing_real_get_source_object; - iface->get_user_data = gcr_parsing_real_get_user_data; -} - -static GcrParsing* -gcr_parsing_new (GcrParser *parser, GInputStream *input, GCancellable *cancel) -{ - GcrParsing *self; - - g_assert (GCR_IS_PARSER (parser)); - g_assert (G_IS_INPUT_STREAM (input)); - - self = g_object_new (GCR_TYPE_PARSING, NULL); - self->parser = g_object_ref (parser); - self->input = g_object_ref (input); - if (cancel) - self->cancel = g_object_ref (cancel); - - return self; -} - -/** - * gcr_parser_parse_stream: - * @self: The parser - * @input: The input stream - * @cancellable: An optional cancellation object - * @error: A location to raise an error on failure - * - * Parse items from the data in a #GInputStream. This function may block while - * reading from the input stream. Use gcr_parser_parse_stream_async() for - * a non-blocking variant. - * - * The GcrParser::parsed and GcrParser::authenticate signals - * may fire during the parsing. - * - * Returns: Whether the parsing completed successfully or not. - */ -gboolean -gcr_parser_parse_stream (GcrParser *self, GInputStream *input, GCancellable *cancellable, - GError **error) -{ - GcrParsing *parsing; - - g_return_val_if_fail (GCR_IS_PARSER (self), FALSE); - g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - parsing = gcr_parsing_new (self, input, cancellable); - parsing->async = FALSE; - - next_state (parsing, state_read_buffer); - g_assert (parsing->complete); - - return gcr_parser_parse_stream_finish (self, G_ASYNC_RESULT (parsing), error); -} - -/** - * gcr_parser_parse_stream_async: - * @self: The parser - * @input: The input stream - * @cancellable: An optional cancellation object - * @callback: Called when the operation result is ready. - * @user_data: Data to pass to callback - * - * Parse items from the data in a #GInputStream. This function completes - * asyncronously and doesn't block. - * - * The GcrParser::parsed and GcrParser::authenticate signals - * may fire during the parsing. - */ -void -gcr_parser_parse_stream_async (GcrParser *self, GInputStream *input, GCancellable *cancellable, - GAsyncReadyCallback callback, gpointer user_data) -{ - GcrParsing *parsing; - - g_return_if_fail (GCR_IS_PARSER (self)); - g_return_if_fail (G_IS_INPUT_STREAM (input)); - - parsing = gcr_parsing_new (self, input, cancellable); - parsing->async = TRUE; - parsing->callback = callback; - parsing->user_data = user_data; - - next_state (parsing, state_read_buffer); -} - -/** - * gcr_parser_parse_stream_finish: - * @self: The parser - * @result:The operation result - * @error: A location to raise an error on failure - * - * Complete an operation to parse a stream. - * - * Returns: Whether the parsing completed successfully or not. - */ -gboolean -gcr_parser_parse_stream_finish (GcrParser *self, GAsyncResult *result, GError **error) -{ - GcrParsing *parsing; - - g_return_val_if_fail (GCR_IS_PARSING (result), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - parsing = GCR_PARSING (result); - g_return_val_if_fail (parsing->complete, FALSE); - - if (parsing->error) { - g_propagate_error (error, parsing->error); - return FALSE; - } - - return TRUE; -} diff --git a/gcr/gcr-parser.h b/gcr/gcr-parser.h deleted file mode 100644 index 99a7e872..00000000 --- a/gcr/gcr-parser.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_PARSER_H__ -#define __GCR_PARSER_H__ - -#include <glib-object.h> -#include <gio/gio.h> - -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_PARSER (gcr_parser_get_type ()) -#define GCR_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PARSER, GcrParser)) -#define GCR_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_PARSER, GcrParserClass)) -#define GCR_IS_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PARSER)) -#define GCR_IS_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_PARSER)) -#define GCR_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_PARSER, GcrParserClass)) - -typedef struct _GcrParser GcrParser; -typedef struct _GcrParserClass GcrParserClass; -typedef struct _GcrParserPrivate GcrParserPrivate; -typedef struct _GcrParsed GcrParsed; - -struct _GcrParser { - GObject parent; - - /*< private >*/ - GcrParserPrivate *pv; -}; - -struct _GcrParserClass { - GObjectClass parent_class; - - /* signals --------------------------------------------------------- */ - - /* A callback for each password needed */ - gboolean (*authenticate) (GcrParser *self, gint count); - - void (*parsed) (GcrParser *self); -}; - -GType gcr_parser_get_type (void); - -GcrParser* gcr_parser_new (void); - -void gcr_parser_format_enable (GcrParser *self, - GcrDataFormat format); - -void gcr_parser_format_disable (GcrParser *self, - GcrDataFormat format); - -gboolean gcr_parser_format_supported (GcrParser *self, - GcrDataFormat format); - -gboolean gcr_parser_parse_data (GcrParser *self, - const guchar *data, - gsize n_data, - GError **error); - -gboolean gcr_parser_parse_stream (GcrParser *self, - GInputStream *input, - GCancellable *cancellable, - GError **error); - -void gcr_parser_parse_stream_async (GcrParser *self, - GInputStream *input, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean gcr_parser_parse_stream_finish (GcrParser *self, - GAsyncResult *result, - GError **error); - -void gcr_parser_add_password (GcrParser *self, - const gchar *password); - -GcrParsed * gcr_parser_get_parsed (GcrParser *self); - -const gchar* gcr_parser_get_parsed_label (GcrParser *self); - -const gchar* gcr_parser_get_parsed_description (GcrParser *self); - -GckAttributes* gcr_parser_get_parsed_attributes (GcrParser *self); - -const guchar * gcr_parser_get_parsed_block (GcrParser *self, - gsize *n_block); - -GcrDataFormat gcr_parser_get_parsed_format (GcrParser *self); - -#define GCR_TYPE_PARSED (gcr_parsed_get_type ()) - -GType gcr_parsed_get_type (void) G_GNUC_CONST; - -GcrParsed * gcr_parsed_ref (GcrParsed *parsed); - -void gcr_parsed_unref (gpointer parsed); - -const gchar* gcr_parsed_get_label (GcrParsed *parsed); - -const gchar* gcr_parsed_get_description (GcrParsed *parsed); - -GckAttributes* gcr_parsed_get_attributes (GcrParsed *parsed); - -const guchar * gcr_parsed_get_data (GcrParsed *parsed, - gsize *n_data); - -GcrDataFormat gcr_parsed_get_format (GcrParsed *parsed); - -G_END_DECLS - -#endif /* __GCR_PARSER_H__ */ diff --git a/gcr/gcr-pkcs11-certificate.c b/gcr/gcr-pkcs11-certificate.c deleted file mode 100644 index 25c22079..00000000 --- a/gcr/gcr-pkcs11-certificate.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-pkcs11-certificate.h" - -#include <gck/gck.h> -#include <string.h> - -#include "gcr-certificate.h" -#include "gcr-internal.h" -#include "gcr-library.h" - -#include "pkcs11/pkcs11.h" - -/** - * SECTION:gcr-pkcs11-certificate - * @title: GcrPkcs11Certificate - * @short_description: A certificate loaded from PKCS\#11 storage - * - * A #GcrPkcs11Certificate is a certificate loaded from a PKCS\#11 storage. - * It is also a valid #GckObject and can be used as such. - * - * Use gcr_pkcs11_certificate_lookup_issuer() to lookup the issuer of a given - * certificate in the PKCS\#11 store. - * - * Various common PKCS\#11 certificate attributes are automatically loaded and - * are available via gcr_pkcs11_certificate_get_attributes(). - */ - -/** - * GcrPkcs11Certificate: - * - * A certificate loaded from PKCS\#11 storage. - */ - -/** - * GcrPkcs11CertificateClass: - * - * The class for #GcrPkcs11Certificate. - */ - -enum { - PROP_0, - PROP_ATTRIBUTES -}; - -struct _GcrPkcs11CertificatePrivate { - GckAttributes *attrs; -}; - -static void gcr_certificate_iface (GcrCertificateIface *iface); -G_DEFINE_TYPE_WITH_CODE (GcrPkcs11Certificate, gcr_pkcs11_certificate, GCK_TYPE_OBJECT, - GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE (); - G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_certificate_iface); -); - -typedef struct { - GckAttributes *search; - GcrCertificate *result; -} lookup_issuer_closure; - -static void -lookup_issuer_free (gpointer data) -{ - lookup_issuer_closure *closure = data; - gck_attributes_unref (closure->search); - g_clear_object (&closure->result); - g_free (closure); -} - -static GckAttributes * -prepare_lookup_certificate_issuer (GcrCertificate *cert) -{ - GckAttributes *search; - gpointer data; - gsize n_data; - - search = gck_attributes_new (); - gck_attributes_add_ulong (search, CKA_CLASS, CKO_CERTIFICATE); - gck_attributes_add_ulong (search, CKA_CERTIFICATE_TYPE, CKC_X_509); - - data = gcr_certificate_get_issuer_raw (cert, &n_data); - gck_attributes_add_data (search, CKA_SUBJECT, data, n_data); - g_free (data); - - return search; -} - -static GcrCertificate* -perform_lookup_certificate (GckAttributes *search, - GCancellable *cancellable, - GError **error) -{ - GcrCertificate *cert; - GckObject *object; - GckAttributes *attrs; - GckModule *module; - GckSession *session; - GckEnumerator *en; - GList *modules; - - if (!gcr_pkcs11_initialize (cancellable, error)) - return NULL; - - modules = gcr_pkcs11_get_modules (); - en = gck_modules_enumerate_objects (modules, search, 0); - gck_list_unref_free (modules); - - object = gck_enumerator_next (en, cancellable, error); - g_object_unref (en); - - if (object == NULL) - return NULL; - - /* - * Only the CKA_VALUE, CKA_CLASS and CKA_CERTIFICATE_TYPE - * is strictly necessary here, but we get more attrs. - */ - attrs = gck_object_get (object, cancellable, error, - CKA_VALUE, CKA_LABEL, - CKA_ID, CKA_CLASS, - CKA_CERTIFICATE_TYPE, - CKA_ISSUER, - CKA_SERIAL_NUMBER, - GCK_INVALID); - - if (attrs == NULL) { - g_object_unref (object); - return NULL; - } - - module = gck_object_get_module (object); - session = gck_object_get_session (object); - - cert = g_object_new (GCR_TYPE_PKCS11_CERTIFICATE, - "module", module, - "handle", gck_object_get_handle (object), - "session", session, - "attributes", attrs, - NULL); - - g_object_unref (module); - g_object_unref (session); - g_object_unref (object); - - gck_attributes_unref (attrs); - - return cert; -} - -static void -thread_lookup_certificate (GSimpleAsyncResult *res, GObject *object, GCancellable *cancel) -{ - lookup_issuer_closure *closure; - GError *error = NULL; - - closure = g_simple_async_result_get_op_res_gpointer (res); - closure->result = perform_lookup_certificate (closure->search, cancel, &error); - - if (error != NULL) { - g_simple_async_result_set_from_error (res, error); - g_clear_error (&error); - } -} - -/* ---------------------------------------------------------------------------- - * OBJECT - */ - -static GObject* -gcr_pkcs11_certificate_constructor (GType type, guint n_props, GObjectConstructParam *props) -{ - gpointer obj = G_OBJECT_CLASS (gcr_pkcs11_certificate_parent_class)->constructor (type, n_props, props); - GckAttributes *attrs; - GckAttribute *attr; - gulong value; - - attrs = gcr_pkcs11_certificate_get_attributes (obj); - g_return_val_if_fail (attrs, NULL); - - if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &value) || - value != CKO_CERTIFICATE) { - g_warning ("attributes don't contain a certificate with: %s", - "CKA_CLASS == CKO_CERTIFICATE"); - return NULL; - } - - if (!gck_attributes_find_ulong (attrs, CKA_CERTIFICATE_TYPE, &value) || - value != CKC_X_509) { - g_warning ("attributes don't contain a certificate with: %s", - "CKA_CERTIFICATE_TYPE == CKC_X_509"); - return NULL; - } - - attr = gck_attributes_find (attrs, CKA_VALUE); - if (!attr || !attr->value || attr->length == 0 || attr->length == G_MAXULONG) { - g_warning ("attributes don't contain a valid: CKA_VALUE"); - return NULL; - } - - return obj; -} - -static void -gcr_pkcs11_certificate_init (GcrPkcs11Certificate *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_PKCS11_CERTIFICATE, GcrPkcs11CertificatePrivate); -} - -static void -gcr_pkcs11_certificate_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (obj); - - switch (prop_id) { - case PROP_ATTRIBUTES: - g_return_if_fail (self->pv->attrs == NULL); - self->pv->attrs = g_value_dup_boxed (value); - g_return_if_fail (self->pv->attrs != NULL); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_pkcs11_certificate_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (obj); - - switch (prop_id) { - case PROP_ATTRIBUTES: - g_value_set_boxed (value, gcr_pkcs11_certificate_get_attributes (self)); - break; - default: - gcr_certificate_mixin_get_property (obj, prop_id, value, pspec); - break; - } -} - -static void -gcr_pkcs11_certificate_finalize (GObject *obj) -{ - GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (obj); - - gck_attributes_unref (self->pv->attrs); - - G_OBJECT_CLASS (gcr_pkcs11_certificate_parent_class)->finalize (obj); -} - -static void -gcr_pkcs11_certificate_class_init (GcrPkcs11CertificateClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->constructor = gcr_pkcs11_certificate_constructor; - gobject_class->get_property = gcr_pkcs11_certificate_get_property; - gobject_class->set_property = gcr_pkcs11_certificate_set_property; - gobject_class->finalize = gcr_pkcs11_certificate_finalize; - - /** - * GcrPkcs11Certificate:attributes: - * - * Automatically loaded attributes for this certificate. - */ - g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, - g_param_spec_boxed ("attributes", "Attributes", "The data displayed in the renderer", - GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_type_class_add_private (gobject_class, sizeof (GcrPkcs11CertificatePrivate)); - - gcr_certificate_mixin_class_init (gobject_class); - _gcr_initialize_library (); -} - -static const guchar * -gcr_pkcs11_certificate_get_der_data (GcrCertificate *cert, - gsize *n_data) -{ - GcrPkcs11Certificate *self = GCR_PKCS11_CERTIFICATE (cert); - GckAttribute *attr; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - g_return_val_if_fail (n_data, NULL); - g_return_val_if_fail (self->pv->attrs, NULL); - - attr = gck_attributes_find (self->pv->attrs, CKA_VALUE); - g_return_val_if_fail (attr && attr->length != 0 && attr->length != G_MAXULONG, NULL); - *n_data = attr->length; - return attr->value; -} - -static void -gcr_certificate_iface (GcrCertificateIface *iface) -{ - iface->get_der_data = gcr_pkcs11_certificate_get_der_data; -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_pkcs11_certificate_get_attributes: - * @self: A #GcrPkcs11Certificate - * - * Access the automatically loaded attributes for this certificate. - * - * Returns: (transfer none): the certificate attributes - */ -GckAttributes * -gcr_pkcs11_certificate_get_attributes (GcrPkcs11Certificate *self) -{ - g_return_val_if_fail (GCR_IS_PKCS11_CERTIFICATE (self), NULL); - return self->pv->attrs; -} - -/** - * gcr_pkcs11_certificate_lookup_issuer: - * @certificate: a #GcrCertificate - * @cancellable: a #GCancellable - * @error: a #GError, or NULL - * - * Lookup a the issuer of a @certificate in the PKCS\#11 storage. The - * lookup is done using the issuer DN of the certificate. No certificate chain - * verification is done. Use a crypto library to make trust decisions. - * - * This call may block, see gcr_pkcs11_certificate_lookup_issuer() for the - * non-blocking version. - * - * Will return %NULL if no issuer certificate is found. Use @error to determine - * if an error occurred. - * - * Returns: (transfer full): a new #GcrPkcs11Certificate, or %NULL - */ -GcrCertificate * -gcr_pkcs11_certificate_lookup_issuer (GcrCertificate *certificate, GCancellable *cancellable, - GError **error) -{ - GckAttributes *search; - GcrCertificate *issuer; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), NULL); - - if (!gcr_pkcs11_initialize (cancellable, error)) - return NULL; - - search = prepare_lookup_certificate_issuer (certificate); - g_return_val_if_fail (search, FALSE); - - issuer = perform_lookup_certificate (search, cancellable, error); - gck_attributes_unref (search); - - return issuer; -} - -/** - * gcr_pkcs11_certificate_lookup_issuer_async: - * @certificate: a #GcrCertificate - * @cancellable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation completes - * @user_data: the data to pass to callback function - * - * Lookup a the issuer of a @certificate in the PKCS\#11 storage. The - * lookup is done using the issuer DN of the certificate. No certificate chain - * verification is done. Use a crypto library to make trust decisions. - * - * When the operation is finished, callback will be called. You can then call - * gcr_pkcs11_certificate_lookup_issuer_finish() to get the result of the - * operation. - */ -void -gcr_pkcs11_certificate_lookup_issuer_async (GcrCertificate *certificate, GCancellable *cancellable, - GAsyncReadyCallback callback, gpointer user_data) -{ - GSimpleAsyncResult *async; - lookup_issuer_closure *closure; - - g_return_if_fail (GCR_IS_CERTIFICATE (certificate)); - - async = g_simple_async_result_new (G_OBJECT (certificate), callback, user_data, - gcr_pkcs11_certificate_lookup_issuer_async); - closure = g_new0 (lookup_issuer_closure, 1); - closure->search = prepare_lookup_certificate_issuer (certificate); - g_return_if_fail (closure->search); - g_simple_async_result_set_op_res_gpointer (async, closure, lookup_issuer_free); - - g_simple_async_result_run_in_thread (async, thread_lookup_certificate, - G_PRIORITY_DEFAULT, cancellable); - - g_object_unref (async); -} - -/** - * gcr_pkcs11_certificate_lookup_issuer_finish: - * @result: the #GAsyncResult passed to the callback - * @error: a #GError, or NULL - * - * Finishes an asynchronous operation started by - * gcr_pkcs11_certificate_lookup_issuer_async(). - * - * Will return %NULL if no issuer certificate is found. Use @error to determine - * if an error occurred. - * - * Returns: (transfer full): a new #GcrPkcs11Certificate, or %NULL - */ -GcrCertificate * -gcr_pkcs11_certificate_lookup_issuer_finish (GAsyncResult *result, GError **error) -{ - lookup_issuer_closure *closure; - GObject *source; - - g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); - - source = g_async_result_get_source_object (result); - g_return_val_if_fail (g_simple_async_result_is_valid (result, source, - gcr_pkcs11_certificate_lookup_issuer_async), NULL); - g_object_unref (source); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return NULL; - - closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); - if (closure->result != NULL) - g_object_ref (closure->result); - return closure->result; -} diff --git a/gcr/gcr-pkcs11-certificate.h b/gcr/gcr-pkcs11-certificate.h deleted file mode 100644 index 04c15b36..00000000 --- a/gcr/gcr-pkcs11-certificate.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_PKCS11_CERTIFICATE_H__ -#define __GCR_PKCS11_CERTIFICATE_H__ - -#include "gcr-types.h" -#include "gcr-certificate.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_PKCS11_CERTIFICATE (gcr_pkcs11_certificate_get_type ()) -#define GCR_PKCS11_CERTIFICATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PKCS11_CERTIFICATE, GcrPkcs11Certificate)) -#define GCR_PKCS11_CERTIFICATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_PKCS11_CERTIFICATE, GcrPkcs11CertificateClass)) -#define GCR_IS_PKCS11_CERTIFICATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PKCS11_CERTIFICATE)) -#define GCR_IS_PKCS11_CERTIFICATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_PKCS11_CERTIFICATE)) -#define GCR_PKCS11_CERTIFICATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_PKCS11_CERTIFICATE, GcrPkcs11CertificateClass)) - -typedef struct _GcrPkcs11Certificate GcrPkcs11Certificate; -typedef struct _GcrPkcs11CertificateClass GcrPkcs11CertificateClass; -typedef struct _GcrPkcs11CertificatePrivate GcrPkcs11CertificatePrivate; - -struct _GcrPkcs11Certificate { - GckObject parent; - - /*< private >*/ - GcrPkcs11CertificatePrivate *pv; -}; - -struct _GcrPkcs11CertificateClass { - /*< private >*/ - GckObjectClass parent_class; -}; - -GType gcr_pkcs11_certificate_get_type (void); - -GckAttributes* gcr_pkcs11_certificate_get_attributes (GcrPkcs11Certificate *self); - -GcrCertificate* gcr_pkcs11_certificate_lookup_issuer (GcrCertificate *certificate, - GCancellable *cancellable, - GError **error); - -void gcr_pkcs11_certificate_lookup_issuer_async (GcrCertificate *certificate, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -GcrCertificate* gcr_pkcs11_certificate_lookup_issuer_finish (GAsyncResult *result, - GError **error); - -G_END_DECLS - -#endif /* __GCR_PKCS11_CERTIFICATE_H__ */ diff --git a/gcr/gcr-pkcs11-import-dialog.c b/gcr/gcr-pkcs11-import-dialog.c deleted file mode 100644 index e33d624a..00000000 --- a/gcr/gcr-pkcs11-import-dialog.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-dialog-util.h" -#include "gcr-pkcs11-import-dialog.h" - -#include "egg/egg-entry-buffer.h" -#include "egg/egg-secure-memory.h" - -#include <gtk/gtk.h> - -#include <glib/gi18n-lib.h> - -EGG_SECURE_DECLARE (import_dialog); - -#define GCR_PKCS11_IMPORT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_PKCS11_IMPORT_DIALOG, GcrPkcs11ImportDialogClass)) -#define GCR_IS_PKCS11_IMPORT_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_PKCS11_IMPORT_DIALOG)) -#define GCR_PKCS11_IMPORT_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_PKCS11_IMPORT_DIALOG, GcrPkcs11ImportDialogClass)) - -enum { - PROP_0, - PROP_IMPORTER -}; - -struct _GcrPkcs11ImportDialog { - GtkDialog parent; - GtkBuilder *builder; - GtkWidget *password_area; - GtkLabel *token_label; - GtkImage *token_image; - GtkEntry *password_entry; - GtkEntry *label_entry; - gboolean label_changed; -}; - -typedef struct _GcrPkcs11ImportDialogClass GcrPkcs11ImportDialogClass; - -struct _GcrPkcs11ImportDialogClass { - GtkDialogClass parent; -}; - -G_DEFINE_TYPE (GcrPkcs11ImportDialog, _gcr_pkcs11_import_dialog, GTK_TYPE_DIALOG); - -static void -on_label_changed (GtkEditable *editable, - gpointer user_data) -{ - GcrPkcs11ImportDialog *self = GCR_PKCS11_IMPORT_DIALOG (user_data); - self->label_changed = TRUE; -} - -static void -_gcr_pkcs11_import_dialog_constructed (GObject *obj) -{ - GcrPkcs11ImportDialog *self = GCR_PKCS11_IMPORT_DIALOG (obj); - GError *error = NULL; - GtkEntryBuffer *buffer; - GtkWidget *widget; - GtkBox *contents; - - G_OBJECT_CLASS (_gcr_pkcs11_import_dialog_parent_class)->constructed (obj); - - if (!gtk_builder_add_from_file (self->builder, UIDIR "gcr-pkcs11-import-dialog.ui", &error)) { - g_warning ("couldn't load ui builder file: %s", error->message); - return; - } - - /* Fill in the dialog from builder */ - widget = GTK_WIDGET (gtk_builder_get_object (self->builder, "pkcs11-import-dialog")); - contents = GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))); - gtk_box_pack_start (contents, widget, TRUE, TRUE, 0); - - /* The password area */ - self->password_area = GTK_WIDGET (gtk_builder_get_object (self->builder, "unlock-area")); - gtk_widget_hide (self->password_area); - - /* Add a secure entry */ - buffer = egg_entry_buffer_new (); - self->password_entry = GTK_ENTRY (gtk_builder_get_object (self->builder, "password-entry")); - gtk_entry_set_buffer (self->password_entry, buffer); - gtk_entry_set_activates_default (self->password_entry, TRUE); - g_object_unref (buffer); - - self->token_label = GTK_LABEL (gtk_builder_get_object (self->builder, "token-description")); - self->token_image = GTK_IMAGE (gtk_builder_get_object (self->builder, "token-image")); - - /* Setup the label */ - self->label_entry = GTK_ENTRY (gtk_builder_get_object (self->builder, "label-entry")); - g_signal_connect (self->label_entry, "changed", G_CALLBACK (on_label_changed), self); - gtk_entry_set_activates_default (self->label_entry, TRUE); - - /* Add our various buttons */ - gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); - gtk_dialog_add_button (GTK_DIALOG (self), GTK_STOCK_OK, GTK_RESPONSE_OK); - gtk_dialog_set_default_response (GTK_DIALOG (self), GTK_RESPONSE_OK); - - gtk_window_set_modal (GTK_WINDOW (self), TRUE); -} - -static void -_gcr_pkcs11_import_dialog_init (GcrPkcs11ImportDialog *self) -{ - self->builder = gtk_builder_new (); -} - -static void -_gcr_pkcs11_import_dialog_finalize (GObject *obj) -{ - GcrPkcs11ImportDialog *self = GCR_PKCS11_IMPORT_DIALOG (obj); - - g_object_unref (self->builder); - - G_OBJECT_CLASS (_gcr_pkcs11_import_dialog_parent_class)->finalize (obj); -} - -static void -_gcr_pkcs11_import_dialog_class_init (GcrPkcs11ImportDialogClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->constructed = _gcr_pkcs11_import_dialog_constructed; - gobject_class->finalize = _gcr_pkcs11_import_dialog_finalize; -} - -GcrPkcs11ImportDialog * -_gcr_pkcs11_import_dialog_new (GtkWindow *parent) -{ - GcrPkcs11ImportDialog *dialog; - - g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL); - - dialog = g_object_new (GCR_TYPE_PKCS11_IMPORT_DIALOG, - "transient-for", parent, - NULL); - - return g_object_ref_sink (dialog); -} - -void -_gcr_pkcs11_import_dialog_get_supplements (GcrPkcs11ImportDialog *self, - GckAttributes *attributes) -{ - const gchar *label; - - g_return_if_fail (GCR_IS_PKCS11_IMPORT_DIALOG (self)); - g_return_if_fail (attributes != NULL); - - label = gtk_entry_get_text (self->label_entry); - if (self->label_changed && label != NULL && label[0]) - gck_attributes_set_string (attributes, CKA_LABEL, label); -} - -void -_gcr_pkcs11_import_dialog_set_supplements (GcrPkcs11ImportDialog *self, - GckAttributes *attributes) -{ - gchar *label; - - g_return_if_fail (GCR_IS_PKCS11_IMPORT_DIALOG (self)); - g_return_if_fail (attributes != NULL); - - if (!gck_attributes_find_string (attributes, CKA_LABEL, &label)) - label = NULL; - - if (label == NULL) - gtk_entry_set_placeholder_text (self->label_entry, _("Automatically chosen")); - gtk_entry_set_text (self->label_entry, label == NULL ? "" : label); - g_free (label); - - self->label_changed = FALSE; -} - -gboolean -_gcr_pkcs11_import_dialog_run (GcrPkcs11ImportDialog *self) -{ - gboolean ret = FALSE; - - g_return_val_if_fail (GCR_IS_PKCS11_IMPORT_DIALOG (self), FALSE); - - if (gtk_dialog_run (GTK_DIALOG (self)) == GTK_RESPONSE_OK) { - ret = TRUE; - } - - gtk_widget_hide (GTK_WIDGET (self)); - - return ret; -} - -void -_gcr_pkcs11_import_dialog_run_async (GcrPkcs11ImportDialog *self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_return_if_fail (GCR_IS_PKCS11_IMPORT_DIALOG (self)); - - _gcr_dialog_util_run_async (GTK_DIALOG (self), cancellable, callback, user_data); -} - -gboolean -_gcr_pkcs11_import_dialog_run_finish (GcrPkcs11ImportDialog *self, - GAsyncResult *result) -{ - gint response; - - g_return_val_if_fail (GCR_IS_PKCS11_IMPORT_DIALOG (self), FALSE); - - response = _gcr_dialog_util_run_finish (GTK_DIALOG (self), result); - - gtk_widget_hide (GTK_WIDGET (self)); - - return (response == GTK_RESPONSE_OK) ? TRUE : FALSE; -} - -GTlsInteractionResult -_gcr_pkcs11_import_dialog_run_ask_password (GcrPkcs11ImportDialog *self, - GTlsPassword *password, - GCancellable *cancellable, - GError **error) -{ - GckTokenInfo *token_info; - const gchar *value; - GckSlot *slot; - GIcon *icon; - gboolean ret; - - g_return_val_if_fail (GCR_IS_PKCS11_IMPORT_DIALOG (self), G_TLS_INTERACTION_UNHANDLED); - g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_INTERACTION_UNHANDLED); - g_return_val_if_fail (error == NULL || *error == NULL, G_TLS_INTERACTION_UNHANDLED); - - if (GCK_IS_PASSWORD (password)) { - slot = gck_password_get_token (GCK_PASSWORD (password)); - token_info = gck_slot_get_token_info (slot); - icon = gcr_icon_for_token (token_info); - gtk_image_set_from_gicon (self->token_image, icon, GTK_ICON_SIZE_BUTTON); - gck_token_info_free (token_info); - g_object_unref (icon); - } - - gtk_label_set_text (self->token_label, g_tls_password_get_description (password)); - - gtk_widget_show (self->password_area); - - ret = _gcr_pkcs11_import_dialog_run (self); - - gtk_widget_hide (self->password_area); - - if (!ret) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, - _("The user cancelled the operation")); - return G_TLS_INTERACTION_FAILED; - } - - value = gtk_entry_get_text (self->password_entry); - g_tls_password_set_value_full (password, egg_secure_strdup (value), - -1, egg_secure_free); - return G_TLS_INTERACTION_HANDLED; -} diff --git a/gcr/gcr-pkcs11-import-dialog.h b/gcr/gcr-pkcs11-import-dialog.h deleted file mode 100644 index 38a1dd4c..00000000 --- a/gcr/gcr-pkcs11-import-dialog.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef __GCR_PKCS11_IMPORT_DIALOG_H__ -#define __GCR_PKCS11_IMPORT_DIALOG_H__ - -#include "gcr.h" - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_PKCS11_IMPORT_DIALOG (_gcr_pkcs11_import_dialog_get_type ()) -#define GCR_PKCS11_IMPORT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PKCS11_IMPORT_DIALOG, GcrPkcs11ImportDialog)) -#define GCR_IS_PKCS11_IMPORT_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PKCS11_IMPORT_DIALOG)) - -typedef struct _GcrPkcs11ImportDialog GcrPkcs11ImportDialog; - -GType _gcr_pkcs11_import_dialog_get_type (void) G_GNUC_CONST; - -GcrPkcs11ImportDialog * _gcr_pkcs11_import_dialog_new (GtkWindow *parent); - -void _gcr_pkcs11_import_dialog_get_supplements (GcrPkcs11ImportDialog *self, - GckAttributes *attributes); - -void _gcr_pkcs11_import_dialog_set_supplements (GcrPkcs11ImportDialog *self, - GckAttributes *attributes); - -gboolean _gcr_pkcs11_import_dialog_run (GcrPkcs11ImportDialog *self); - -void _gcr_pkcs11_import_dialog_run_async (GcrPkcs11ImportDialog *self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean _gcr_pkcs11_import_dialog_run_finish (GcrPkcs11ImportDialog *self, - GAsyncResult *result); - -GTlsInteractionResult _gcr_pkcs11_import_dialog_run_ask_password (GcrPkcs11ImportDialog *self, - GTlsPassword *password, - GCancellable *cancellable, - GError **error); - -G_END_DECLS - -#endif /* __GCR_PKCS11_IMPORT_DIALOG_H__ */ diff --git a/gcr/gcr-pkcs11-import-dialog.ui b/gcr/gcr-pkcs11-import-dialog.ui deleted file mode 100644 index a565cf1f..00000000 --- a/gcr/gcr-pkcs11-import-dialog.ui +++ /dev/null @@ -1,251 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - <!-- interface-requires gtk+ 2.12 --> - <object class="GtkVBox" id="pkcs11-import-dialog"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="border_width">6</property> - <property name="spacing">6</property> - <child> - <object class="GtkFrame" id="unlock-area"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label_xalign">0</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkAlignment" id="alignment2"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="left_padding">12</property> - <child> - <object class="GtkBox" id="box1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="orientation">vertical</property> - <property name="spacing">6</property> - <child> - <object class="GtkLabel" id="password-description"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">In order to import, please enter the password.</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkGrid" id="grid2"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="row_spacing">6</property> - <property name="column_spacing">12</property> - <child> - <object class="GtkEntry" id="password-entry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">●</property> - <property name="visibility">False</property> - <property name="width_chars">20</property> - <property name="invisible_char_set">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">1</property> - <property name="width">1</property> - <property name="height">1</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="password-label"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Password:</property> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">1</property> - <property name="width">1</property> - <property name="height">1</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="token-label"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Token:</property> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> - <property name="width">1</property> - <property name="height">1</property> - </packing> - </child> - <child> - <object class="GtkBox" id="box2"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="spacing">6</property> - <child> - <object class="GtkImage" id="token-image"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="stock">gtk-missing-image</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="token-description"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Label</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">0</property> - <property name="width">1</property> - <property name="height">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="label5"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><b>Unlock</b></property> - <property name="use_markup">True</property> - </object> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkFrame" id="settings-area"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label_xalign">0</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkAlignment" id="alignment1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="left_padding">12</property> - <child> - <object class="GtkGrid" id="grid1"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="row_spacing">6</property> - <property name="column_spacing">12</property> - <child> - <object class="GtkLabel" id="label-label"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Label:</property> - </object> - <packing> - <property name="left_attach">0</property> - <property name="top_attach">0</property> - <property name="width">1</property> - <property name="height">1</property> - </packing> - </child> - <child> - <object class="GtkEntry" id="label-entry"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">●</property> - <property name="width_chars">20</property> - <property name="invisible_char_set">True</property> - </object> - <packing> - <property name="left_attach">1</property> - <property name="top_attach">0</property> - <property name="width">1</property> - <property name="height">1</property> - </packing> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - <child> - <placeholder/> - </child> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel" id="label4"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="margin_bottom">6</property> - <property name="xalign">0</property> - <property name="label" translatable="yes"><b>Import settings</b></property> - <property name="use_markup">True</property> - </object> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <object class="GtkSizeGroup" id="entry-size-group"> - <property name="mode">GTK_SIZE_GROUP_HORIZONTAL</property> - <widgets> - <widget name="password-label"/> - <widget name="token-label"/> - <widget name="label-label"/> - </widgets> - </object> -</interface> diff --git a/gcr/gcr-pkcs11-import-interaction.c b/gcr/gcr-pkcs11-import-interaction.c deleted file mode 100644 index e9a18335..00000000 --- a/gcr/gcr-pkcs11-import-interaction.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-dialog-util.h" -#include "gcr-import-interaction.h" -#include "gcr-pkcs11-import-interaction.h" - -#include <glib/gi18n-lib.h> - -#define GCR_PKCS11_IMPORT_INTERACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_PKCS11_IMPORT_INTERACTION, GcrPkcs11ImportInteractionClass)) -#define GCR_IS_PKCS11_IMPORT_INTERACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_PKCS11_IMPORT_INTERACTION)) -#define GCR_PKCS11_IMPORT_INTERACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_PKCS11_IMPORT_INTERACTION, GcrPkcs11ImportInteractionClass)) - -enum { - PROP_0, - PROP_PARENT_WINDOW -}; - -typedef struct _GcrPkcs11ImportInteractionClass GcrPkcs11ImportInteractionClass; - -struct _GcrPkcs11ImportInteraction { - GTlsInteraction parent; - gboolean supplemented; - GtkWindow *parent_window; - GcrPkcs11ImportDialog *dialog; -}; - -struct _GcrPkcs11ImportInteractionClass { - GTlsInteractionClass parent_class; -}; - -static void _gcr_pkcs11_import_interaction_iface_init (GcrImportInteractionIface *iface); - -G_DEFINE_TYPE_WITH_CODE(GcrPkcs11ImportInteraction, _gcr_pkcs11_import_interaction, G_TYPE_TLS_INTERACTION, - G_IMPLEMENT_INTERFACE (GCR_TYPE_IMPORT_INTERACTION, _gcr_pkcs11_import_interaction_iface_init)); - -static void -_gcr_pkcs11_import_interaction_init (GcrPkcs11ImportInteraction *self) -{ - self->dialog = _gcr_pkcs11_import_dialog_new (self->parent_window); -} - -static void -_gcr_pkcs11_import_interaction_dispose (GObject *obj) -{ - GcrPkcs11ImportInteraction *self = GCR_PKCS11_IMPORT_INTERACTION (obj); - - g_clear_object (&self->dialog); - - G_OBJECT_CLASS (_gcr_pkcs11_import_interaction_parent_class)->dispose (obj); -} - -static void -_gcr_pkcs11_import_interaction_set_property (GObject *obj, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GcrPkcs11ImportInteraction *self = GCR_PKCS11_IMPORT_INTERACTION (obj); - - switch (prop_id) { - case PROP_PARENT_WINDOW: - gtk_window_set_transient_for (GTK_WINDOW (self->dialog), - g_value_get_object (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_pkcs11_import_interaction_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GcrPkcs11ImportInteraction *self = GCR_PKCS11_IMPORT_INTERACTION (obj); - - switch (prop_id) { - case PROP_PARENT_WINDOW: - g_value_set_object (value, gtk_window_get_transient_for (GTK_WINDOW (self->dialog))); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static GTlsInteractionResult -_gcr_pkcs11_import_interaction_ask_password (GTlsInteraction *interaction, - GTlsPassword *password, - GCancellable *cancellable, - GError **error) -{ - GcrPkcs11ImportInteraction *self = GCR_PKCS11_IMPORT_INTERACTION (interaction); - - g_return_val_if_fail (self->dialog != NULL, G_TLS_INTERACTION_UNHANDLED); - - self->supplemented = TRUE; - return _gcr_pkcs11_import_dialog_run_ask_password (self->dialog, password, cancellable, error); -} - -static void -_gcr_pkcs11_import_interaction_supplement_prep (GcrImportInteraction *interaction, - GckAttributes *attributes) -{ - GcrPkcs11ImportInteraction *self = GCR_PKCS11_IMPORT_INTERACTION (interaction); - - self->supplemented = FALSE; - _gcr_pkcs11_import_dialog_set_supplements (self->dialog, attributes); -} - -static GTlsInteractionResult -_gcr_pkcs11_import_interaction_supplement (GcrImportInteraction *interaction, - GckAttributes *attributes, - GCancellable *cancellable, - GError **error) -{ - GcrPkcs11ImportInteraction *self = GCR_PKCS11_IMPORT_INTERACTION (interaction); - - g_return_val_if_fail (self->dialog != NULL, G_TLS_INTERACTION_UNHANDLED); - - if (self->supplemented) - return G_TLS_INTERACTION_HANDLED; - - self->supplemented = TRUE; - if (_gcr_pkcs11_import_dialog_run (self->dialog)) { - _gcr_pkcs11_import_dialog_get_supplements (self->dialog, attributes); - return G_TLS_INTERACTION_HANDLED; - - } else { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, _("The user cancelled the operation")); - return G_TLS_INTERACTION_FAILED; - } -} - -static void -on_dialog_run_async (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GckAttributes *attributes = g_simple_async_result_get_op_res_gpointer (res); - - if (_gcr_pkcs11_import_dialog_run_finish (GCR_PKCS11_IMPORT_DIALOG (source), result)) { - _gcr_pkcs11_import_dialog_get_supplements (GCR_PKCS11_IMPORT_DIALOG (source), attributes); - - } else { - g_simple_async_result_set_error (res, G_IO_ERROR, G_IO_ERROR_CANCELLED, - _("The user cancelled the operation")); - } - - g_simple_async_result_complete (res); - g_object_unref (res); -} - -static void -_gcr_pkcs11_import_interaction_supplement_async (GcrImportInteraction *interaction, - GckAttributes *attributes, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GcrPkcs11ImportInteraction *self = GCR_PKCS11_IMPORT_INTERACTION (interaction); - GSimpleAsyncResult *res; - - g_return_if_fail (self->dialog != NULL); - - res = g_simple_async_result_new (G_OBJECT (interaction), callback, user_data, - _gcr_pkcs11_import_interaction_supplement_async); - - /* If dialog was already shown, then short circuit */ - if (self->supplemented) { - g_simple_async_result_complete_in_idle (res); - - } else { - self->supplemented = TRUE; - g_simple_async_result_set_op_res_gpointer (res, gck_attributes_ref (attributes), - (GDestroyNotify)gck_attributes_unref); - _gcr_pkcs11_import_dialog_run_async (self->dialog, cancellable, - on_dialog_run_async, g_object_ref (res)); - } - - g_object_unref (res); -} - -static GTlsInteractionResult -_gcr_pkcs11_import_interaction_supplement_finish (GcrImportInteraction *interaction, - GAsyncResult *result, - GError **error) -{ - GcrPkcs11ImportInteraction *self = GCR_PKCS11_IMPORT_INTERACTION (interaction); - - g_return_val_if_fail (self->dialog != NULL, G_TLS_INTERACTION_UNHANDLED); - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (interaction), - _gcr_pkcs11_import_interaction_supplement_async), G_TLS_INTERACTION_UNHANDLED); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return G_TLS_INTERACTION_FAILED; - - return G_TLS_INTERACTION_HANDLED; - -} - -static void -_gcr_pkcs11_import_interaction_iface_init (GcrImportInteractionIface *iface) -{ - iface->supplement_prep = _gcr_pkcs11_import_interaction_supplement_prep; - iface->supplement = _gcr_pkcs11_import_interaction_supplement; - iface->supplement_async = _gcr_pkcs11_import_interaction_supplement_async; - iface->supplement_finish = _gcr_pkcs11_import_interaction_supplement_finish; -} - -static void -_gcr_pkcs11_import_interaction_class_init (GcrPkcs11ImportInteractionClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass); - - gobject_class->dispose = _gcr_pkcs11_import_interaction_dispose; - gobject_class->set_property = _gcr_pkcs11_import_interaction_set_property; - gobject_class->get_property = _gcr_pkcs11_import_interaction_get_property; - - interaction_class->ask_password = _gcr_pkcs11_import_interaction_ask_password; - - g_object_class_install_property (gobject_class, PROP_PARENT_WINDOW, - g_param_spec_object ("parent-window", "Parent Window", "Prompt Parent Window", - GTK_TYPE_WINDOW, G_PARAM_READWRITE)); -} - -GTlsInteraction * -_gcr_pkcs11_import_interaction_new (GtkWindow *parent_window) -{ - g_return_val_if_fail (parent_window == NULL || GTK_IS_WINDOW (parent_window), NULL); - return g_object_new (GCR_TYPE_PKCS11_IMPORT_INTERACTION, - "parent-window", parent_window, - NULL); -} diff --git a/gcr/gcr-pkcs11-import-interaction.h b/gcr/gcr-pkcs11-import-interaction.h deleted file mode 100644 index 97027ba9..00000000 --- a/gcr/gcr-pkcs11-import-interaction.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef __GCR_PKCS11_IMPORT_INTERACTION_H__ -#define __GCR_PKCS11_IMPORT_INTERACTION_H__ - -#include "gcr.h" - -#include "gcr-pkcs11-import-dialog.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_PKCS11_IMPORT_INTERACTION (_gcr_pkcs11_import_interaction_get_type ()) -#define GCR_PKCS11_IMPORT_INTERACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PKCS11_IMPORT_INTERACTION, GcrPkcs11ImportInteraction)) -#define GCR_IS_PKCS11_IMPORT_INTERACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PKCS11_IMPORT_INTERACTION)) - -typedef struct _GcrPkcs11ImportInteraction GcrPkcs11ImportInteraction; - -GType _gcr_pkcs11_import_interaction_get_type (void) G_GNUC_CONST; - -GTlsInteraction * _gcr_pkcs11_import_interaction_new (GtkWindow *parent_window); - -G_END_DECLS - -#endif /* __GCR_PKCS11_IMPORT_INTERACTION_H__ */ diff --git a/gcr/gcr-pkcs11-importer.c b/gcr/gcr-pkcs11-importer.c deleted file mode 100644 index 5cc60b62..00000000 --- a/gcr/gcr-pkcs11-importer.c +++ /dev/null @@ -1,910 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#define DEBUG_FLAG GCR_DEBUG_IMPORT -#include "gcr-debug.h" -#include "gcr-fingerprint.h" -#include "gcr-icons.h" -#include "gcr-internal.h" -#include "gcr-library.h" -#include "gcr-import-interaction.h" -#include "gcr-internal.h" -#include "gcr-parser.h" -#include "gcr-pkcs11-importer.h" - -#include "egg/egg-hex.h" - -#include <gck/gck.h> - -#include <gcrypt.h> - -#include <glib/gi18n-lib.h> - -enum { - PROP_0, - PROP_LABEL, - PROP_ICON, - PROP_INTERACTION, - PROP_SLOT, - PROP_IMPORTED, - PROP_QUEUED -}; - -typedef struct _GcrPkcs11ImporterClass GcrPkcs11ImporterClass; - -struct _GcrPkcs11Importer { - GObject parent; - GckSlot *slot; - GList *objects; - GckSession *session; - GQueue *queue; - GTlsInteraction *interaction; - gboolean any_private; -}; - -struct _GcrPkcs11ImporterClass { - GObjectClass parent_class; -}; - -typedef struct { - GcrPkcs11Importer *importer; - GCancellable *cancellable; - gboolean prompted; - gboolean async; - GckAttributes *supplement; -} GcrImporterData; - -/* State forward declarations */ -static void state_cancelled (GSimpleAsyncResult *res, - gboolean async); - -static void state_complete (GSimpleAsyncResult *res, - gboolean async); - -static void state_create_object (GSimpleAsyncResult *res, - gboolean async); - -static void state_supplement (GSimpleAsyncResult *res, - gboolean async); - -static void state_open_session (GSimpleAsyncResult *res, - gboolean async); - -static void _gcr_pkcs11_importer_init_iface (GcrImporterIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrPkcs11Importer, _gcr_pkcs11_importer, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_IMPORTER, _gcr_pkcs11_importer_init_iface); -); - -#define BLOCK 4096 - -static void -gcr_importer_data_free (gpointer data) -{ - GcrImporterData *state = data; - - g_clear_object (&state->cancellable); - g_clear_object (&state->importer); - g_free (state); -} - -static void -next_state (GSimpleAsyncResult *res, - void (*state) (GSimpleAsyncResult *, gboolean)) -{ - GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res); - - g_assert (state); - - if (g_cancellable_is_cancelled (data->cancellable)) - state = state_cancelled; - - (state) (res, data->async); -} - -/* --------------------------------------------------------------------------------- - * COMPLETE - */ - -static void -state_complete (GSimpleAsyncResult *res, - gboolean async) -{ - g_simple_async_result_complete (res); -} - -static void -state_cancelled (GSimpleAsyncResult *res, - gboolean async) -{ - GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res); - GError *error = NULL; - - if (data->cancellable && !g_cancellable_is_cancelled (data->cancellable)) - g_cancellable_cancel (data->cancellable); - - g_cancellable_set_error_if_cancelled (data->cancellable, &error); - g_simple_async_result_take_error (res, error); - next_state (res, state_complete); -} - -/* --------------------------------------------------------------------------------- - * CREATE OBJECTS - */ - -static void -complete_create_object (GSimpleAsyncResult *res, - GckObject *object, - GError *error) -{ - GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res); - GcrPkcs11Importer *self = data->importer; - - if (object == NULL) { - g_simple_async_result_take_error (res, error); - next_state (res, state_complete); - - } else { - self->objects = g_list_append (self->objects, object); - next_state (res, state_create_object); - } -} - -static void -on_create_object (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GError *error = NULL; - GckObject *object; - - object = gck_session_create_object_finish (GCK_SESSION (source), result, &error); - complete_create_object (res, object, error); - g_object_unref (res); -} - -static void -state_create_object (GSimpleAsyncResult *res, - gboolean async) -{ - GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res); - GcrPkcs11Importer *self = data->importer; - GckAttributes *attrs; - GckObject *object; - GError *error = NULL; - - /* No more objects */ - if (g_queue_is_empty (self->queue)) { - next_state (res, state_complete); - - } else { - - /* Pop first one off the list */ - attrs = g_queue_pop_head (self->queue); - g_assert (attrs != NULL); - - if (async) { - gck_session_create_object_async (self->session, attrs, - data->cancellable, on_create_object, - g_object_ref (res)); - } else { - object = gck_session_create_object (self->session, attrs, - data->cancellable, &error); - complete_create_object (res, object, error); - } - - gck_attributes_unref (attrs); - } -} - -/* --------------------------------------------------------------------------------- - * SUPPLEMENTING and FIXING UP - */ - -typedef struct { - GckAttributes *certificate; - GckAttributes *private_key; -} CertificateKeyPair; - -static void -supplement_with_attributes (GckAttributes *attrs, - GckAttributes *supplements) -{ - GckAttribute *supplement; - gint i; - - for (i = 0; i < gck_attributes_count (supplements); i++) { - supplement = gck_attributes_at (supplements, i); - if (!gck_attribute_is_invalid (supplement) && supplement->length != 0) - gck_attributes_add (attrs, supplement); - } -} - -static void -supplement_id_for_data (GckAttributes *attrs, - guchar *nonce, - gsize n_once, - gpointer data, - gsize n_data) -{ - gcry_md_hd_t mdh; - gcry_error_t gcry; - - if (gck_attributes_find (attrs, CKA_ID) != NULL) - return; - - gcry = gcry_md_open (&mdh, GCRY_MD_SHA1, 0); - g_return_if_fail (gcry == 0); - - gcry_md_write (mdh, nonce, n_once); - gcry_md_write (mdh, data, n_data); - - gck_attributes_add_data (attrs, CKA_ID, - gcry_md_read (mdh, 0), - gcry_md_get_algo_dlen (GCRY_MD_SHA1)); - - gcry_md_close (mdh); -} - -static void -supplement_attributes (GcrPkcs11Importer *self, - GckAttributes *supplements) -{ - GHashTable *pairs; - GHashTable *paired; - CertificateKeyPair *pair; - gboolean supplemented = FALSE; - GckAttributes *attrs; - gulong klass; - guchar *finger; - gchar *fingerprint; - guchar nonce[20]; - GHashTableIter iter; - gsize n_finger; - GQueue *queue; - GList *l; - - /* A table of certificate/key pairs by fingerprint */ - pairs = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, g_free); - - for (l = self->queue->head; l != NULL; l = g_list_next (l)) { - attrs = l->data; - if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &klass)) - g_return_if_reached (); - - /* Make a string fingerprint for this guy */ - finger = gcr_fingerprint_from_attributes (attrs, G_CHECKSUM_SHA1, - &n_finger); - if (finger) { - fingerprint = egg_hex_encode (finger, n_finger); - g_free (finger); - - pair = g_hash_table_lookup (pairs, fingerprint); - if (pair == NULL) { - pair = g_new0 (CertificateKeyPair, 1); - g_hash_table_insert (pairs, fingerprint, pair); - } else { - g_free (fingerprint); - } - } else { - pair = NULL; - } - - fingerprint = NULL; - - gck_attributes_set_boolean (attrs, CKA_TOKEN, CK_TRUE); - - switch (klass) { - case CKO_CERTIFICATE: - gck_attributes_set_boolean (attrs, CKA_PRIVATE, FALSE); - if (pair != NULL && pair->certificate == NULL) - pair->certificate = attrs; - break; - case CKO_PRIVATE_KEY: - gck_attributes_set_boolean (attrs, CKA_PRIVATE, TRUE); - gck_attributes_add_boolean (attrs, CKA_DECRYPT, TRUE); - gck_attributes_add_boolean (attrs, CKA_SIGN, TRUE); - gck_attributes_add_boolean (attrs, CKA_SIGN_RECOVER, TRUE); - gck_attributes_add_boolean (attrs, CKA_UNWRAP, TRUE); - gck_attributes_add_boolean (attrs, CKA_SENSITIVE, TRUE); - if (pair != NULL && pair->private_key == NULL) - pair->private_key = attrs; - break; - } - } - - /* For generation of CKA_ID's */ - gcry_create_nonce (nonce, sizeof (nonce)); - - /* A table for marking which attributes are in the pairs table */ - paired = g_hash_table_new (g_direct_hash, g_direct_equal); - - /* Now move everything in pairs to the front */ - queue = g_queue_new (); - g_hash_table_iter_init (&iter, pairs); - while (g_hash_table_iter_next (&iter, (gpointer *)&fingerprint, (gpointer *)&pair)) { - if (pair->certificate != NULL && pair->private_key != NULL) { - /* - * Generate a CKA_ID based on the fingerprint and nonce, - * and do the same CKA_ID for both private key and certificate. - */ - - supplement_with_attributes (pair->private_key, supplements); - supplement_id_for_data (pair->private_key, nonce, sizeof (nonce), - fingerprint, strlen (fingerprint)); - g_queue_push_tail (queue, pair->private_key); - g_hash_table_insert (paired, pair->private_key, "present"); - - supplement_with_attributes (pair->private_key, supplements); - supplement_id_for_data (pair->certificate, nonce, sizeof (nonce), - fingerprint, strlen (fingerprint)); - g_queue_push_tail (queue, pair->certificate); - g_hash_table_insert (paired, pair->certificate, "present"); - - /* Used the suplements for the pairs, don't use for unpaired stuff */ - supplemented = TRUE; - } - } - - /* Go through the old queue, and look for anything not paired */ - for (l = self->queue->head; l != NULL; l = g_list_next (l)) { - attrs = l->data; - if (!g_hash_table_lookup (paired, attrs)) { - if (!supplemented) - supplement_with_attributes (attrs, supplements); - - /* - * Generate a CKA_ID based on the location of attrs in, - * memory, since this together with the nonce should - * be unique. - */ - supplement_id_for_data (attrs, nonce, sizeof (nonce), - &attrs, sizeof (gpointer)); - - g_queue_push_tail (queue, l->data); - } - } - - /* And swap the new queue into place */ - g_queue_free (self->queue); - self->queue = queue; - - g_hash_table_destroy (paired); - g_hash_table_destroy (pairs); -} - -static void -complete_supplement (GSimpleAsyncResult *res, - GError *error) -{ - GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res); - - if (error == NULL) { - supplement_attributes (data->importer, data->supplement); - next_state (res, state_create_object); - } else { - g_simple_async_result_take_error (res, error); - next_state (res, state_complete); - } -} - -static void -on_supplement_done (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res); - GcrPkcs11Importer *self = data->importer; - GError *error = NULL; - - gcr_import_interaction_supplement_finish (GCR_IMPORT_INTERACTION (self->interaction), - result, &error); - complete_supplement (res, error); - g_object_unref (res); -} - -static void -state_supplement (GSimpleAsyncResult *res, - gboolean async) -{ - GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res); - GcrPkcs11Importer *self = data->importer; - GError *error = NULL; - - if (self->interaction == NULL || !GCR_IS_IMPORT_INTERACTION (self->interaction)) { - complete_supplement (res, NULL); - - } else if (async) { - gcr_import_interaction_supplement_async (GCR_IMPORT_INTERACTION (self->interaction), - data->supplement, data->cancellable, - on_supplement_done, g_object_ref (res)); - - } else { - gcr_import_interaction_supplement (GCR_IMPORT_INTERACTION (self->interaction), - data->supplement, data->cancellable, &error); - complete_supplement (res, error); - } -} - -static void -supplement_prep (GSimpleAsyncResult *res) -{ - GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res); - GcrPkcs11Importer *self = data->importer; - GckAttribute *the_label = NULL; - GckAttribute *attr; - gboolean first = TRUE; - GList *l; - - if (data->supplement) - gck_attributes_unref (data->supplement); - data->supplement = gck_attributes_new (); - - /* Do we have a consistent label across all objects? */ - for (l = self->queue->head; l != NULL; l = g_list_next (l)) { - attr = gck_attributes_find (l->data, CKA_LABEL); - if (first) - the_label = attr; - else if (!gck_attribute_equal (the_label, attr)) - the_label = NULL; - first = FALSE; - } - - /* If consistent label, set that in supplement data */ - if (the_label != NULL) - gck_attributes_add (data->supplement, the_label); - else - gck_attributes_add_empty (data->supplement, CKA_LABEL); - - if (GCR_IS_IMPORT_INTERACTION (self->interaction)) - gcr_import_interaction_supplement_prep (GCR_IMPORT_INTERACTION (self->interaction), - data->supplement); -} - -/* --------------------------------------------------------------------------------- - * OPEN SESSION - */ - -static void -complete_open_session (GSimpleAsyncResult *res, - GckSession *session, - GError *error) -{ - GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res); - GcrPkcs11Importer *self = data->importer; - - if (!session) { - g_simple_async_result_take_error (res, error); - next_state (res, state_complete); - - } else { - g_clear_object (&self->session); - self->session = session; - next_state (res, state_supplement); - } -} - -static void -on_open_session (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); - GError *error = NULL; - GckSession *session; - - session = gck_slot_open_session_finish (GCK_SLOT (source), result, &error); - complete_open_session (res, session, error); - g_object_unref (res); -} - -static void -state_open_session (GSimpleAsyncResult *res, - gboolean async) -{ - GcrImporterData *data = g_simple_async_result_get_op_res_gpointer (res); - GcrPkcs11Importer *self = data->importer; - guint options = GCK_SESSION_READ_WRITE | GCK_SESSION_LOGIN_USER; - GckSession *session; - GError *error = NULL; - - if (async) { - gck_slot_open_session_async (self->slot, options, - data->cancellable, on_open_session, - g_object_ref (res)); - } else { - session = gck_slot_open_session_full (self->slot, options, 0, - NULL, NULL, data->cancellable, &error); - complete_open_session (res, session, error); - } -} - -static void -_gcr_pkcs11_importer_init (GcrPkcs11Importer *self) -{ - self->queue = g_queue_new (); -} - -static void -_gcr_pkcs11_importer_dispose (GObject *obj) -{ - GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj); - - gck_list_unref_free (self->objects); - self->objects = NULL; - g_clear_object (&self->session); - g_clear_object (&self->interaction); - - while (!g_queue_is_empty (self->queue)) - gck_attributes_unref (g_queue_pop_head (self->queue)); - - G_OBJECT_CLASS (_gcr_pkcs11_importer_parent_class)->dispose (obj); -} - -static void -_gcr_pkcs11_importer_finalize (GObject *obj) -{ - GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj); - - g_clear_object (&self->slot); - - G_OBJECT_CLASS (_gcr_pkcs11_importer_parent_class)->finalize (obj); -} - -static void -_gcr_pkcs11_importer_set_property (GObject *obj, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj); - - switch (prop_id) { - case PROP_SLOT: - self->slot = g_value_dup_object (value); - g_return_if_fail (self->slot); - break; - case PROP_INTERACTION: - g_clear_object (&self->interaction); - self->interaction = g_value_dup_object (value); - g_object_notify (G_OBJECT (self), "interaction"); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static gchar * -calculate_label (GcrPkcs11Importer *self) -{ - GckTokenInfo *info; - gchar *result; - - info = gck_slot_get_token_info (self->slot); - result = g_strdup (info->label); - gck_token_info_free (info); - - return result; -} - -static GIcon * -calculate_icon (GcrPkcs11Importer *self, - GckTokenInfo *token_info) -{ - GckTokenInfo *info = NULL; - GIcon *result; - - if (token_info == NULL) - info = token_info = gck_slot_get_token_info (self->slot); - result = gcr_icon_for_token (token_info); - gck_token_info_free (info); - - return result; -} - -static void -_gcr_pkcs11_importer_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (obj); - - switch (prop_id) { - case PROP_LABEL: - g_value_take_string (value, calculate_label (self)); - break; - case PROP_ICON: - g_value_take_object (value, calculate_icon (self, NULL)); - break; - case PROP_SLOT: - g_value_set_object (value, _gcr_pkcs11_importer_get_slot (self)); - break; - case PROP_IMPORTED: - g_value_take_boxed (value, _gcr_pkcs11_importer_get_imported (self)); - break; - case PROP_QUEUED: - g_value_set_pointer (value, _gcr_pkcs11_importer_get_queued (self)); - break; - case PROP_INTERACTION: - g_value_set_object (value, self->interaction); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_pkcs11_importer_class_init (GcrPkcs11ImporterClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GckAttributes *registered; - - gobject_class->dispose = _gcr_pkcs11_importer_dispose; - gobject_class->finalize = _gcr_pkcs11_importer_finalize; - gobject_class->set_property = _gcr_pkcs11_importer_set_property; - gobject_class->get_property = _gcr_pkcs11_importer_get_property; - - g_object_class_override_property (gobject_class, PROP_LABEL, "label"); - - g_object_class_override_property (gobject_class, PROP_ICON, "icon"); - - g_object_class_override_property (gobject_class, PROP_INTERACTION, "interaction"); - - g_object_class_install_property (gobject_class, PROP_SLOT, - g_param_spec_object ("slot", "Slot", "PKCS#11 slot to import data into", - GCK_TYPE_SLOT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (gobject_class, PROP_IMPORTED, - g_param_spec_boxed ("imported", "Imported", "Imported objects", - GCK_TYPE_LIST, G_PARAM_READABLE)); - - g_object_class_install_property (gobject_class, PROP_QUEUED, - g_param_spec_pointer ("queued", "Queued", "Queued attributes", - G_PARAM_READABLE)); - - registered = gck_attributes_new (); - gck_attributes_add_ulong (registered, CKA_CLASS, CKO_CERTIFICATE); - gck_attributes_add_ulong (registered, CKA_CERTIFICATE_TYPE, CKC_X_509); - gcr_importer_register (GCR_TYPE_PKCS11_IMPORTER, registered); - gck_attributes_unref (registered); - - registered = gck_attributes_new (); - gck_attributes_add_ulong (registered, CKA_CLASS, CKO_PRIVATE_KEY); - gcr_importer_register (GCR_TYPE_PKCS11_IMPORTER, registered); - gck_attributes_unref (registered); - - _gcr_initialize_library (); -} - -static GList * -list_all_slots (void) -{ - GList *modules; - GList *results; - - modules = gcr_pkcs11_get_modules (); - results = gck_modules_get_slots (modules, TRUE); - gck_list_unref_free (modules); - - return results; -} - -static const char *token_blacklist[] = { - "pkcs11:manufacturer=Gnome%20Keyring;serial=1:SECRET:MAIN", - "pkcs11:manufacturer=Gnome%20Keyring;serial=1:USER:DEFAULT", - NULL -}; - -static gboolean -is_slot_importable (GckSlot *slot, - GckTokenInfo *token) -{ - GError *error = NULL; - GckUriData *uri; - gboolean match; - guint i; - - if (token->flags & CKF_WRITE_PROTECTED) { - _gcr_debug ("token is not importable: %s: write protected", token->label); - return FALSE; - } - if (!(token->flags & CKF_TOKEN_INITIALIZED)) { - _gcr_debug ("token is not importable: %s: not initialized", token->label); - return FALSE; - } - if ((token->flags & CKF_LOGIN_REQUIRED) && - !(token->flags & CKF_USER_PIN_INITIALIZED)) { - _gcr_debug ("token is not importable: %s: user pin not initialized", token->label); - return FALSE; - } - - for (i = 0; token_blacklist[i] != NULL; i++) { - uri = gck_uri_parse (token_blacklist[i], GCK_URI_FOR_TOKEN | GCK_URI_FOR_MODULE, &error); - if (uri == NULL) { - g_warning ("couldn't parse pkcs11 blacklist uri: %s", error->message); - g_clear_error (&error); - continue; - } - - match = gck_slot_match (slot, uri); - gck_uri_data_free (uri); - - if (match) { - _gcr_debug ("token is not importable: %s: on the black list", token->label); - return FALSE; - } - } - - return TRUE; -} - -static GList * -_gcr_pkcs11_importer_create_for_parsed (GcrParsed *parsed) -{ - GcrImporter *self; - GList *slots, *l; - GList *results = NULL; - GckTokenInfo *token_info; - gboolean importable; - - slots = list_all_slots (); - for (l = slots; l != NULL; l = g_list_next (l)) { - token_info = gck_slot_get_token_info (l->data); - importable = is_slot_importable (l->data, token_info); - - if (importable) { - _gcr_debug ("creating importer for token: %s", token_info->label); - self = _gcr_pkcs11_importer_new (l->data); - if (!gcr_importer_queue_for_parsed (self, parsed)) - g_assert_not_reached (); - results = g_list_prepend (results, self); - } - - gck_token_info_free (token_info); - } - gck_list_unref_free (slots); - - return g_list_reverse (results); -} - -static gboolean -_gcr_pkcs11_importer_queue_for_parsed (GcrImporter *importer, - GcrParsed *parsed) -{ - GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (importer); - GckAttributes *attrs; - const gchar *label; - - attrs = gcr_parsed_get_attributes (parsed); - label = gcr_parsed_get_label (parsed); - _gcr_pkcs11_importer_queue (self, label, attrs); - - return TRUE; -} - -static void -_gcr_pkcs11_importer_import_async (GcrImporter *importer, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GcrPkcs11Importer *self = GCR_PKCS11_IMPORTER (importer); - GSimpleAsyncResult *res; - GcrImporterData *data; - - res = g_simple_async_result_new (G_OBJECT (importer), callback, user_data, - _gcr_pkcs11_importer_import_async); - data = g_new0 (GcrImporterData, 1); - data->async = TRUE; - data->importer = g_object_ref (importer); - data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; - g_simple_async_result_set_op_res_gpointer (res, data, gcr_importer_data_free); - - supplement_prep (res); - gck_slot_set_interaction (self->slot, self->interaction); - - next_state (res, state_open_session); - g_object_unref (res); -} - -static gboolean -_gcr_pkcs11_importer_import_finish (GcrImporter *importer, - GAsyncResult *result, - GError **error) -{ - g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (importer), - _gcr_pkcs11_importer_import_async), FALSE); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return FALSE; - - return TRUE; -} - -static void -_gcr_pkcs11_importer_init_iface (GcrImporterIface *iface) -{ - iface->create_for_parsed = _gcr_pkcs11_importer_create_for_parsed; - iface->queue_for_parsed = _gcr_pkcs11_importer_queue_for_parsed; - iface->import_async = _gcr_pkcs11_importer_import_async; - iface->import_finish = _gcr_pkcs11_importer_import_finish; -} - -/** - * _gcr_pkcs11_importer_new: - * - * Returns: (transfer full) (type Gcr.Pkcs11Importer): the new importer - */ -GcrImporter * -_gcr_pkcs11_importer_new (GckSlot *slot) -{ - g_return_val_if_fail (GCK_IS_SLOT (slot), NULL); - - return g_object_new (GCR_TYPE_PKCS11_IMPORTER, - "slot", slot, - NULL); -} - -GckSlot * -_gcr_pkcs11_importer_get_slot (GcrPkcs11Importer *self) -{ - g_return_val_if_fail (GCR_IS_PKCS11_IMPORTER (self), NULL); - return self->slot; -} - -GList * -_gcr_pkcs11_importer_get_imported (GcrPkcs11Importer *self) -{ - g_return_val_if_fail (GCR_IS_PKCS11_IMPORTER (self), NULL); - return g_list_copy (self->objects); -} - -GList * -_gcr_pkcs11_importer_get_queued (GcrPkcs11Importer *self) -{ - g_return_val_if_fail (GCR_IS_PKCS11_IMPORTER (self), NULL); - return g_list_copy (self->queue->head); -} - -void -_gcr_pkcs11_importer_queue (GcrPkcs11Importer *self, - const gchar *label, - GckAttributes *attrs) -{ - g_return_if_fail (GCR_IS_PKCS11_IMPORTER (self)); - g_return_if_fail (attrs != NULL); - - if (label != NULL && !gck_attributes_find (attrs, CKA_LABEL)) - gck_attributes_add_string (attrs, CKA_LABEL, label); - - g_queue_push_tail (self->queue, gck_attributes_ref (attrs)); -} diff --git a/gcr/gcr-pkcs11-importer.h b/gcr/gcr-pkcs11-importer.h deleted file mode 100644 index 5f66f7b3..00000000 --- a/gcr/gcr-pkcs11-importer.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_H_INSIDE__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> can be included directly." -#endif - -#ifndef __GCR_PKCS11_IMPORTER_H__ -#define __GCR_PKCS11_IMPORTER_H__ - -#include "gcr-importer.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_PKCS11_IMPORTER (_gcr_pkcs11_importer_get_type ()) -#define GCR_PKCS11_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_PKCS11_IMPORTER, GcrPkcs11Importer)) -#define GCR_PKCS11_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_PKCS11_IMPORTER, GcrPkcs11ImporterClass)) -#define GCR_IS_PKCS11_IMPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_PKCS11_IMPORTER)) -#define GCR_IS_PKCS11_IMPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_PKCS11_IMPORTER)) -#define GCR_PKCS11_IMPORTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_PKCS11_IMPORTER, GcrPkcs11ImporterClass)) - -typedef struct _GcrPkcs11Importer GcrPkcs11Importer; - - -GType _gcr_pkcs11_importer_get_type (void); - -GcrImporter * _gcr_pkcs11_importer_new (GckSlot *slot); - -void _gcr_pkcs11_importer_queue (GcrPkcs11Importer *self, - const gchar *label, - GckAttributes *attrs); - -GckSlot * _gcr_pkcs11_importer_get_slot (GcrPkcs11Importer *self); - -GList * _gcr_pkcs11_importer_get_queued (GcrPkcs11Importer *self); - -GList * _gcr_pkcs11_importer_get_imported (GcrPkcs11Importer *self); - -G_END_DECLS - -#endif /* __GCR_PKCS11_IMPORTER_H__ */ diff --git a/gcr/gcr-record.c b/gcr/gcr-record.c deleted file mode 100644 index 7b065eb0..00000000 --- a/gcr/gcr-record.c +++ /dev/null @@ -1,811 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-record.h" -#define DEBUG_FLAG GCR_DEBUG_PARSE -#include "gcr-debug.h" - -#include "egg/egg-timegm.h" - -#include <stdlib.h> -#include <string.h> -#include <time.h> - -#define MAX_COLUMNS 32 - -typedef struct { - gpointer next; - gsize n_value; - gchar value[1]; - /* Hangs off the end */ -} GcrRecordBlock; - -struct _GcrRecord { - GcrRecordBlock *block; - const gchar *columns[MAX_COLUMNS]; - guint n_columns; - gchar delimiter; -}; - -G_DEFINE_BOXED_TYPE (GcrRecord, _gcr_record, _gcr_record_copy, _gcr_record_free); - -static GcrRecordBlock * -record_block_new (const gchar *value, - gsize length) -{ - GcrRecordBlock *block; - - block = g_malloc (sizeof (GcrRecordBlock) + length); - block->next = NULL; - block->n_value = length; - - if (value != NULL) { - memcpy (block->value, value, length); - block->value[length] = 0; - } else { - block->value[0] = 0; - } - - return block; -} - -static GcrRecordBlock * -record_block_take (gchar *value, - gsize length) -{ - GcrRecordBlock *block; - - g_assert (value); - - block = g_realloc (value, sizeof (GcrRecordBlock) + length); - memmove (((gchar*)block) + G_STRUCT_OFFSET (GcrRecordBlock, value), - block, length); - block->next = NULL; - block->n_value = length; - block->value[length] = 0; - - return block; -} - -static GcrRecord * -record_flatten (GcrRecord *record) -{ - GcrRecord *result; - GcrRecordBlock *block; - gsize total; - gsize at; - gsize len; - guint i; - - /* Calculate the length of what we need */ - total = 0; - for (i = 0; i < record->n_columns; i++) - total += strlen (record->columns[i]) + 1; - - /* Allocate a new GcrRecordData which will hold all that */ - result = g_slice_new0 (GcrRecord); - result->block = block = record_block_new (NULL, total); - - at = 0; - for (i = 0; i < record->n_columns; i++) { - len = strlen (record->columns[i]); - result->columns[i] = block->value + at; - memcpy ((gchar *)result->columns[i], record->columns[i], len + 1); - at += len + 1; - } - - result->n_columns = record->n_columns; - result->delimiter = record->delimiter; - g_assert (at == total); - - return result; -} - -static void -print_record_to_string (GcrRecord *record, - GString *string) -{ - guint i; - - for (i = 0; i < record->n_columns; i++) { - g_string_append (string, record->columns[i]); - g_string_append_c (string, record->delimiter); - } -} - -gchar * -_gcr_record_format (GcrRecord *record) -{ - GString *string; - - g_return_val_if_fail (record, NULL); - - string = g_string_new (""); - print_record_to_string (record, string); - return g_string_free (string, FALSE); -} - -GcrRecord * -_gcr_record_new (GQuark schema, - guint n_columns, - gchar delimiter) -{ - GcrRecord *result; - guint i; - - result = g_slice_new0 (GcrRecord); - result->block = NULL; - result->delimiter = delimiter; - - for (i = 0; i < n_columns; i++) - result->columns[i] = ""; - result->columns[0] = g_quark_to_string (schema); - result->n_columns = n_columns; - - return result; -} - -GcrRecord * -_gcr_record_copy (GcrRecord *record) -{ - return record_flatten (record); -} - -static GcrRecord * -take_and_parse_internal (GcrRecordBlock *block, - gchar delimiter, - gboolean allow_empty) -{ - GcrRecord *result; - gchar *at, *beg, *end; - - g_assert (block); - - result = g_slice_new0 (GcrRecord); - result->block = block; - result->delimiter = delimiter; - - _gcr_debug ("parsing line %s", block->value); - - at = block->value; - for (;;) { - if (result->n_columns >= MAX_COLUMNS) { - _gcr_debug ("too many record (%d) in gnupg line", MAX_COLUMNS); - _gcr_record_free (result); - return NULL; - } - - beg = at; - result->columns[result->n_columns] = beg; - - at = strchr (beg, delimiter); - if (at == NULL) { - end = (block->value + block->n_value) - 1; - } else { - at[0] = '\0'; - end = at; - at++; - } - - if (allow_empty || end > beg) - result->n_columns++; - - if (at == NULL) - break; - } - - return result; -} - -GcrRecord* -_gcr_record_parse_colons (const gchar *line, gssize n_line) -{ - g_return_val_if_fail (line, NULL); - if (n_line < 0) - n_line = strlen (line); - return take_and_parse_internal (record_block_new (line, n_line), ':', TRUE); -} - -GcrRecord* -_gcr_record_parse_spaces (const gchar *line, gssize n_line) -{ - g_return_val_if_fail (line, NULL); - if (n_line < 0) - n_line = strlen (line); - return take_and_parse_internal (record_block_new (line, n_line), ' ', FALSE); -} - -guint -_gcr_record_get_count (GcrRecord *record) -{ - g_return_val_if_fail (record, 0); - return record->n_columns; -} - -static void -record_take_column (GcrRecord *record, - guint column, - GcrRecordBlock *block) -{ - g_assert (block->next == NULL); - block->next = record->block; - record->block = block; - - g_assert (column < record->n_columns); - record->columns[column] = block->value; -} - -static const char HEXC_LOWER[] = "0123456789abcdef"; - -/* Will return NULL if unescaping failed or not needed */ -static gchar * -c_colons_unescape (const gchar *source, - gsize *length) -{ - const gchar *p = source, *octal, *hex; - gchar *dest = NULL; - gchar *q = dest; - gchar *pos; - - while (*p) { - if (*p == '\\') { - if (dest == NULL) { - dest = g_malloc (strlen (source) + 1); - memcpy (dest, source, (p - source)); - q = dest + (p - source); - } - - p++; - switch (*p) { - case '\0': /* invalid trailing backslash */ - g_free (dest); - return NULL; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': - *q = 0; - octal = p; - while ((p < octal + 3) && (*p >= '0') && (*p <= '7')) { - *q = (*q * 8) + (*p - '0'); - p++; - } - q++; - p--; - break; - case 'x': - *q = 0; - hex = p; - while (p < hex + 2) { - pos = strchr (HEXC_LOWER, g_ascii_tolower (*p)); - if (pos == 0) { /* invalid bad hex character */ - g_free (dest); - return NULL; - } - *q = (*q * 16) + (pos - HEXC_LOWER); - p++; - } - q++; - p--; - break; - case 'b': - *q++ = '\b'; - break; - case 'f': - *q++ = '\f'; - break; - case 'n': - *q++ = '\n'; - break; - case 'r': - *q++ = '\r'; - break; - case 't': - *q++ = '\t'; - break; - default: /* Also handles \" and \\ */ - *q++ = *p; - break; - } - } else if (q != NULL) { - *q++ = *p; - } - p++; - } - - if (q != NULL) { - *q = 0; - if (length) - *length = q - dest; - } - - return dest; -} - -/* Will return NULL if no escaping needed */ -static gchar * -c_colons_escape (const gchar *source, - const gchar extra, - gsize *length) -{ - const guchar *p; - gchar *dest = NULL; - gchar *q = NULL; - gchar escape; - gsize off; - - g_return_val_if_fail (source != NULL, NULL); - - p = (guchar *) source; - - while (*p) { - escape = 0; - switch (*p) { - case '\b': - escape = 'b'; - break; - case '\f': - escape = 'f'; - break; - case '\n': - escape = 'n'; - break; - case '\r': - escape = 'r'; - break; - case '\t': - escape = 't'; - break; - case '\\': - escape = '\\'; - break; - case '"': - escape = '"'; - break; - } - - if (escape != 0 || *p < ' ' || *p >= 0x127 || *p == extra) { - if (dest == NULL) { - /* Each source byte needs maximally four destination chars (\xff) */ - dest = g_malloc (strlen (source) * 4 + 1); - off = (gchar *)p - source; - memcpy (dest, source, off); - q = dest + off; - } - - if (escape) { - *q++ = '\\'; - *q++ = escape; - } else { - *q++ = '\\'; - *q++ = 'x'; - *q++ = HEXC_LOWER[*p >> 4 & 0xf]; - *q++ = HEXC_LOWER[*p & 0xf]; - } - } else if (q != NULL) { - *q++ = *p; - } - p++; - } - - if (q != NULL) { - *q = 0; - if (length) - *length = q - dest; - } - - return dest; -} - -gchar* -_gcr_record_get_string (GcrRecord *record, guint column) -{ - const gchar *value; - gchar *text = NULL; - - g_return_val_if_fail (record, NULL); - - value = _gcr_record_get_raw (record, column); - if (!value) - return NULL; - - text = c_colons_unescape (value, NULL); - if (text != NULL) - value = text; - - /* If it's not UTF-8, we guess that it's latin1 */ - if (!g_utf8_validate (value, -1, NULL)) { - gchar *conv = g_convert (value, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL); - g_free (text); - value = text = conv; - } - - /* - * latin1 to utf-8 conversion can't really fail, just produce - * garbage... so there's no need to check here. - */ - - return (text == value) ? text : g_strdup (value); -} - -void -_gcr_record_set_string (GcrRecord *record, - guint column, - const gchar *string) -{ - GcrRecordBlock *block; - gchar *escaped; - - g_return_if_fail (record != NULL); - g_return_if_fail (string != NULL); - g_return_if_fail (column < record->n_columns); - - escaped = c_colons_escape (string, record->delimiter, NULL); - if (escaped != NULL) - block = record_block_take (escaped, strlen (escaped)); - else - block = record_block_new (string, strlen (string)); - - record_take_column (record, column, block); -} - -gchar -_gcr_record_get_char (GcrRecord *record, - guint column) -{ - const gchar *value; - - g_return_val_if_fail (record, 0); - - value = _gcr_record_get_raw (record, column); - if (!value) - return 0; - - if (value[0] != 0 && value[1] == 0) - return value[0]; - - return 0; -} - -void -_gcr_record_set_char (GcrRecord *record, - guint column, - gchar value) -{ - g_return_if_fail (record != NULL); - g_return_if_fail (column < record->n_columns); - g_return_if_fail (value != 0); - - record_take_column (record, column, record_block_new (&value, 1)); -} - -gboolean -_gcr_record_get_uint (GcrRecord *record, guint column, guint *value) -{ - const gchar *raw; - gint64 result; - gchar *end = NULL; - - g_return_val_if_fail (record, FALSE); - - raw = _gcr_record_get_raw (record, column); - if (raw == NULL) - return FALSE; - - result = g_ascii_strtoll (raw, &end, 10); - if (!end || end[0]) { - _gcr_debug ("invalid unsigned integer value: %s", raw); - return FALSE; - } - - if (result < 0 || result > G_MAXUINT32) { - _gcr_debug ("unsigned integer value is out of range: %s", raw); - return FALSE; - } - - if (value) - *value = (guint)result; - return TRUE; -} - -void -_gcr_record_set_uint (GcrRecord *record, - guint column, - guint value) -{ - gchar *escaped; - - g_return_if_fail (record != NULL); - g_return_if_fail (column < record->n_columns); - - escaped = g_strdup_printf ("%u", value); - record_take_column (record, column, - record_block_take (escaped, strlen (escaped))); -} - -gboolean -_gcr_record_get_ulong (GcrRecord *record, - guint column, - gulong *value) -{ - const gchar *raw; - gint64 result; - gchar *end = NULL; - - g_return_val_if_fail (record, FALSE); - - raw = _gcr_record_get_raw (record, column); - if (raw == NULL) - return FALSE; - - result = g_ascii_strtoull (raw, &end, 10); - if (!end || end[0]) { - _gcr_debug ("invalid unsigned long value: %s", raw); - return FALSE; - } - - if (result < 0 || result > G_MAXULONG) { - _gcr_debug ("unsigned long value is out of range: %s", raw); - return FALSE; - } - - if (value) - *value = (guint)result; - return TRUE; - -} - -void -_gcr_record_set_ulong (GcrRecord *record, - guint column, - gulong value) -{ - gchar *escaped; - - g_return_if_fail (record != NULL); - g_return_if_fail (column < record->n_columns); - - escaped = g_strdup_printf ("%lu", value); - record_take_column (record, column, - record_block_take (escaped, strlen (escaped))); -} - -GDateTime * -_gcr_record_get_date (GcrRecord *record, - guint column) -{ - const gchar *raw; - gulong result; - gchar *end = NULL; - struct tm tm; - - g_return_val_if_fail (record, NULL); - - raw = _gcr_record_get_raw (record, column); - if (raw == NULL) - return NULL; - - /* Try to parse as a number */ - result = strtoul (raw, &end, 10); - if (end != NULL && end[0] == '\0') - return g_date_time_new_from_unix_utc (result); - - /* Try to parse as a date */ - memset (&tm, 0, sizeof (tm)); - end = strptime (raw, "%Y-%m-%d", &tm); - if (!end || end[0]) { - _gcr_debug ("invalid date value: %s", raw); - return NULL; - } - - return g_date_time_new_utc (tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 0, 0, 0); -} - -/** - * _gcr_record_get_base64: - * @record: The record - * @column: The column to decode. - * @n_data: Location to return size of returned data. - * - * Decode a column of a record as base64 data. - * - * Returns: (transfer full): The decoded value, or %NULL if not found. - */ -gpointer -_gcr_record_get_base64 (GcrRecord *record, guint column, gsize *n_data) -{ - const gchar *raw; - - g_return_val_if_fail (record, NULL); - - raw = _gcr_record_get_raw (record, column); - if (raw == NULL) - return NULL; - - return g_base64_decode (raw, n_data); -} - -void -_gcr_record_set_base64 (GcrRecord *record, - guint column, - gconstpointer data, - gsize n_data) -{ - GcrRecordBlock *block; - gint state, save; - gsize estimate; - gsize length; - - g_return_if_fail (record != NULL); - g_return_if_fail (column < record->n_columns); - - estimate = n_data * 4 / 3 + n_data * 4 / (3 * 65) + 7; - block = record_block_new (NULL, estimate); - - /* The actual base64 data, without line breaks */ - state = save = 0; - length = g_base64_encode_step ((guchar *)data, n_data, FALSE, - block->value, &state, &save); - length += g_base64_encode_close (TRUE, block->value + length, - &state, &save); - block->value[length] = 0; - g_assert (length < estimate); - - g_strchomp (block->value); - record_take_column (record, column, block); -} - -const gchar* -_gcr_record_get_raw (GcrRecord *record, guint column) -{ - g_return_val_if_fail (record, NULL); - - if (column >= record->n_columns) { - _gcr_debug ("only %d columns exist, tried to access %d", - record->n_columns, column); - return NULL; - } - - return record->columns[column]; -} - -void -_gcr_record_set_raw (GcrRecord *record, - guint column, - const gchar *value) -{ - g_return_if_fail (record != NULL); - g_return_if_fail (value != NULL); - g_return_if_fail (column < record->n_columns); - - record_take_column (record, column, - record_block_new (value, strlen (value))); -} - -void -_gcr_record_take_raw (GcrRecord *record, - guint column, - gchar *value) -{ - g_return_if_fail (record != NULL); - g_return_if_fail (value != NULL); - g_return_if_fail (column < record->n_columns); - - record_take_column (record, column, - record_block_take (value, strlen (value))); -} - -void -_gcr_record_free (gpointer record) -{ - GcrRecordBlock *block, *next; - GcrRecord *rec = record; - - if (!record) - return; - - for (block = rec->block; block != NULL; block = next) { - next = block->next; - g_free (block); - } - - g_slice_free (GcrRecord, record); -} - -GQuark -_gcr_record_get_schema (GcrRecord *record) -{ - const gchar *value; - - value = _gcr_record_get_raw (record, GCR_RECORD_SCHEMA); - if (value != NULL) - return g_quark_try_string (value); - return 0; -} - -GcrRecord * -_gcr_records_find (GPtrArray *records, - GQuark schema) -{ - guint i; - - g_return_val_if_fail (records, NULL); - g_return_val_if_fail (schema, NULL); - - for (i = 0; i < records->len; i++) { - if (schema == _gcr_record_get_schema (records->pdata[i])) - return records->pdata[i]; - } - - return NULL; -} - -gchar * -_gcr_records_format (GPtrArray *records) -{ - GString *string; - guint i; - - g_return_val_if_fail (records, NULL); - - string = g_string_new (""); - for (i = 0; i < records->len; i++) { - print_record_to_string (records->pdata[i], string); - g_string_append_c (string, '\n'); - } - return g_string_free (string, FALSE); -} - -GPtrArray * -_gcr_records_parse_colons (gconstpointer data, - gssize n_data) -{ - GPtrArray *result = NULL; - GcrRecordBlock *block; - GcrRecord *record; - gchar **lines; - guint i; - - lines = g_strsplit (data, "\n", n_data); - result = g_ptr_array_new_with_free_func (_gcr_record_free); - - for (i = 0; lines[i] != NULL; i++) { - block = record_block_take (lines[i], strlen (lines[i])); - record = take_and_parse_internal (block, ':', TRUE); - if (record == NULL) { - g_ptr_array_unref (result); - result = NULL; - break; - } - g_ptr_array_add (result, record); - } - - /* Free any not done */ - for (; lines[i] != NULL; i++) - g_free (lines[i]); - - /* Individual lines already freed */ - g_free (lines); - - return result; -} diff --git a/gcr/gcr-record.h b/gcr/gcr-record.h deleted file mode 100644 index 37201cef..00000000 --- a/gcr/gcr-record.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef GCR_RECORD_H -#define GCR_RECORD_H - -#include <glib.h> -#include <glib-object.h> - -/* - * Gnupg's official format for listing keys is in the '--with-colons' format. - * This is documented in doc/DETAILS in the gnupg distribution. Looks like: - * - * pub:f:1024:17:6C7EE1B8621CC013:899817715:1055898235::m:::scESC: - * fpr:::::::::ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013: - * uid:f::::::::Werner Koch <wk@g10code.com>: - * uid:f::::::::Werner Koch <wk@gnupg.org>: - * sub:f:1536:16:06AD222CADF6A6E1:919537416:1036177416:::::e: - * fpr:::::::::CF8BCC4B18DE08FCD8A1615906AD222CADF6A6E1: - * sub:r:1536:20:5CE086B5B5A18FF4:899817788:1025961788:::::esc: - * fpr:::::::::AB059359A3B81F410FCFF97F5CE086B5B5A18FF4: - * - * Each row is colon delimeted, and has a certain 'schema'. The first item - * in the row tells us the schema. Then the various columns are numbered, - * (schema is zero). - */ - -G_BEGIN_DECLS - -#define GCR_RECORD_SCHEMA_ATTRIBUTE (g_quark_from_static_string ("ATTRIBUTE")) -#define GCR_RECORD_SCHEMA_IMPORT_OK (g_quark_from_static_string ("IMPORT_OK")) -#define GCR_RECORD_SCHEMA_FPR (g_quark_from_static_string ("fpr")) -#define GCR_RECORD_SCHEMA_PUB (g_quark_from_static_string ("pub")) -#define GCR_RECORD_SCHEMA_SUB (g_quark_from_static_string ("sub")) -#define GCR_RECORD_SCHEMA_SEC (g_quark_from_static_string ("sec")) -#define GCR_RECORD_SCHEMA_SSB (g_quark_from_static_string ("ssb")) -#define GCR_RECORD_SCHEMA_UID (g_quark_from_static_string ("uid")) -#define GCR_RECORD_SCHEMA_UAT (g_quark_from_static_string ("uat")) -#define GCR_RECORD_SCHEMA_XA1 (g_quark_from_static_string ("xa1")) -#define GCR_RECORD_SCHEMA_SIG (g_quark_from_static_string ("sig")) -#define GCR_RECORD_SCHEMA_RVK (g_quark_from_static_string ("rvk")) - -/* Common columns for schemas */ -typedef enum { - GCR_RECORD_SCHEMA = 0, - GCR_RECORD_TRUST = 1, -} GcrRecordColumns; - -/* - * Columns for ATTRIBUTE status message. eg: - * [GNUPG:] ATTRIBUTE FBAFC70D60AE13D560764062B547B5580EEB5A80 10604 1 1 1 1227936754 0 1 - */ -typedef enum { - GCR_RECORD_ATTRIBUTE_KEY_FINGERPRINT = 1, - GCR_RECORD_ATTRIBUTE_LENGTH = 2, - GCR_RECORD_ATTRIBUTE_TYPE = 3, - GCR_RECORD_ATTRIBUTE_TIMESTAMP = 6, - GCR_RECORD_ATTRIBUTE_EXPIRY = 7, - GCR_RECORD_ATTRIBUTE_FLAGS = 8 -} GcrRecordAttributeColumns; - -/* - * Columns for IMPORT_OK and IMPORT_PROBLEM status message. eg: - * [GNUPG:] IMPORT_OK 1 6BD9050FD8FC941B43412DCC68B7AB8957548DCD - * [GNUPG:] IMPORT_PROBLEM 1 - */ -typedef enum { - GCR_RECORD_IMPORT_REASON = 1, - GCR_RECORD_IMPORT_FINGERPRINT -} GcrRecordImportColumns; - -/* - * Columns for fpr schema, add them as they're used. eg: - * fpr:::::::::ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013: - */ -typedef enum { - GCR_RECORD_FPR_FINGERPRINT = 9, - GCR_RECORD_FPR_MAX = 10 -} GcrRecordFprColumns; - -/* - * Columns for pub, sec, sub, and ssb schemas. eg: - * pub:f:1024:17:6C7EE1B8621CC013:899817715:1055898235::m:::scESC: - */ -typedef enum { - GCR_RECORD_KEY_BITS = 2, - GCR_RECORD_KEY_ALGO = 3, - GCR_RECORD_KEY_KEYID = 4, - GCR_RECORD_KEY_TIMESTAMP = 5, - GCR_RECORD_KEY_EXPIRY = 6, - GCR_RECORD_KEY_OWNERTRUST = 8, -} GcrRecordKeyColumns; - -typedef enum { - GCR_RECORD_PUB_CAPS = 11, - GCR_RECORD_PUB_MAX = 12 -} GcrRecordPubColumns; - -typedef enum { - GCR_RECORD_SEC_MAX = 15 -} GcrRecordSecColumns; - -/* - * Columns for uid schema, add them as they're used. eg: - * uid:u::::1024442705::7A5C6648DAA1F5D12BD80BBED538439ABAFEE203::Test <test@example.com>: - */ -typedef enum { - GCR_RECORD_UID_TIMESTAMP = 5, - GCR_RECORD_UID_EXPIRY = 6, - GCR_RECORD_UID_FINGERPRINT = 7, - GCR_RECORD_UID_USERID = 9, - GCR_RECORD_UID_MAX = 10, -} GcrRecordUidColumns; - -/* - * Columns for sig schema. eg: - * sig:::17:FAD3A86D2505A4D5:1291829838::::Stef Walter <stefw@servingtfi.com>:10x: - */ -typedef enum { - GCR_RECORD_SIG_STATUS = 1, - GCR_RECORD_SIG_ALGO = 3, - GCR_RECORD_SIG_KEYID = 4, - GCR_RECORD_SIG_TIMESTAMP = 5, - GCR_RECORD_SIG_EXPIRY = 6, - GCR_RECORD_SIG_USERID = 9, - GCR_RECORD_SIG_CLASS = 10, - GCR_RECORD_SIG_MAX = 11, -} GcrRecordSigColumns; - -/* - * Columns for rvk schema. eg: - * rvk:::17::::::3FC732041D23E9EA66DDB5009C9DBC21DF74DC61:80: - */ -typedef enum { - GCR_RECORD_RVK_ALGO = 3, - GCR_RECORD_RVK_FINGERPRINT = 9, - GCR_RECORD_RVK_CLASS = 10, - GCR_RECORD_RVK_MAX = 11, -} GcrRecordRvkColumns; - -/* - * Columns for uat schema, add them as they're used. eg: - * uat:u::::1024442705::7A5C6648DAA1F5D12BD80BBED538439ABAFEE203::1 3233: - */ -typedef enum { - GCR_RECORD_UAT_TRUST = 1, - GCR_RECORD_UAT_FINGERPRINT = 7, - GCR_RECORD_UAT_COUNT_SIZE = 9, - GCR_RECORD_UAT_MAX = 10, -} GcrRecordUatColumns; - -/* - * Columns for xa1 schema. This is a schema that we've invented ourselves - * for representing the actual data of openpgp attribute packets. eg: - * xa1:e:10838:1:::1998-02-02:0:ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013::... - */ -typedef enum { - GCR_RECORD_XA1_TRUST = 1, - GCR_RECORD_XA1_LENGTH = 2, - GCR_RECORD_XA1_TYPE = 3, - GCR_RECORD_XA1_TIMESTAMP = 5, - GCR_RECORD_XA1_EXPIRY = 6, - GCR_RECORD_XA1_FINGERPRINT = 7, - GCR_RECORD_XA1_DATA = 9, - GCR_RECORD_XA1_MAX = 11, -} GcrRecordXa1Columns; - -typedef struct _GcrRecord GcrRecord; - -#define GCR_TYPE_RECORD (_gcr_record_get_type ()) - -GType _gcr_record_get_type (void) G_GNUC_CONST; - -GcrRecord * _gcr_record_new (GQuark schema, - guint n_columns, - gchar delimiter); - -GcrRecord* _gcr_record_copy (GcrRecord *record); - -GcrRecord* _gcr_record_parse_colons (const gchar *line, - gssize n_line); - -GcrRecord* _gcr_record_parse_spaces (const gchar *line, - gssize n_line); - -gchar * _gcr_record_format (GcrRecord *record); - -void _gcr_record_free (gpointer record); - -guint _gcr_record_get_count (GcrRecord *record); - -gchar _gcr_record_get_char (GcrRecord *record, - guint column); - -void _gcr_record_set_char (GcrRecord *record, - guint column, - gchar value); - -gchar* _gcr_record_get_string (GcrRecord *record, - guint column); - -void _gcr_record_set_string (GcrRecord *record, - guint column, - const gchar *value); - -gboolean _gcr_record_get_uint (GcrRecord *record, - guint column, - guint *value); - -void _gcr_record_set_uint (GcrRecord *record, - guint column, - guint value); - -gboolean _gcr_record_get_ulong (GcrRecord *record, - guint column, - gulong *value); - -void _gcr_record_set_ulong (GcrRecord *record, - guint column, - gulong value); - -GDateTime * _gcr_record_get_date (GcrRecord *record, - guint column); - -gpointer _gcr_record_get_base64 (GcrRecord *record, - guint column, - gsize *n_data); - -void _gcr_record_set_base64 (GcrRecord *record, - guint column, - gconstpointer data, - gsize n_data); - -const gchar* _gcr_record_get_raw (GcrRecord *record, - guint column); - -void _gcr_record_set_raw (GcrRecord *record, - guint column, - const gchar *value); - -void _gcr_record_take_raw (GcrRecord *record, - guint column, - gchar *value); - -GQuark _gcr_record_get_schema (GcrRecord *record); - -GPtrArray * _gcr_records_parse_colons (gconstpointer data, - gssize n_data); - -gchar * _gcr_records_format (GPtrArray *records); - -GcrRecord * _gcr_records_find (GPtrArray *records, - GQuark schema); - -G_END_DECLS - -#endif /* GCR_RECORD_H */ diff --git a/gcr/gcr-renderer.c b/gcr/gcr-renderer.c deleted file mode 100644 index c98376b5..00000000 --- a/gcr/gcr-renderer.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-deprecated.h" -#include "gcr-renderer.h" - -#include "gcr-certificate-renderer.h" -#include "gcr-gnupg-renderer.h" -#include "gcr-key-renderer.h" - -#include "gck/gck.h" - -#include <gtk/gtk.h> - -/** - * SECTION:gcr-renderer - * @title: GcrRenderer - * @short_description: An interface implemented by renderers. - * - * A #GcrRenderer is an interface that's implemented by renderers which wish - * to render data to a #GcrViewer. - * - * The interaction between #GcrRenderer and #GcrViewer is not stable yet, and - * so new renderers cannot be implemented outside the Gcr library at this time. - * - * To lookup a renderer for a given set of attributes, use the gcr_renderer_create() - * function. This will create and initialize a renderer that's capable of viewing - * the data in those attributes. - */ - -/** - * GcrRenderer: - * - * A renderer. - */ - -/** - * GcrRendererIface: - * @parent: the parent interface type - * @data_changed: signal emitted when data being rendered changes - * @render_view: method invoked to render the data into a viewer - * @populate_popup: method invoked to populate a popup menu with additional - * renderer options - * - * The interface for #GcrRenderer - */ - -enum { - DATA_CHANGED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -typedef struct _GcrRegistered { - GckAttributes *attrs; - GType renderer_type; -} GcrRegistered; - -static GArray *registered_renderers = NULL; -static gboolean registered_sorted = FALSE; - -static void -gcr_renderer_default_init (GcrRendererIface *iface) -{ - static gboolean initialized = FALSE; - if (!initialized) { - - /** - * GcrRenderer:label: - * - * The label to display. - */ - g_object_interface_install_property (iface, - g_param_spec_string ("label", "Label", "The label for the renderer", - "", G_PARAM_READWRITE)); - - /** - * GcrRenderer:attributes: - * - * The attributes to display. - */ - g_object_interface_install_property (iface, - g_param_spec_boxed ("attributes", "Attributes", "The data displayed in the renderer", - GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE)); - - /** - * GcrRenderer::data-changed: - * - * A signal that is emitted by the renderer when it's data - * changed and should be rerendered. - */ - signals[DATA_CHANGED] = g_signal_new ("data-changed", GCR_TYPE_RENDERER, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GcrRendererIface, data_changed), - NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - - initialized = TRUE; - } -} - -typedef GcrRendererIface GcrRendererInterface; - -G_DEFINE_INTERFACE (GcrRenderer, gcr_renderer, G_TYPE_OBJECT); - -/** - * gcr_renderer_render_view: - * @self: The renderer - * @viewer: The viewer to render to. - * - * Render the contents of the renderer to the given viewer. - */ -void -gcr_renderer_render_view (GcrRenderer *self, GcrViewer *viewer) -{ - g_return_if_fail (GCR_IS_RENDERER (self)); - g_return_if_fail (GCR_RENDERER_GET_INTERFACE (self)->render_view); - GCR_RENDERER_GET_INTERFACE (self)->render_view (self, viewer); -} - -/** - * gcr_renderer_render: - * @self: the renderer - * @viewer: the viewer to render to - * - * Render a renderer to the viewer. - * - * Deprecated: 3.2: Use gcr_renderer_render_view() instead - */ -void -gcr_renderer_render (GcrRenderer *self, - GcrViewer *viewer) -{ - gcr_renderer_render_view (self, viewer); -} - -/** - * gcr_renderer_popuplate_popup: - * @self: The renderer - * @viewer: The viewer that is displaying a popup - * @menu: The popup menu being displayed - * - * Called by #GcrViewer when about to display a popup menu for the content - * displayed by the renderer. The renderer can add a menu item if desired. - */ -void -gcr_renderer_popuplate_popup (GcrRenderer *self, GcrViewer *viewer, - GtkMenu *menu) -{ - g_return_if_fail (GCR_IS_RENDERER (self)); - if (GCR_RENDERER_GET_INTERFACE (self)->populate_popup) - GCR_RENDERER_GET_INTERFACE (self)->populate_popup (self, viewer, menu); -} - -/** - * gcr_renderer_emit_data_changed: - * @self: The renderer - * - * Emit the GcrRenderer::data-changed signal on the renderer. This is used by - * renderer implementations. - */ -void -gcr_renderer_emit_data_changed (GcrRenderer *self) -{ - g_return_if_fail (GCR_IS_RENDERER (self)); - g_signal_emit (self, signals[DATA_CHANGED], 0); -} - -static gint -sort_registered_by_n_attrs (gconstpointer a, gconstpointer b) -{ - const GcrRegistered *ra = a; - const GcrRegistered *rb = b; - gulong na, nb; - - g_assert (a); - g_assert (b); - - na = gck_attributes_count (ra->attrs); - nb = gck_attributes_count (rb->attrs); - - /* Note we're sorting in reverse order */ - if (na < nb) - return 1; - return (na == nb) ? 0 : -1; -} - -/** - * gcr_renderer_create: - * @label: (allow-none): The label for the renderer - * @attrs: The attributes to render - * - * Create and initialize a renderer for the given attributes and label. These - * renderers should have been preregistered via gcr_renderer_register(). - * - * Returns: (transfer full) (allow-none): a new renderer, or %NULL if no renderer - * matched the attributes; the render should be released with g_object_unref() - */ -GcrRenderer * -gcr_renderer_create (const gchar *label, GckAttributes *attrs) -{ - GcrRegistered *registered; - gboolean matched; - gulong n_attrs; - gulong j; - gsize i; - - g_return_val_if_fail (attrs, NULL); - - gcr_renderer_register_well_known (); - - if (!registered_renderers) - return NULL; - - if (!registered_sorted) { - g_array_sort (registered_renderers, sort_registered_by_n_attrs); - registered_sorted = TRUE; - } - - for (i = 0; i < registered_renderers->len; ++i) { - registered = &(g_array_index (registered_renderers, GcrRegistered, i)); - n_attrs = gck_attributes_count (registered->attrs); - - matched = TRUE; - - for (j = 0; j < n_attrs; ++j) { - if (!gck_attributes_contains (attrs, gck_attributes_at (registered->attrs, j))) { - matched = FALSE; - break; - } - } - - if (matched) - return g_object_new (registered->renderer_type, "label", label, - "attributes", attrs, NULL); - } - - return NULL; -} - -/** - * gcr_renderer_register: - * @renderer_type: The renderer class type - * @attrs: The attributes to match - * - * Register a renderer to be created when matching attributes are passed to - * gcr_renderer_create(). - */ -void -gcr_renderer_register (GType renderer_type, GckAttributes *attrs) -{ - GcrRegistered registered; - - if (!registered_renderers) - registered_renderers = g_array_new (FALSE, FALSE, sizeof (GcrRegistered)); - - registered.renderer_type = renderer_type; - registered.attrs = gck_attributes_ref (attrs); - g_array_append_val (registered_renderers, registered); - registered_sorted = FALSE; -} - -/** - * gcr_renderer_register_well_known: - * - * Register all the well known renderers for certificates and keys known to the - * Gcr library. - */ -void -gcr_renderer_register_well_known (void) -{ - g_type_class_unref (g_type_class_ref (GCR_TYPE_CERTIFICATE_RENDERER)); - g_type_class_unref (g_type_class_ref (GCR_TYPE_KEY_RENDERER)); - g_type_class_unref (g_type_class_ref (GCR_TYPE_GNUPG_RENDERER)); -} diff --git a/gcr/gcr-renderer.h b/gcr/gcr-renderer.h deleted file mode 100644 index 4223ce66..00000000 --- a/gcr/gcr-renderer.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_RENDERER_H__ -#define __GCR_RENDERER_H__ - -#include <glib-object.h> - -#include "gcr-column.h" -#include "gcr-types.h" -#include "gcr-viewer.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_RENDERER (gcr_renderer_get_type()) -#define GCR_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_RENDERER, GcrRenderer)) -#define GCR_IS_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_RENDERER)) -#define GCR_RENDERER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_RENDERER, GcrRendererIface)) - -typedef struct _GcrRenderer GcrRenderer; -typedef struct _GcrRendererIface GcrRendererIface; - -struct _GcrRendererIface { - GTypeInterface parent; - - /* signals */ - void (*data_changed) (GcrRenderer *self); - - /* virtual */ - void (*render_view) (GcrRenderer *self, GcrViewer *viewer); - - void (*populate_popup) (GcrRenderer *self, GcrViewer *viewer, GtkMenu *menu); - - /*< private >*/ - gpointer dummy1; - - gpointer dummy2; - gpointer dummy3; - gpointer dummy4; - gpointer dummy5; - gpointer dummy6; - gpointer dummy7; - -}; - -GType gcr_renderer_get_type (void) G_GNUC_CONST; - -void gcr_renderer_render_view (GcrRenderer *self, - GcrViewer *viewer); - -void gcr_renderer_popuplate_popup (GcrRenderer *self, - GcrViewer *viewer, - GtkMenu *menu); - -void gcr_renderer_emit_data_changed (GcrRenderer *self); - -GcrRenderer* gcr_renderer_create (const gchar *label, - GckAttributes *attrs); - -void gcr_renderer_register (GType renderer_type, - GckAttributes *attrs); - -void gcr_renderer_register_well_known (void); - -G_END_DECLS - -#endif /* __GCR_RENDERER_H__ */ diff --git a/gcr/gcr-secret-exchange.c b/gcr/gcr-secret-exchange.c deleted file mode 100644 index 92899ad4..00000000 --- a/gcr/gcr-secret-exchange.c +++ /dev/null @@ -1,848 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-secret-exchange.h" - -#include "egg/egg-dh.h" -#include "egg/egg-hkdf.h" -#include "egg/egg-libgcrypt.h" -#include "egg/egg-padding.h" -#include "egg/egg-secure-memory.h" - -#include <string.h> -#include <gcrypt.h> - -EGG_SECURE_DECLARE (secret_exchange); - -/** - * SECTION:gcr-secret-exchange - * @title: GcrSecretExchange - * @short_description: Exchange secrets between processes in an unexposed way. - * - * Allows exchange of secrets between two processes on the same system without - * exposing those secrets to things like loggers, non-pageable memory etc. - * - * This does not protect against active attacks like MITM attacks. - * - * Each side creates a #GcrSecretExchange object, and one of the sides calls - * gcr_secret_exchange_begin(). This creates a string, which should be passed - * to the other side. Each side passes the strings it receives into - * gcr_secret_exchange_receive(). - * - * In order to send a reply (either with or without a secret) use - * gcr_secret_exchange_send(). A side must have had gcr_secret_exchange_receive() - * successfully called before it can use gcr_secret_exchange_send(). - * - * The #GcrSecretExchange objects can be used for multiple iterations of the - * conversation, or for just one request/reply. The only limitation being that - * the initial request cannot contain a secret. - * - * Caveat: Information about the approximate length (rounded up to the nearest - * 16 bytes) may be leaked. If this is considered inacceptable, do not use - * #GcrSecretExchange. - */ - -/** - * GcrSecretExchange: - * - * An object representing one side of a secret exchange. - */ - -/** - * GcrSecretExchangeClass: - * - * The class for #GcrSecretExchange - */ - -/** - * GCR_SECRET_EXCHANGE_PROTOCOL_1: - * - * The current secret exchange protocol. Key agreement is done using DH with the - * 1536 bit IKE parameter group. Keys are derived using SHA256 with HKDF. The - * transport encryption is done with 128 bit AES. - */ - -#define SECRET_EXCHANGE_PROTOCOL_1_PREFIX "[" GCR_SECRET_EXCHANGE_PROTOCOL_1 "]\n" - -enum { - PROP_0, - PROP_PROTOCOL -}; - -typedef struct _GcrSecretExchangeDefault GcrSecretExchangeDefault; - -struct _GcrSecretExchangePrivate { - GcrSecretExchangeDefault *default_exchange; - GDestroyNotify destroy_exchange; - gboolean explicit_protocol; - gboolean generated; - guchar *publi; - gsize n_publi; - gboolean derived; - gchar *secret; - gsize n_secret; -}; - -G_DEFINE_TYPE (GcrSecretExchange, gcr_secret_exchange, G_TYPE_OBJECT); - -static void -key_file_set_base64 (GKeyFile *key_file, const gchar *section, - const gchar *field, gconstpointer data, gsize n_data) -{ - gchar *value; - - value = g_base64_encode (data, n_data); - g_key_file_set_value (key_file, section, field, value); - g_free (value); -} - -static gpointer -key_file_get_base64 (GKeyFile *key_file, const gchar *section, - const gchar *field, gsize *n_result) -{ - gpointer result = NULL; - gchar *data; - - g_return_val_if_fail (key_file, NULL); - g_return_val_if_fail (section, NULL); - g_return_val_if_fail (field, NULL); - g_return_val_if_fail (n_result, NULL); - - data = g_key_file_get_value (key_file, section, field, NULL); - if (data != NULL) - result = g_base64_decode (data, n_result); - g_free (data); - return result; -} - -static void -gcr_secret_exchange_init (GcrSecretExchange *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_SECRET_EXCHANGE, - GcrSecretExchangePrivate); -} - - -static void -gcr_secret_exchange_set_property (GObject *obj, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GcrSecretExchange *self = GCR_SECRET_EXCHANGE (obj); - const gchar *protocol; - - switch (prop_id) { - case PROP_PROTOCOL: - protocol = g_value_get_string (value); - if (protocol != NULL) { - if (g_str_equal (protocol, GCR_SECRET_EXCHANGE_PROTOCOL_1)) - self->pv->explicit_protocol = TRUE; - else - g_warning ("the GcrSecretExchange protocol %s is unsupported defaulting to %s", - protocol, GCR_SECRET_EXCHANGE_PROTOCOL_1); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_secret_exchange_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GcrSecretExchange *self = GCR_SECRET_EXCHANGE (obj); - - switch (prop_id) { - case PROP_PROTOCOL: - g_value_set_string (value, gcr_secret_exchange_get_protocol (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -clear_secret_exchange (GcrSecretExchange *self) -{ - g_free (self->pv->publi); - self->pv->publi = NULL; - self->pv->n_publi = 0; - self->pv->derived = FALSE; - self->pv->generated = TRUE; - egg_secure_free (self->pv->secret); - self->pv->secret = NULL; - self->pv->n_secret = 0; -} - -static void -gcr_secret_exchange_finalize (GObject *obj) -{ - GcrSecretExchange *self = GCR_SECRET_EXCHANGE (obj); - - if (self->pv->destroy_exchange) - (self->pv->destroy_exchange) (self->pv->default_exchange); - - clear_secret_exchange (self); - - G_OBJECT_CLASS (gcr_secret_exchange_parent_class)->finalize (obj); -} - -/** - * gcr_secret_exchange_new: - * @protocol: (allow-none): the exchange protocol to use - * - * Create a new secret exchange object. - * - * Specify a protocol of %NULL to allow any protocol. This is especially - * relevant on the side of the exchange that does not call - * gcr_secret_exchange_begin(), that is the originator. Currently the only - * protocol supported is %GCR_SECRET_EXCHANGE_PROTOCOL_1. - * - * Returns: (transfer full): A new #GcrSecretExchange object - */ -GcrSecretExchange * -gcr_secret_exchange_new (const gchar *protocol) -{ - return g_object_new (GCR_TYPE_SECRET_EXCHANGE, - "protocol", protocol, - NULL); -} - -/** - * gcr_secret_exchange_get_protocol: - * @self: a #GcrSecretExchange object - * Get the secret exchange protocol. - * - * Will return %NULL if no protocol was specified, and either - * gcr_secret_exchange_begin() or gcr_secret_exchange_receive() have not been - * called successfully. - * - * Returns: the protocol or %NULL - */ -const gchar * -gcr_secret_exchange_get_protocol (GcrSecretExchange *self) -{ - g_return_val_if_fail (GCR_IS_SECRET_EXCHANGE (self), NULL); - if (self->pv->explicit_protocol || self->pv->generated) - return GCR_SECRET_EXCHANGE_PROTOCOL_1; - return NULL; -} - -/** - * gcr_secret_exchange_begin: - * @self: a #GcrSecretExchange object - * - * Begin the secret exchange. The resulting string should be sent to the other - * side of the exchange. The other side should use gcr_secret_exchange_receive() - * to process the string. - * - * Returns: (transfer full): A newly allocated string to be sent to the other - * side of the secret exchange - */ -gchar * -gcr_secret_exchange_begin (GcrSecretExchange *self) -{ - GcrSecretExchangeClass *klass; - GKeyFile *output; - gchar *result; - - g_return_val_if_fail (GCR_IS_SECRET_EXCHANGE (self), NULL); - - klass = GCR_SECRET_EXCHANGE_GET_CLASS (self); - g_return_val_if_fail (klass->generate_exchange_key, NULL); - - clear_secret_exchange (self); - - output = g_key_file_new (); - - if (!(klass->generate_exchange_key) (self, GCR_SECRET_EXCHANGE_PROTOCOL_1, - &self->pv->publi, &self->pv->n_publi)) - g_return_val_if_reached (NULL); - self->pv->generated = TRUE; - - key_file_set_base64 (output, GCR_SECRET_EXCHANGE_PROTOCOL_1, "public", - self->pv->publi, self->pv->n_publi); - - result = g_key_file_to_data (output, NULL, NULL); - g_return_val_if_fail (result != NULL, NULL); - - g_strchomp (result); - - if (g_str_has_prefix (result, SECRET_EXCHANGE_PROTOCOL_1_PREFIX)) - g_warning ("the prepared data does not have the correct protocol prefix"); - - g_key_file_free (output); - - return result; -} - -static gboolean -derive_key (GcrSecretExchange *self, - GKeyFile *input) -{ - GcrSecretExchangeClass *klass; - gboolean ret; - guchar *peer; - gsize n_peer; - - klass = GCR_SECRET_EXCHANGE_GET_CLASS (self); - g_return_val_if_fail (klass->derive_transport_key, FALSE); - - peer = key_file_get_base64 (input, GCR_SECRET_EXCHANGE_PROTOCOL_1, "public", &n_peer); - if (peer == NULL) { - g_message ("secret-exchange: invalid or missing 'public' argument"); - return FALSE; - } - - ret = (klass->derive_transport_key) (self, peer, n_peer); - self->pv->derived = ret; - - g_free (peer); - return ret; -} - -static gboolean -perform_decrypt (GcrSecretExchange *self, - GKeyFile *input, - guchar **secret, - gsize *n_secret) -{ - GcrSecretExchangeClass *klass; - gpointer iv, value; - guchar *result; - gsize n_result, n_iv, n_value; - gboolean ret; - - klass = GCR_SECRET_EXCHANGE_GET_CLASS (self); - g_return_val_if_fail (klass->decrypt_transport_data, FALSE); - - iv = key_file_get_base64 (input, GCR_SECRET_EXCHANGE_PROTOCOL_1, "iv", &n_iv); - - value = key_file_get_base64 (input, GCR_SECRET_EXCHANGE_PROTOCOL_1, "secret", &n_value); - if (value == NULL) { - g_message ("secret-exchange: invalid or missing value"); - g_free (iv); - return FALSE; - } - - ret = (klass->decrypt_transport_data) (self, egg_secure_realloc, value, n_value, - iv, n_iv, &result, &n_result); - - g_free (value); - g_free (iv); - - if (!ret) - return FALSE; - - /* Reallocate a null terminator */ - if (result) { - result = egg_secure_realloc (result, n_result + 1); - result[n_result] = 0; - } - - *secret = result; - *n_secret = n_result; - - return TRUE; -} - -/** - * gcr_secret_exchange_receive: - * @self: a #GcrSecretExchange object - * @exchange: the string received - * - * Receive a string from the other side of secret exchange. This string will - * have been created by gcr_secret_exchange_begin() or gcr_secret_exchange_send() - * - * Returns: whether the string was successfully parsed and received - */ -gboolean -gcr_secret_exchange_receive (GcrSecretExchange *self, - const gchar *exchange) -{ - GcrSecretExchangeClass *klass; - GKeyFile *input; - gchar *secret; - gsize n_secret; - gboolean ret; - - g_return_val_if_fail (GCR_IS_SECRET_EXCHANGE (self), FALSE); - g_return_val_if_fail (exchange != NULL, FALSE); - - klass = GCR_SECRET_EXCHANGE_GET_CLASS (self); - g_return_val_if_fail (klass->generate_exchange_key, FALSE); - g_return_val_if_fail (klass->derive_transport_key, FALSE); - - /* Parse the input */ - input = g_key_file_new (); - if (!g_key_file_load_from_data (input, exchange, strlen (exchange), - G_KEY_FILE_NONE, NULL)) { - g_key_file_free (input); - g_message ("couldn't parse secret exchange data"); - return FALSE; - } - - if (!self->pv->generated) { - if (!(klass->generate_exchange_key) (self, GCR_SECRET_EXCHANGE_PROTOCOL_1, - &self->pv->publi, &self->pv->n_publi)) - g_return_val_if_reached (FALSE); - self->pv->generated = TRUE; - } - - if (!self->pv->derived) { - if (!derive_key (self, input)) - return FALSE; - } - - ret = TRUE; - - if (g_key_file_has_key (input, GCR_SECRET_EXCHANGE_PROTOCOL_1, "secret", NULL)) { - - /* Remember that this can return a NULL secret */ - if (!perform_decrypt (self, input, (guchar **)&secret, &n_secret)) { - ret = FALSE; - } else { - egg_secure_free (self->pv->secret); - self->pv->secret = secret; - self->pv->n_secret = n_secret; - } - } - - return ret; -} - -/** - * gcr_secret_exchange_get_secret: - * @self: a #GcrSecretExchange object - * @secret_len: (allow-none): optionally, a location to store the length of returned secret - * - * Returns the last secret received. If no secret has yet been received this - * will return %NULL. The string is owned by the #GcrSecretExchange object - * and will be valid until the next time that gcr_secret_exchange_receive() - * is called on this object, or the object is destroyed. - * - * Depending on the secret passed into the other side of the secret exchange, - * the resurt may be a binary string. It does however have a null terminator, - * so if you're certain that it is does not contain arbitrary binary data, - * it can be used as a string. - * - * Returns: (transfer none) (array length=secret_len): the last secret received - */ -const gchar * -gcr_secret_exchange_get_secret (GcrSecretExchange *self, - gsize *secret_len) -{ - g_return_val_if_fail (GCR_IS_SECRET_EXCHANGE (self), NULL); - - if (secret_len) - *secret_len = self->pv->n_secret; - return self->pv->secret; -} - -static gboolean -perform_encrypt (GcrSecretExchange *self, - GKeyFile *output, - const gchar *secret, - gsize n_secret) -{ - GcrSecretExchangeClass *klass; - guchar *result, *iv; - gsize n_result, n_iv; - - klass = GCR_SECRET_EXCHANGE_GET_CLASS (self); - g_return_val_if_fail (klass->encrypt_transport_data, FALSE); - - if (!(klass->encrypt_transport_data) (self, g_realloc, (const guchar *)secret, - n_secret, &iv, &n_iv, &result, &n_result)) - return FALSE; - - key_file_set_base64 (output, GCR_SECRET_EXCHANGE_PROTOCOL_1, "secret", result, n_result); - key_file_set_base64 (output, GCR_SECRET_EXCHANGE_PROTOCOL_1, "iv", iv, n_iv); - - g_free (result); - g_free (iv); - - return TRUE; -} - -/** - * gcr_secret_exchange_send: - * @self: a #GcrSecretExchange object - * @secret: (allow-none): optionally, a secret to send to the other side - * @secret_len: length of @secret, or -1 if null terminated - * - * Send a reply to the other side of the secret exchange, optionally sending a - * secret. - * - * gcr_secret_exchange_receive() must have been successfully called at least - * once on this object. In other words this object must have received data - * from the other side of the secret exchange, before we can send a secret. - * - * Returns: (transfer full): a newly allocated string to be sent to the other - * side of the secret exchange - */ -gchar * -gcr_secret_exchange_send (GcrSecretExchange *self, - const gchar *secret, - gssize secret_len) -{ - GKeyFile *output; - gchar *result; - - g_return_val_if_fail (GCR_IS_SECRET_EXCHANGE (self), NULL); - - if (!self->pv->derived) { - g_warning ("gcr_secret_exchange_receive() must be called " - "before calling this function"); - return NULL; - } - - output = g_key_file_new (); - key_file_set_base64 (output, GCR_SECRET_EXCHANGE_PROTOCOL_1, "public", self->pv->publi, - self->pv->n_publi); - - if (secret != NULL) { - if (secret_len < 0) - secret_len = strlen (secret); - if (!perform_encrypt (self, output, secret, secret_len)) { - g_key_file_free (output); - return NULL; - } - } - - result = g_key_file_to_data (output, NULL, NULL); - g_return_val_if_fail (result != NULL, NULL); - - g_strchomp (result); - - if (g_str_has_prefix (result, SECRET_EXCHANGE_PROTOCOL_1_PREFIX)) - g_warning ("the prepared data does not have the correct protocol prefix"); - - g_key_file_free (output); - return result; -} - -/* - * This is the only set we support so far. It includes: - * - DH with the 1536 ike modp group for key exchange - * - HKDF SHA256 for hashing of the key to appropriate size - * - AES 128 CBC for encryption - * - PKCS#7 style padding - */ - -#define EXCHANGE_1_IKE_NAME "ietf-ike-grp-modp-1536" -#define EXCHANGE_1_KEY_LENGTH 16 -#define EXCHANGE_1_IV_LENGTH 16 -#define EXCHANGE_1_HASH_ALGO "sha256" -#define EXCHANGE_1_CIPHER_ALGO GCRY_CIPHER_AES128 -#define EXCHANGE_1_CIPHER_MODE GCRY_CIPHER_MODE_CBC - -struct _GcrSecretExchangeDefault { - gcry_mpi_t prime; - gcry_mpi_t base; - gcry_mpi_t pub; - gcry_mpi_t priv; - gpointer key; -}; - -static guchar * -mpi_to_data (gcry_mpi_t mpi, - gsize *n_data) -{ - gcry_error_t gcry; - guchar *data; - - /* Get the size */ - gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, n_data, mpi); - g_return_val_if_fail (gcry == 0, NULL); - - data = g_malloc0 (*n_data); - - /* Write into buffer */ - gcry = gcry_mpi_print (GCRYMPI_FMT_USG, data, *n_data, n_data, mpi); - g_return_val_if_fail (gcry == 0, NULL); - - return data; -} - -static gcry_mpi_t -mpi_from_data (const guchar *data, - gsize n_data) -{ - gcry_mpi_t mpi; - gcry_error_t gcry; - - gcry = gcry_mpi_scan (&mpi, GCRYMPI_FMT_USG, data, n_data, NULL); - return (gcry == 0) ? mpi : NULL; -} - -static void -gcr_secret_exchange_default_free (gpointer to_free) -{ - GcrSecretExchangeDefault *data = to_free; - gcry_mpi_release (data->prime); - gcry_mpi_release (data->base); - gcry_mpi_release (data->pub); - gcry_mpi_release (data->priv); - if (data->key) { - egg_secure_clear (data->key, EXCHANGE_1_KEY_LENGTH); - egg_secure_free (data->key); - } - g_free (data); -} - -static gboolean -gcr_secret_exchange_default_generate_exchange_key (GcrSecretExchange *exchange, - const gchar *scheme, - guchar **public_key, - gsize *n_public_key) -{ - GcrSecretExchangeDefault *data = exchange->pv->default_exchange; - - if (data == NULL) { - data = g_new0 (GcrSecretExchangeDefault, 1); - if (!egg_dh_default_params (EXCHANGE_1_IKE_NAME, &data->prime, &data->base)) - g_return_val_if_reached (FALSE); - - exchange->pv->default_exchange = data; - exchange->pv->destroy_exchange = gcr_secret_exchange_default_free; - } - - gcry_mpi_release (data->priv); - data->priv = NULL; - gcry_mpi_release (data->pub); - data->pub = NULL; - egg_secure_free (data->key); - data->key = NULL; - - if (!egg_dh_gen_pair (data->prime, data->base, 0, - &data->pub, &data->priv)) - g_return_val_if_reached (FALSE); - - *public_key = mpi_to_data (data->pub, n_public_key); - return *public_key != NULL; -} - -static gboolean -gcr_secret_exchange_default_derive_transport_key (GcrSecretExchange *exchange, - const guchar *peer, - gsize n_peer) -{ - GcrSecretExchangeDefault *data = exchange->pv->default_exchange; - gpointer ikm; - gsize n_ikm; - gcry_mpi_t mpi; - - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (data->priv != NULL, FALSE); - - mpi = mpi_from_data (peer, n_peer); - if (mpi == NULL) - return FALSE; - - /* Build up a key we can use */ - ikm = egg_dh_gen_secret (mpi, data->priv, data->prime, &n_ikm); - g_return_val_if_fail (ikm != NULL, FALSE); - - if (data->key == NULL) - data->key = egg_secure_alloc (EXCHANGE_1_KEY_LENGTH); - - if (!egg_hkdf_perform (EXCHANGE_1_HASH_ALGO, ikm, n_ikm, NULL, 0, - NULL, 0, data->key, EXCHANGE_1_KEY_LENGTH)) - g_return_val_if_reached (FALSE); - - egg_secure_free (ikm); - gcry_mpi_release (mpi); - - return TRUE; -} - -static gboolean -gcr_secret_exchange_default_encrypt_transport_data (GcrSecretExchange *exchange, - GckAllocator allocator, - const guchar *plain_text, - gsize n_plain_text, - guchar **iv, - gsize *n_iv, - guchar **cipher_text, - gsize *n_cipher_text) -{ - GcrSecretExchangeDefault *data = exchange->pv->default_exchange; - gcry_cipher_hd_t cih; - gcry_error_t gcry; - guchar *padded; - gsize n_result; - guchar *result; - gsize pos; - - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (data->key != NULL, FALSE); - - gcry = gcry_cipher_open (&cih, EXCHANGE_1_CIPHER_ALGO, EXCHANGE_1_CIPHER_MODE, 0); - if (gcry != 0) { - g_warning ("couldn't create aes cipher context: %s", gcry_strerror (gcry)); - g_free (iv); - return FALSE; - } - - *iv = (allocator) (NULL, EXCHANGE_1_IV_LENGTH); - g_return_val_if_fail (*iv != NULL, FALSE); - gcry_create_nonce (*iv, EXCHANGE_1_IV_LENGTH); - *n_iv = EXCHANGE_1_IV_LENGTH; - - /* 16 = 128 bits */ - gcry = gcry_cipher_setkey (cih, data->key, EXCHANGE_1_KEY_LENGTH); - g_return_val_if_fail (gcry == 0, FALSE); - - /* 16 = 128 bits */ - gcry = gcry_cipher_setiv (cih, *iv, EXCHANGE_1_IV_LENGTH); - g_return_val_if_fail (gcry == 0, FALSE); - - /* Pad the text properly */ - if (!egg_padding_pkcs7_pad (egg_secure_realloc, 16, plain_text, n_plain_text, - (gpointer*)&padded, &n_result)) - g_return_val_if_reached (FALSE); - result = (allocator) (NULL, n_result); - g_return_val_if_fail (result != NULL, FALSE); - - for (pos = 0; pos < n_result; pos += 16) { - gcry = gcry_cipher_encrypt (cih, result + pos, 16, padded + pos, 16); - g_return_val_if_fail (gcry == 0, FALSE); - } - - gcry_cipher_close (cih); - - egg_secure_clear (padded, n_result); - egg_secure_free (padded); - - *cipher_text = result; - *n_cipher_text = n_result; - return TRUE; -} - -static gboolean -gcr_secret_exchange_default_decrypt_transport_data (GcrSecretExchange *exchange, - GckAllocator allocator, - const guchar *cipher_text, - gsize n_cipher_text, - const guchar *iv, - gsize n_iv, - guchar **plain_text, - gsize *n_plain_text) -{ - GcrSecretExchangeDefault *data = exchange->pv->default_exchange; - guchar* padded; - guchar* result; - gsize n_result; - gsize pos; - gcry_cipher_hd_t cih; - gcry_error_t gcry; - - g_return_val_if_fail (data != NULL, FALSE); - g_return_val_if_fail (data->key != NULL, FALSE); - - if (iv == NULL || n_iv != EXCHANGE_1_IV_LENGTH) { - g_message ("secret-exchange: invalid or missing iv"); - return FALSE; - } - - if (n_cipher_text % 16 != 0) { - g_message ("secret-message: invalid length for cipher text"); - return FALSE; - } - - gcry = gcry_cipher_open (&cih, EXCHANGE_1_CIPHER_ALGO, EXCHANGE_1_CIPHER_MODE, 0); - if (gcry != 0) { - g_warning ("couldn't create aes cipher context: %s", gcry_strerror (gcry)); - return FALSE; - } - - /* 16 = 128 bits */ - gcry = gcry_cipher_setkey (cih, data->key, EXCHANGE_1_KEY_LENGTH); - g_return_val_if_fail (gcry == 0, FALSE); - - /* 16 = 128 bits */ - gcry = gcry_cipher_setiv (cih, iv, n_iv); - g_return_val_if_fail (gcry == 0, FALSE); - - /* Allocate memory for the result */ - padded = (allocator) (NULL, n_cipher_text); - g_return_val_if_fail (padded != NULL, FALSE); - - for (pos = 0; pos < n_cipher_text; pos += 16) { - gcry = gcry_cipher_decrypt (cih, padded + pos, 16, (guchar *)cipher_text + pos, 16); - g_return_val_if_fail (gcry == 0, FALSE); - } - - gcry_cipher_close (cih); - - if (!egg_padding_pkcs7_unpad (allocator, 16, padded, n_cipher_text, - (gpointer*)&result, &n_result)) - result = NULL; - - /* Free the padded text */ - (allocator) (padded, 0); - - *plain_text = result; - *n_plain_text = n_result; - return TRUE; -} - -static void -gcr_secret_exchange_class_init (GcrSecretExchangeClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->get_property = gcr_secret_exchange_get_property; - gobject_class->set_property = gcr_secret_exchange_set_property; - gobject_class->finalize = gcr_secret_exchange_finalize; - - klass->generate_exchange_key = gcr_secret_exchange_default_generate_exchange_key; - klass->derive_transport_key = gcr_secret_exchange_default_derive_transport_key; - klass->decrypt_transport_data = gcr_secret_exchange_default_decrypt_transport_data; - klass->encrypt_transport_data = gcr_secret_exchange_default_encrypt_transport_data; - - g_type_class_add_private (gobject_class, sizeof (GcrSecretExchangePrivate)); - - egg_libgcrypt_initialize (); - - /** - * GcrSecretExchange:protocol: - * - * The protocol being used for the exchange. - * - * Will be %NULL if no protocol was specified when creating this object, - * and either gcr_secret_exchange_begin() or gcr_secret_exchange_receive() - * have not been called successfully. - */ - g_object_class_install_property (gobject_class, PROP_PROTOCOL, - g_param_spec_string ("protocol", "Protocol", "Exchange protocol", - GCR_SECRET_EXCHANGE_PROTOCOL_1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} diff --git a/gcr/gcr-secret-exchange.h b/gcr/gcr-secret-exchange.h deleted file mode 100644 index 5608f632..00000000 --- a/gcr/gcr-secret-exchange.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef __GCR_SECRET_EXCHANGE_H__ -#define __GCR_SECRET_EXCHANGE_H__ - -#include "gcr-base.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_SECRET_EXCHANGE_PROTOCOL_1 "sx-aes-1" - -#define GCR_TYPE_SECRET_EXCHANGE (gcr_secret_exchange_get_type ()) -#define GCR_SECRET_EXCHANGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_SECRET_EXCHANGE, GcrSecretExchange)) -#define GCR_SECRET_EXCHANGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_SECRET_EXCHANGE, GcrSecretExchangeClass)) -#define GCR_IS_SECRET_EXCHANGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_SECRET_EXCHANGE)) -#define GCR_IS_SECRET_EXCHANGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_SECRET_EXCHANGE)) -#define GCR_SECRET_EXCHANGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_SECRET_EXCHANGE, GcrSecretExchangeClass)) - -typedef struct _GcrSecretExchange GcrSecretExchange; -typedef struct _GcrSecretExchangeClass GcrSecretExchangeClass; -typedef struct _GcrSecretExchangePrivate GcrSecretExchangePrivate; - -struct _GcrSecretExchange { - /*< private >*/ - GObject parent; - GcrSecretExchangePrivate *pv; -}; - -struct _GcrSecretExchangeClass { - /*< private >*/ - GObjectClass parent_class; - - /* virtual methods, not used publicly */ - gboolean (*generate_exchange_key) (GcrSecretExchange *exchange, - const gchar *scheme, - guchar **public_key, - gsize *n_public_key); - - gboolean (*derive_transport_key) (GcrSecretExchange *exchange, - const guchar *peer, - gsize n_peer); - - gboolean (*encrypt_transport_data) (GcrSecretExchange *exchange, - GckAllocator allocator, - const guchar *plain_text, - gsize n_plain_text, - guchar **parameter, - gsize *n_parameter, - guchar **cipher_text, - gsize *n_cipher_text); - - gboolean (*decrypt_transport_data) (GcrSecretExchange *exchange, - GckAllocator allocator, - const guchar *cipher_text, - gsize n_cipher_text, - const guchar *parameter, - gsize n_parameter, - guchar **plain_text, - gsize *n_plain_text); - - gpointer dummy[6]; -}; - -/* Caller side functions */ - -GType gcr_secret_exchange_get_type (void); - -GcrSecretExchange * gcr_secret_exchange_new (const gchar *protocol); - -const gchar * gcr_secret_exchange_get_protocol (GcrSecretExchange *self); - -gchar * gcr_secret_exchange_begin (GcrSecretExchange *self); - -gboolean gcr_secret_exchange_receive (GcrSecretExchange *self, - const gchar *exchange); - -gchar * gcr_secret_exchange_send (GcrSecretExchange *self, - const gchar *secret, - gssize secret_len); - -const gchar * gcr_secret_exchange_get_secret (GcrSecretExchange *self, - gsize *secret_len); - -G_END_DECLS - -#endif /* __GCR_SECRET_EXCHANGE_H__ */ diff --git a/gcr/gcr-simple-certificate.c b/gcr/gcr-simple-certificate.c deleted file mode 100644 index 03e3e763..00000000 --- a/gcr/gcr-simple-certificate.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-certificate.h" -#include "gcr-comparable.h" -#include "gcr-internal.h" -#include "gcr-simple-certificate.h" - -#include <string.h> - -/** - * SECTION:gcr-simple-certificate - * @title: GcrSimpleCertificate - * @short_description: A certificate loaded from a memory buffer - * - * An implementation of #GcrCertificate which loads a certificate from DER - * data already located in memory. - * - * To create a #GcrSimpleCertificate object use the - * gcr_simple_certificate_new() or gcr_simple_certificate_new_static() - * functions. - */ - -/** - * GcrSimpleCertificate: - * - * A #GcrCertificate which represents a certificate already in memory. - */ - -/** - * GcrSimpleCertificateClass: - * @parent_class: The parent class - * - * The class for #GcrSimpleCertificate. - */ - -struct _GcrSimpleCertificatePrivate { - const guchar *data; - gsize n_data; - guchar *owned; -}; - -/* Forward declarations */ -static void gcr_simple_certificate_iface_init (GcrCertificateIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrSimpleCertificate, gcr_simple_certificate, G_TYPE_OBJECT, - GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE (); - G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, gcr_simple_certificate_iface_init); -); - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static void -gcr_simple_certificate_init (GcrSimpleCertificate *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_SIMPLE_CERTIFICATE, GcrSimpleCertificatePrivate); -} - -static void -gcr_simple_certificate_real_finalize (GObject *obj) -{ - GcrSimpleCertificate *self = GCR_SIMPLE_CERTIFICATE (obj); - - g_free (self->pv->owned); - self->pv->owned = NULL; - self->pv->data = NULL; - self->pv->n_data = 0; - - G_OBJECT_CLASS (gcr_simple_certificate_parent_class)->finalize (obj); -} - -static void -gcr_simple_certificate_class_init (GcrSimpleCertificateClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->finalize = gcr_simple_certificate_real_finalize; - gobject_class->get_property = gcr_certificate_mixin_get_property; - - g_type_class_add_private (gobject_class, sizeof (GcrSimpleCertificatePrivate)); - - gcr_certificate_mixin_class_init (gobject_class); - _gcr_initialize_library (); -} - -static const guchar * -gcr_simple_certificate_get_der_data (GcrCertificate *cert, - gsize *n_data) -{ - GcrSimpleCertificate *self = GCR_SIMPLE_CERTIFICATE (cert); - - g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL); - g_return_val_if_fail (n_data, NULL); - g_return_val_if_fail (self->pv->data, NULL); - - /* This is called when we're not a base class */ - *n_data = self->pv->n_data; - return self->pv->data; -} - -static void -gcr_simple_certificate_iface_init (GcrCertificateIface *iface) -{ - iface->get_der_data = gcr_simple_certificate_get_der_data; -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_simple_certificate_new: - * @data: (array length=n_data): the raw DER certificate data - * @n_data: The length of @data - * - * Create a new #GcrSimpleCertificate for the raw DER data. The @data memory is - * copied so you can dispose of it after this function returns. - * - * Returns: (transfer full) (type Gcr.SimpleCertificate): a new #GcrSimpleCertificate - */ -GcrCertificate * -gcr_simple_certificate_new (const guchar *data, - gsize n_data) -{ - GcrSimpleCertificate *cert; - - g_return_val_if_fail (data, NULL); - g_return_val_if_fail (n_data, NULL); - - cert = g_object_new (GCR_TYPE_SIMPLE_CERTIFICATE, NULL); - - cert->pv->data = cert->pv->owned = g_memdup (data, n_data); - cert->pv->n_data = n_data; - return GCR_CERTIFICATE (cert); -} - -/** - * gcr_simple_certificate_new_static: (skip) - * @data: (array length=n_data): The raw DER certificate data - * @n_data: The length of @data - * - * Create a new #GcrSimpleCertificate for the raw DER data. The @data memory is - * not copied and must persist until the #GcrSimpleCertificate object is - * destroyed. - * - * Returns: (transfer full) (type Gcr.SimpleCertificate): a new #GcrSimpleCertificate - */ -GcrCertificate * -gcr_simple_certificate_new_static (const guchar *data, - gsize n_data) -{ - GcrSimpleCertificate *cert; - - g_return_val_if_fail (data, NULL); - g_return_val_if_fail (n_data, NULL); - - cert = g_object_new (GCR_TYPE_SIMPLE_CERTIFICATE, NULL); - - cert->pv->owned = NULL; - cert->pv->data = data; - cert->pv->n_data = n_data; - return GCR_CERTIFICATE (cert); -} diff --git a/gcr/gcr-simple-certificate.h b/gcr/gcr-simple-certificate.h deleted file mode 100644 index d95aaae8..00000000 --- a/gcr/gcr-simple-certificate.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_SIMPLE_CERTIFICATE_H__ -#define __GCR_SIMPLE_CERTIFICATE_H__ - -#include "gcr-base.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_SIMPLE_CERTIFICATE (gcr_simple_certificate_get_type ()) -#define GCR_SIMPLE_CERTIFICATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_SIMPLE_CERTIFICATE, GcrSimpleCertificate)) -#define GCR_SIMPLE_CERTIFICATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_SIMPLE_CERTIFICATE, GcrSimpleCertificateClass)) -#define GCR_IS_SIMPLE_CERTIFICATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_SIMPLE_CERTIFICATE)) -#define GCR_IS_SIMPLE_CERTIFICATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_SIMPLE_CERTIFICATE)) -#define GCR_SIMPLE_CERTIFICATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_SIMPLE_CERTIFICATE, GcrSimpleCertificateClass)) - -typedef struct _GcrSimpleCertificate GcrSimpleCertificate; -typedef struct _GcrSimpleCertificateClass GcrSimpleCertificateClass; -typedef struct _GcrSimpleCertificatePrivate GcrSimpleCertificatePrivate; - -struct _GcrSimpleCertificate { - GObject parent; - - /*< private >*/ - GcrSimpleCertificatePrivate *pv; -}; - -struct _GcrSimpleCertificateClass { - GObjectClass parent_class; -}; - -GType gcr_simple_certificate_get_type (void); - -GcrCertificate * gcr_simple_certificate_new (const guchar *data, - gsize n_data); - -GcrCertificate * gcr_simple_certificate_new_static (const guchar *data, - gsize n_data); - -G_END_DECLS - -#endif /* __GCR_SIMPLE_CERTIFICATE_H__ */ diff --git a/gcr/gcr-simple-collection.c b/gcr/gcr-simple-collection.c deleted file mode 100644 index f843a7c3..00000000 --- a/gcr/gcr-simple-collection.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-collection.h" -#include "gcr-deprecated-base.h" -#include "gcr-internal.h" -#include "gcr-simple-collection.h" - -#include <string.h> - -/** - * SECTION:gcr-simple-collection - * @title: GcrSimpleCollection - * @short_description: A simple implementation of GcrCollection - * - * A simple implementation of #GcrCollection, which you can add and remove - * objects from. Use gcr_simple_collection_add() to do this - * gcr_simple_collection_remove(). - */ - -/** - * GcrSimpleCollection: - * - * A simple implementation of #GcrCollection. - */ - -/** - * GcrSimpleCollectionClass: - * @parent_class: The parent class - * - * The class for #GcrSimpleCollection. - */ - -struct _GcrSimpleCollectionPrivate { - GHashTable *items; -}; - -static void gcr_collection_iface (GcrCollectionIface *iface); -G_DEFINE_TYPE_WITH_CODE (GcrSimpleCollection, gcr_simple_collection, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_COLLECTION, gcr_collection_iface)); - -#define UNUSED_VALUE GUINT_TO_POINTER (1) - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static void -gcr_simple_collection_init (GcrSimpleCollection *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_SIMPLE_COLLECTION, GcrSimpleCollectionPrivate); - self->pv->items = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL); -} - -static void -gcr_simple_collection_dispose (GObject *obj) -{ - GcrSimpleCollection *self = GCR_SIMPLE_COLLECTION (obj); - - g_hash_table_remove_all (self->pv->items); - - G_OBJECT_CLASS (gcr_simple_collection_parent_class)->dispose (obj); -} - -static void -gcr_simple_collection_finalize (GObject *obj) -{ - GcrSimpleCollection *self = GCR_SIMPLE_COLLECTION (obj); - - g_assert (self->pv->items); - g_assert (g_hash_table_size (self->pv->items) == 0); - g_hash_table_destroy (self->pv->items); - self->pv->items = NULL; - - G_OBJECT_CLASS (gcr_simple_collection_parent_class)->finalize (obj); -} - -static void -gcr_simple_collection_class_init (GcrSimpleCollectionClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = gcr_simple_collection_dispose; - gobject_class->finalize = gcr_simple_collection_finalize; - g_type_class_add_private (gobject_class, sizeof (GcrSimpleCollectionPrivate)); -} - -static guint -gcr_simple_collection_real_get_length (GcrCollection *coll) -{ - GcrSimpleCollection *self = GCR_SIMPLE_COLLECTION (coll); - return g_hash_table_size (self->pv->items); -} - -static GList* -gcr_simple_collection_real_get_objects (GcrCollection *coll) -{ - GcrSimpleCollection *self = GCR_SIMPLE_COLLECTION (coll); - return g_hash_table_get_keys (self->pv->items); -} - -static gboolean -gcr_simple_collection_real_contains (GcrCollection *collection, - GObject *object) -{ - GcrSimpleCollection *self = GCR_SIMPLE_COLLECTION (collection); - return g_hash_table_lookup (self->pv->items, object) ? TRUE : FALSE; -} - -static void -gcr_collection_iface (GcrCollectionIface *iface) -{ - iface->get_length = gcr_simple_collection_real_get_length; - iface->get_objects = gcr_simple_collection_real_get_objects; - iface->contains = gcr_simple_collection_real_contains; -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_simple_collection_new: - * - * Create a new #GcrSimpleCollection. - * - * Returns: (transfer full) (type Gcr.SimpleCollection): a newly allocated - * collection, which should be freed with g_object_unref() - */ -GcrCollection * -gcr_simple_collection_new (void) -{ - return g_object_new (GCR_TYPE_SIMPLE_COLLECTION, NULL); -} - -/** - * gcr_simple_collection_add: - * @self: The collection - * @object: The object to add - * - * Add an object to this collection - */ -void -gcr_simple_collection_add (GcrSimpleCollection *self, GObject *object) -{ - g_return_if_fail (GCR_IS_SIMPLE_COLLECTION (self)); - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (!g_hash_table_lookup (self->pv->items, object)); - g_hash_table_insert (self->pv->items, g_object_ref (object), UNUSED_VALUE); - gcr_collection_emit_added (GCR_COLLECTION (self), object); -} - -/** - * gcr_simple_collection_remove: - * @self: The collection - * @object: The object to remove from the collection - * - * Remove an object from the collection. - */ -void -gcr_simple_collection_remove (GcrSimpleCollection *self, GObject *object) -{ - g_return_if_fail (GCR_IS_SIMPLE_COLLECTION (self)); - g_return_if_fail (G_IS_OBJECT (object)); - g_return_if_fail (g_hash_table_lookup (self->pv->items, object)); - g_object_ref (object); - g_hash_table_remove (self->pv->items, object); - gcr_collection_emit_removed (GCR_COLLECTION (self), object); - g_object_unref (object); -} - -/** - * gcr_simple_collection_contains: - * @self: The collection - * @object: The object to check - * - * Check if the collection contains a certain object. - * - * Deprecated: use gcr_collection_contains() instead - * - * Returns: %TRUE if the collection contains the object. - */ -gboolean -gcr_simple_collection_contains (GcrSimpleCollection *self, GObject *object) -{ - g_return_val_if_fail (GCR_IS_SIMPLE_COLLECTION (self), FALSE); - g_return_val_if_fail (G_IS_OBJECT (object), FALSE); - return gcr_collection_contains (GCR_COLLECTION (self), object); -} diff --git a/gcr/gcr-simple-collection.h b/gcr/gcr-simple-collection.h deleted file mode 100644 index e78c48c9..00000000 --- a/gcr/gcr-simple-collection.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_SIMPLE_COLLECTION_H__ -#define __GCR_SIMPLE_COLLECTION_H__ - -#include "gcr-base.h" -#include "gcr-collection.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_SIMPLE_COLLECTION (gcr_simple_collection_get_type ()) -#define GCR_SIMPLE_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_COLLECTION, GcrSimpleCollection)) -#define GCR_SIMPLE_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_COLLECTION, GcrSimpleCollectionClass)) -#define GCR_IS_SIMPLE_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_COLLECTION)) -#define GCR_IS_SIMPLE_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_COLLECTION)) -#define GCR_SIMPLE_COLLECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_COLLECTION, GcrSimpleCollectionClass)) - -typedef struct _GcrSimpleCollection GcrSimpleCollection; -typedef struct _GcrSimpleCollectionClass GcrSimpleCollectionClass; -typedef struct _GcrSimpleCollectionPrivate GcrSimpleCollectionPrivate; - -struct _GcrSimpleCollection { - GObject parent; - - /*< private >*/ - GcrSimpleCollectionPrivate *pv; -}; - -struct _GcrSimpleCollectionClass { - GObjectClass parent_class; -}; - -GType gcr_simple_collection_get_type (void); - -GcrCollection* gcr_simple_collection_new (void); - -void gcr_simple_collection_add (GcrSimpleCollection *self, - GObject *object); - -void gcr_simple_collection_remove (GcrSimpleCollection *self, - GObject *object); - -G_END_DECLS - -#endif /* __GCR_SIMPLE_COLLECTION_H__ */ diff --git a/gcr/gcr-single-collection.c b/gcr/gcr-single-collection.c deleted file mode 100644 index 942d47de..00000000 --- a/gcr/gcr-single-collection.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-collection.h" -#include "gcr-single-collection.h" - -#include <string.h> - -/** - * GcrSingleCollection: - * - * A single implementation of #GcrCollection. - */ - -struct _GcrSingleCollection { - GObject parent; - GObject *object; -}; - -/** - * GcrSingleCollectionClass: - * @parent_class: The parent class - * - * The class for #GcrSingleCollection. - */ - -struct _GcrSingleCollectionClass { - GObjectClass parent_class; -}; - -static void _gcr_single_collection_iface (GcrCollectionIface *iface); -G_DEFINE_TYPE_WITH_CODE (GcrSingleCollection, _gcr_single_collection, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_COLLECTION, _gcr_single_collection_iface)); - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static void -_gcr_single_collection_init (GcrSingleCollection *self) -{ - -} - -static void -_gcr_single_collection_dispose (GObject *obj) -{ - GcrSingleCollection *self = GCR_SINGLE_COLLECTION (obj); - - _gcr_single_collection_set_object (self, NULL); - - G_OBJECT_CLASS (_gcr_single_collection_parent_class)->dispose (obj); -} - -static void -_gcr_single_collection_class_init (GcrSingleCollectionClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = _gcr_single_collection_dispose; -} - -static guint -_gcr_single_collection_real_get_length (GcrCollection *coll) -{ - GcrSingleCollection *self = GCR_SINGLE_COLLECTION (coll); - return self->object == NULL ? 0 : 1; -} - -static GList* -_gcr_single_collection_real_get_objects (GcrCollection *coll) -{ - GcrSingleCollection *self = GCR_SINGLE_COLLECTION (coll); - return self->object == NULL ? NULL : g_list_append (NULL, self->object); -} - -static gboolean -_gcr_single_collection_real_contains (GcrCollection *collection, - GObject *object) -{ - GcrSingleCollection *self = GCR_SINGLE_COLLECTION (collection); - return self->object == object; -} - -static void -_gcr_single_collection_iface (GcrCollectionIface *iface) -{ - iface->get_length = _gcr_single_collection_real_get_length; - iface->get_objects = _gcr_single_collection_real_get_objects; - iface->contains = _gcr_single_collection_real_contains; -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -GcrCollection * -_gcr_single_collection_new (GObject *object) -{ - GcrSingleCollection *self; - - self = g_object_new (GCR_TYPE_SINGLE_COLLECTION, NULL); - _gcr_single_collection_set_object (self, object); - - return GCR_COLLECTION (self); -} - -GObject * -_gcr_single_collection_get_object (GcrSingleCollection *self) -{ - g_return_val_if_fail (GCR_IS_SINGLE_COLLECTION (self), NULL); - return self->object; -} - -void -_gcr_single_collection_set_object (GcrSingleCollection *self, - GObject *object) -{ - GObject *obj; - - g_return_if_fail (GCR_IS_SINGLE_COLLECTION (self)); - g_return_if_fail (object == NULL || G_IS_OBJECT (object)); - - if (object == self->object) - return; - - if (self->object) { - obj = self->object; - self->object = NULL; - gcr_collection_emit_removed (GCR_COLLECTION (self), obj); - g_object_unref (obj); - } - - if (object) { - self->object = g_object_ref (object); - gcr_collection_emit_added (GCR_COLLECTION (self), self->object); - } -} diff --git a/gcr/gcr-single-collection.h b/gcr/gcr-single-collection.h deleted file mode 100644 index 9bd598ff..00000000 --- a/gcr/gcr-single-collection.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef __GCR_SINGLE_COLLECTION_H__ -#define __GCR_SINGLE_COLLECTION_H__ - -#include "gcr-base.h" -#include "gcr-collection.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_SINGLE_COLLECTION (_gcr_single_collection_get_type ()) -#define GCR_SINGLE_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_COLLECTION, GcrSingleCollection)) -#define GCR_SINGLE_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_COLLECTION, GcrSingleCollectionClass)) -#define GCR_IS_SINGLE_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_COLLECTION)) -#define GCR_IS_SINGLE_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_COLLECTION)) -#define GCR_SINGLE_COLLECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_COLLECTION, GcrSingleCollectionClass)) - -typedef struct _GcrSingleCollection GcrSingleCollection; -typedef struct _GcrSingleCollectionClass GcrSingleCollectionClass; - -GType _gcr_single_collection_get_type (void); - -GcrCollection * _gcr_single_collection_new (GObject *object); - -GObject * _gcr_single_collection_get_object (GcrSingleCollection *self); - -void _gcr_single_collection_set_object (GcrSingleCollection *self, - GObject *object); - -G_END_DECLS - -#endif /* __GCR_SINGLE_COLLECTION_H__ */ diff --git a/gcr/gcr-tree-selector.c b/gcr/gcr-tree-selector.c deleted file mode 100644 index fb5261fe..00000000 --- a/gcr/gcr-tree-selector.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-collection-model.h" -#include "gcr-internal.h" -#include "gcr-tree-selector.h" - -#include <glib/gi18n-lib.h> - -#include <string.h> - -/** - * SECTION:gcr-tree-selector - * @title: GcrTreeSelector - * @short_description: A selector widget to select certificates or keys. - * - * The #GcrTreeSelector can be used to select certificates or keys. It allows - * the user to select multiple objects from a tree. - */ - -/** - * GcrTreeSelector: - * - * A tree selector widget. - */ - -/** - * GcrTreeSelectorClass: - * - * The class for #GcrTreeSelector. - */ - -enum { - PROP_0, - PROP_COLLECTION, - PROP_COLUMNS -}; - -struct _GcrTreeSelectorPrivate { - GcrCollection *collection; - const GcrColumn *columns; - GcrCollectionModel *model; -}; - -G_DEFINE_TYPE (GcrTreeSelector, gcr_tree_selector, GTK_TYPE_TREE_VIEW); - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -static void -on_check_column_toggled (GtkCellRendererToggle *cell, gchar *path, GcrCollectionModel *model) -{ - GtkTreeIter iter; - - g_assert (path != NULL); - - if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (model), &iter, path)) - gcr_collection_model_toggle_selected (model, &iter); -} - -static void -add_string_column (GcrTreeSelector *self, const GcrColumn *column, gint column_id) -{ - GtkCellRenderer *cell; - GtkTreeViewColumn *col; - const gchar *label; - - g_assert (column->column_type == G_TYPE_STRING); - g_assert (!(column->flags & GCR_COLUMN_HIDDEN)); - - cell = gtk_cell_renderer_text_new (); - g_object_set (G_OBJECT (cell), "ellipsize", PANGO_ELLIPSIZE_END, NULL); - label = column->label ? g_dpgettext2 (NULL, "column", column->label) : ""; - col = gtk_tree_view_column_new_with_attributes (label, cell, "text", column_id, NULL); - gtk_tree_view_column_set_resizable (col, TRUE); - if (column->flags & GCR_COLUMN_SORTABLE) - gtk_tree_view_column_set_sort_column_id (col, column_id); - gtk_tree_view_append_column (GTK_TREE_VIEW (self), col); -} - -static void -add_icon_column (GcrTreeSelector *self, const GcrColumn *column, gint column_id) -{ - GtkCellRenderer *cell; - GtkTreeViewColumn *col; - const gchar *label; - - g_assert (column->column_type == G_TYPE_ICON); - g_assert (!(column->flags & GCR_COLUMN_HIDDEN)); - - cell = gtk_cell_renderer_pixbuf_new (); - g_object_set (cell, "stock-size", GTK_ICON_SIZE_BUTTON, NULL); - label = column->label ? g_dpgettext2 (NULL, "column", column->label) : ""; - col = gtk_tree_view_column_new_with_attributes (label, cell, "gicon", column_id, NULL); - gtk_tree_view_column_set_resizable (col, TRUE); - if (column->flags & GCR_COLUMN_SORTABLE) - gtk_tree_view_column_set_sort_column_id (col, column_id); - gtk_tree_view_append_column (GTK_TREE_VIEW (self), col); -} - -static void -add_check_column (GcrTreeSelector *self, guint column_id) -{ - GtkCellRenderer *cell; - GtkTreeViewColumn *col; - - cell = gtk_cell_renderer_toggle_new (); - g_signal_connect (cell, "toggled", G_CALLBACK (on_check_column_toggled), self->pv->model); - - col = gtk_tree_view_column_new_with_attributes ("", cell, "active", column_id, NULL); - gtk_tree_view_column_set_resizable (col, FALSE); - gtk_tree_view_append_column (GTK_TREE_VIEW (self), col); -} - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - -static GObject* -gcr_tree_selector_constructor (GType type, guint n_props, GObjectConstructParam *props) -{ - GcrTreeSelector *self = GCR_TREE_SELECTOR (G_OBJECT_CLASS (gcr_tree_selector_parent_class)->constructor(type, n_props, props)); - const GcrColumn *column; - guint i; - - g_return_val_if_fail (self, NULL); - g_return_val_if_fail (self->pv->columns, NULL); - - self->pv->model = gcr_collection_model_new_full (self->pv->collection, - self->pv->columns); - - gtk_tree_view_set_model (GTK_TREE_VIEW (self), GTK_TREE_MODEL (self->pv->model)); - - /* First add the check mark column */ - add_check_column (self, gcr_collection_model_column_for_selected (self->pv->model)); - - for (column = self->pv->columns, i = 0; column->property_name; ++column, ++i) { - if (column->flags & GCR_COLUMN_HIDDEN) - continue; - - if (column->column_type == G_TYPE_STRING) - add_string_column (self, column, i); - else if (column->column_type == G_TYPE_ICON) - add_icon_column (self, column, i); - else - g_warning ("skipping unsupported column '%s' of type: %s", - column->property_name, g_type_name (column->column_type)); - } - - return G_OBJECT (self); -} - -static void -gcr_tree_selector_init (GcrTreeSelector *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_TREE_SELECTOR, GcrTreeSelectorPrivate); -} - -static void -gcr_tree_selector_dispose (GObject *obj) -{ - GcrTreeSelector *self = GCR_TREE_SELECTOR (obj); - - if (self->pv->model) - g_object_unref (self->pv->model); - self->pv->model = NULL; - - if (self->pv->collection) - g_object_unref (self->pv->collection); - self->pv->collection = NULL; - - G_OBJECT_CLASS (gcr_tree_selector_parent_class)->dispose (obj); -} - -static void -gcr_tree_selector_finalize (GObject *obj) -{ - GcrTreeSelector *self = GCR_TREE_SELECTOR (obj); - - g_assert (!self->pv->collection); - g_assert (!self->pv->model); - - G_OBJECT_CLASS (gcr_tree_selector_parent_class)->finalize (obj); -} - -static void -gcr_tree_selector_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrTreeSelector *self = GCR_TREE_SELECTOR (obj); - switch (prop_id) { - case PROP_COLLECTION: - g_return_if_fail (!self->pv->collection); - self->pv->collection = g_value_dup_object (value); - g_return_if_fail (self->pv->collection); - break; - case PROP_COLUMNS: - g_return_if_fail (!self->pv->columns); - self->pv->columns = g_value_get_pointer (value); - g_return_if_fail (self->pv->columns); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_tree_selector_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrTreeSelector *self = GCR_TREE_SELECTOR (obj); - - switch (prop_id) { - case PROP_COLLECTION: - g_value_set_object (value, gcr_tree_selector_get_collection (self)); - break; - case PROP_COLUMNS: - g_value_set_pointer (value, (gpointer)gcr_tree_selector_get_columns (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_tree_selector_class_init (GcrTreeSelectorClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->constructor = gcr_tree_selector_constructor; - gobject_class->dispose = gcr_tree_selector_dispose; - gobject_class->finalize = gcr_tree_selector_finalize; - gobject_class->set_property = gcr_tree_selector_set_property; - gobject_class->get_property = gcr_tree_selector_get_property; - - g_type_class_add_private (gobject_class, sizeof (GcrTreeSelectorPrivate)); - - /** - * GcrTreeSelector:collection: - * - * The collection which contains the objects to display in the selector. - */ - g_object_class_install_property (gobject_class, PROP_COLLECTION, - g_param_spec_object ("collection", "Collection", "Collection to select from", - GCR_TYPE_COLLECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - /** - * GcrTreeSelector:columns: - * - * The columns to use to display the objects. - */ - g_object_class_install_property (gobject_class, PROP_COLUMNS, - g_param_spec_pointer ("columns", "Columns", "Columns to display in selector", - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_tree_selector_new: (skip) - * @collection: The collection that contains the objects to display - * @columns: The columns to use to display the objects - * - * Create a new #GcrTreeSelector. - * - * Returns: (transfer full): a newly allocated selector, which should be - * released with g_object_unref() - */ -GcrTreeSelector * -gcr_tree_selector_new (GcrCollection *collection, const GcrColumn *columns) -{ - return g_object_new (GCR_TYPE_TREE_SELECTOR, - "collection", collection, - "columns", columns, - NULL); -} - -/** - * gcr_tree_selector_get_collection: - * @self: The selector - * - * Get the collection that this selector is displaying objects from. - * - * Returns: (transfer none): the collection, owned by the selector - */ -GcrCollection * -gcr_tree_selector_get_collection (GcrTreeSelector *self) -{ - g_return_val_if_fail (GCR_IS_TREE_SELECTOR (self), NULL); - return self->pv->collection; -} - -/** - * gcr_tree_selector_get_columns: (skip) - * @self: The selector - * - * Get the columns displayed in a selector in multiple mode. - * - * Returns: (transfer none): The columns, owned by the selector. - */ -const GcrColumn * -gcr_tree_selector_get_columns (GcrTreeSelector *self) -{ - g_return_val_if_fail (GCR_IS_TREE_SELECTOR (self), NULL); - return self->pv->columns; -} - -/** - * gcr_tree_selector_get_selected: - * @self: The selector - * - * Get a list of selected objects. - * - * Returns: (transfer container) (element-type GLib.Object): the list of selected - * objects, to be released with g_list_free() - */ -GList* -gcr_tree_selector_get_selected (GcrTreeSelector *self) -{ - g_return_val_if_fail (GCR_IS_TREE_SELECTOR (self), NULL); - return gcr_collection_model_get_selected_objects (self->pv->model); -} - -/** - * gcr_tree_selector_set_selected: - * @self: The selector - * @selected: (element-type GLib.Object): The list of objects to select. - * - * Select certain objects in the selector. - */ -void -gcr_tree_selector_set_selected (GcrTreeSelector *self, GList *selected) -{ - g_return_if_fail (GCR_IS_TREE_SELECTOR (self)); - gcr_collection_model_set_selected_objects (self->pv->model, selected); -} diff --git a/gcr/gcr-tree-selector.h b/gcr/gcr-tree-selector.h deleted file mode 100644 index 7792153c..00000000 --- a/gcr/gcr-tree-selector.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_TREE_SELECTOR_H__ -#define __GCR_TREE_SELECTOR_H__ - -#include "gcr-types.h" - -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_TREE_SELECTOR (gcr_tree_selector_get_type ()) -#define GCR_TREE_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_TREE_SELECTOR, GcrTreeSelector)) -#define GCR_TREE_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_TREE_SELECTOR, GcrTreeSelectorClass)) -#define GCR_IS_TREE_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_TREE_SELECTOR)) -#define GCR_IS_TREE_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_TREE_SELECTOR)) -#define GCR_TREE_SELECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_TREE_SELECTOR, GcrTreeSelectorClass)) - -typedef struct _GcrTreeSelector GcrTreeSelector; -typedef struct _GcrTreeSelectorClass GcrTreeSelectorClass; -typedef struct _GcrTreeSelectorPrivate GcrTreeSelectorPrivate; - -struct _GcrTreeSelector { - GtkTreeView parent; - - /*< private >*/ - GcrTreeSelectorPrivate *pv; -}; - -struct _GcrTreeSelectorClass { - /*< private >*/ - GtkTreeViewClass parent_class; -}; - -GType gcr_tree_selector_get_type (void); - -GcrTreeSelector* gcr_tree_selector_new (GcrCollection *collection, - const GcrColumn *columns); - -GcrCollection* gcr_tree_selector_get_collection (GcrTreeSelector *self); - -const GcrColumn* gcr_tree_selector_get_columns (GcrTreeSelector *self); - -GList* gcr_tree_selector_get_selected (GcrTreeSelector *self); - -void gcr_tree_selector_set_selected (GcrTreeSelector *self, - GList *selected); - -G_END_DECLS - -#endif /* __GCR_TREE_SELECTOR_H__ */ diff --git a/gcr/gcr-trust.c b/gcr/gcr-trust.c deleted file mode 100644 index 48006e64..00000000 --- a/gcr/gcr-trust.c +++ /dev/null @@ -1,878 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-base.h" -#define DEBUG_FLAG GCR_DEBUG_TRUST -#include "gcr-debug.h" -#include "gcr-types.h" -#include "gcr-internal.h" -#include "gcr-library.h" -#include "gcr-trust.h" - -#include <gck/gck.h> - -#include "pkcs11/pkcs11n.h" -#include "pkcs11/pkcs11i.h" -#include "pkcs11/pkcs11x.h" - -#include <glib/gi18n-lib.h> - -/** - * SECTION:gcr-trust - * @title: Trust Storage and Lookups - * @short_description: Store and lookup bits of information used for - * verifying certificates. - * - * These functions provide access to stored information about which - * certificates the system and user trusts as certificate authority trust - * anchors, or overrides to the normal verification of certificates. - * - * Trust anchors are used to verify the certificate authority in a certificate - * chain. Trust anchors are always valid for a given purpose. The most common - * purpose is the #GCR_PURPOSE_SERVER_AUTH and is used for a client application - * to verify that the certificate at the server side of a TLS connection is - * authorized to act as such. To check if a certificate is a trust anchor use - * gcr_trust_is_certificate_anchored(). - * - * Pinned certificates are used when a user overrides the default trust - * decision for a given certificate. They're often used with self-signed - * certificates. Pinned certificates are always only valid for a single peer - * such as the remote host with which TLS is being performed. To lookup - * pinned certificates use gcr_trust_is_certificate_pinned(). - * - * After the user has requested to override the trust decision - * about a given certificate then a pinned certificates can be added by using - * the gcr_trust_add_pinned_certificate() function. - * - * These functions do not constitute a viable method for verifying certificates - * used in TLS or other locations. Instead they support such verification - * by providing some of the needed data for a trust decision. - * - * The storage is provided by pluggable PKCS\#11 modules. - */ - -/** - * GCR_PURPOSE_SERVER_AUTH: - * - * The purpose used to verify the server certificate in a TLS connection. This - * is the most common purpose in use. - */ - -/** - * GCR_PURPOSE_CLIENT_AUTH: - * - * The purpose used to verify the client certificate in a TLS connection. - */ - -/** - * GCR_PURPOSE_CODE_SIGNING: - * - * The purpose used to verify certificate used for the signature on signed code. - */ - -/** - * GCR_PURPOSE_EMAIL: - * - * The purpose used to verify certificates that are used in email communication - * such as S/MIME. - */ - -/* ---------------------------------------------------------------------------------- - * HELPERS - */ - -typedef struct { - GckAttributes *attrs; - gboolean found; -} trust_closure; - -static void -trust_closure_free (gpointer data) -{ - trust_closure *closure = data; - gck_attributes_unref (closure->attrs); - g_free (closure); -} - -static GckAttributes* -prepare_trust_attrs (GcrCertificate *certificate, CK_X_ASSERTION_TYPE type) -{ - GckAttributes *attrs; - gconstpointer data; - gsize n_data; - - attrs = gck_attributes_new (); - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_X_TRUST_ASSERTION); - gck_attributes_add_ulong (attrs, CKA_X_ASSERTION_TYPE, type); - - data = gcr_certificate_get_der_data (certificate, &n_data); - g_return_val_if_fail (data, NULL); - gck_attributes_add_data (attrs, CKA_X_CERTIFICATE_VALUE, data, n_data); - - return attrs; -} - -/* ---------------------------------------------------------------------------------- - * GET PINNED CERTIFICATE - */ - -static GckAttributes * -prepare_is_certificate_pinned (GcrCertificate *certificate, const gchar *purpose, const gchar *peer) -{ - GckAttributes *attrs; - - attrs = prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE); - g_return_val_if_fail (attrs, NULL); - - gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose); - gck_attributes_add_string (attrs, CKA_X_PEER, peer); - - return attrs; -} - -static gboolean -perform_is_certificate_pinned (GckAttributes *search, - GCancellable *cancellable, - GError **error) -{ - GckEnumerator *en; - GList *slots; - GckObject *object; - - if (!gcr_pkcs11_initialize (cancellable, error)) - return FALSE; - - slots = gcr_pkcs11_get_trust_lookup_slots (); - _gcr_debug ("searching for pinned certificate in %d slots", - g_list_length (slots)); - en = gck_slots_enumerate_objects (slots, search, 0); - gck_list_unref_free (slots); - - object = gck_enumerator_next (en, cancellable, error); - g_object_unref (en); - - if (object) - g_object_unref (object); - - _gcr_debug ("%s certificate anchor", object ? "found" : "did not find"); - return (object != NULL); -} - -/** - * gcr_trust_is_certificate_pinned: - * @certificate: a #GcrCertificate to check - * @purpose: the purpose string - * @peer: the peer for this pinned - * @cancellable: a #GCancellable - * @error: a #GError, or NULL - * - * Check if @certificate is pinned for @purpose to communicate with @peer. - * A pinned certificate overrides all other certificate verification. - * - * This call may block, see gcr_trust_is_certificate_pinned_async() for the - * non-blocking version. - * - * In the case of an error, %FALSE is also returned. Check @error to detect - * if an error occurred. - * - * Returns: %TRUE if the certificate is pinned for the host and purpose - */ -gboolean -gcr_trust_is_certificate_pinned (GcrCertificate *certificate, const gchar *purpose, - const gchar *peer, GCancellable *cancellable, GError **error) -{ - GckAttributes *search; - gboolean ret; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), FALSE); - g_return_val_if_fail (purpose, FALSE); - g_return_val_if_fail (peer, FALSE); - - search = prepare_is_certificate_pinned (certificate, purpose, peer); - g_return_val_if_fail (search, FALSE); - - ret = perform_is_certificate_pinned (search, cancellable, error); - gck_attributes_unref (search); - - return ret; -} - -static void -thread_is_certificate_pinned (GSimpleAsyncResult *result, GObject *object, GCancellable *cancel) -{ - GError *error = NULL; - trust_closure *closure; - - closure = g_simple_async_result_get_op_res_gpointer (result); - closure->found = perform_is_certificate_pinned (closure->attrs, cancel, &error); - - if (error != NULL) { - g_simple_async_result_set_from_error (result, error); - g_clear_error (&error); - } -} - -/** - * gcr_trust_is_certificate_pinned_async: - * @certificate: a #GcrCertificate to check - * @purpose: the purpose string - * @peer: the peer for this pinned - * @cancellable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation completes - * @user_data: the data to pass to callback function - * - * Check if @certificate is pinned for @purpose to communicate with @peer. A - * pinned certificate overrides all other certificate verification. - * - * When the operation is finished, callback will be called. You can then call - * gcr_trust_is_certificate_pinned_finish() to get the result of the - * operation. - */ -void -gcr_trust_is_certificate_pinned_async (GcrCertificate *certificate, const gchar *purpose, - const gchar *peer, GCancellable *cancellable, - GAsyncReadyCallback callback, gpointer user_data) -{ - GSimpleAsyncResult *async; - trust_closure *closure; - - g_return_if_fail (GCR_CERTIFICATE (certificate)); - g_return_if_fail (purpose); - g_return_if_fail (peer); - - async = g_simple_async_result_new (NULL, callback, user_data, - gcr_trust_is_certificate_pinned_async); - closure = g_new0 (trust_closure, 1); - closure->attrs = prepare_is_certificate_pinned (certificate, purpose, peer); - g_return_if_fail (closure->attrs); - g_simple_async_result_set_op_res_gpointer (async, closure, trust_closure_free); - - g_simple_async_result_run_in_thread (async, thread_is_certificate_pinned, - G_PRIORITY_DEFAULT, cancellable); - - g_object_unref (async); -} - -/** - * gcr_trust_is_certificate_pinned_finish: - * @result: the #GAsyncResult passed to the callback - * @error: a #GError, or NULL - * - * Finishes an asynchronous operation started by - * gcr_trust_is_certificate_pinned_async(). - * - * In the case of an error, %FALSE is also returned. Check @error to detect - * if an error occurred. - * - * Returns: %TRUE if the certificate is pinned. - */ -gboolean -gcr_trust_is_certificate_pinned_finish (GAsyncResult *result, GError **error) -{ - trust_closure *closure; - - g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, - gcr_trust_is_certificate_pinned_async), FALSE); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return FALSE; - - closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); - return closure->found; -} - -/* ---------------------------------------------------------------------------------- - * ADD PINNED CERTIFICATE - */ - -static GckAttributes * -prepare_add_pinned_certificate (GcrCertificate *certificate, const gchar *purpose, const gchar *peer) -{ - GckAttributes *attrs; - - attrs = prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE); - g_return_val_if_fail (attrs, NULL); - - gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose); - gck_attributes_add_string (attrs, CKA_X_PEER, peer); - gck_attributes_add_boolean (attrs, CKA_TOKEN, TRUE); - - return attrs; -} - -static gboolean -perform_add_pinned_certificate (GckAttributes *search, - GCancellable *cancellable, - GError **error) -{ - GckAttributes *attrs; - gboolean ret = FALSE; - GError *lerr = NULL; - GckObject *object; - GckSession *session; - GckSlot *slot; - GckEnumerator *en; - GList *slots; - - if (!gcr_pkcs11_initialize (cancellable, error)) - return FALSE; - - slots = gcr_pkcs11_get_trust_lookup_slots (); - en = gck_slots_enumerate_objects (slots, search, CKF_RW_SESSION); - gck_list_unref_free (slots); - - /* We need an error below */ - if (error && !*error) - *error = lerr; - - object = gck_enumerator_next (en, cancellable, error); - g_object_unref (en); - - if (*error) - return FALSE; - - /* It already exists */ - if (object) { - g_object_unref (object); - return TRUE; - } - - attrs = gck_attributes_new (); - gck_attributes_add_all (attrs, search); - - /* TODO: Add relevant label */ - - /* Find an appropriate token */ - slot = gcr_pkcs11_get_trust_store_slot (); - if (slot == NULL) { - g_set_error (error, GCK_ERROR, CKR_FUNCTION_FAILED, - /* Translators: A pinned certificate is an exception which - trusts a given certificate explicitly for a purpose and - communication with a certain peer. */ - _("Couldn't find a place to store the pinned certificate")); - ret = FALSE; - } else { - session = gck_slot_open_session (slot, CKF_RW_SESSION, NULL, error); - if (session != NULL) { - object = gck_session_create_object (session, attrs, cancellable, error); - if (object != NULL) { - g_object_unref (object); - ret = TRUE; - } - - g_object_unref (session); - } - - g_object_unref (slot); - } - - gck_attributes_unref (attrs); - - /* Our own local error pointer */ - g_clear_error (&lerr); - - return ret; -} - -/** - * gcr_trust_add_pinned_certificate: - * @certificate: a #GcrCertificate - * @purpose: the purpose string - * @peer: the peer for this pinned certificate - * @cancellable: a #GCancellable - * @error: a #GError, or NULL - * - * Add a pinned @certificate for connections to @peer for @purpose. A pinned - * certificate overrides all other certificate verification and should be - * used with care. - * - * If the same pinned certificate already exists, then this operation - * does not add another, and succeeds without error. - * - * This call may block, see gcr_trust_add_pinned_certificate_async() for the - * non-blocking version. - * - * Returns: %TRUE if the pinned certificate is recorded successfully - */ -gboolean -gcr_trust_add_pinned_certificate (GcrCertificate *certificate, const gchar *purpose, const gchar *peer, - GCancellable *cancellable, GError **error) -{ - GckAttributes *search; - gboolean ret; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), FALSE); - g_return_val_if_fail (purpose, FALSE); - g_return_val_if_fail (peer, FALSE); - - search = prepare_add_pinned_certificate (certificate, purpose, peer); - g_return_val_if_fail (search, FALSE); - - ret = perform_add_pinned_certificate (search, cancellable, error); - gck_attributes_unref (search); - - return ret; -} - -static void -thread_add_pinned_certificate (GSimpleAsyncResult *result, GObject *object, GCancellable *cancel) -{ - GError *error = NULL; - trust_closure *closure; - - closure = g_simple_async_result_get_op_res_gpointer (result); - perform_add_pinned_certificate (closure->attrs, cancel, &error); - - if (error != NULL) { - g_simple_async_result_set_from_error (result, error); - g_clear_error (&error); - } -} - -/** - * gcr_trust_add_pinned_certificate_async: - * @certificate: a #GcrCertificate - * @purpose: the purpose string - * @peer: the peer for this pinned certificate - * @cancellable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation completes - * @user_data: the data to pass to callback function - * - * Add a pinned certificate for communication with @peer for @purpose. A pinned - * certificate overrides all other certificate verification and should be used - * with care. - * - * If the same pinned certificate already exists, then this operation - * does not add another, and succeeds without error. - * - * When the operation is finished, callback will be called. You can then call - * gcr_trust_add_pinned_certificate_finish() to get the result of the - * operation. - */ -void -gcr_trust_add_pinned_certificate_async (GcrCertificate *certificate, const gchar *purpose, - const gchar *peer, GCancellable *cancellable, - GAsyncReadyCallback callback, gpointer user_data) -{ - GSimpleAsyncResult *async; - trust_closure *closure; - - g_return_if_fail (GCR_IS_CERTIFICATE (certificate)); - g_return_if_fail (purpose); - g_return_if_fail (peer); - - async = g_simple_async_result_new (NULL, callback, user_data, - gcr_trust_add_pinned_certificate_async); - closure = g_new0 (trust_closure, 1); - closure->attrs = prepare_add_pinned_certificate (certificate, purpose, peer); - g_return_if_fail (closure->attrs); - g_simple_async_result_set_op_res_gpointer (async, closure, trust_closure_free); - - g_simple_async_result_run_in_thread (async, thread_add_pinned_certificate, - G_PRIORITY_DEFAULT, cancellable); - - g_object_unref (async); -} - -/** - * gcr_trust_add_pinned_certificate_finish: - * @result: the #GAsyncResult passed to the callback - * @error: a #GError, or NULL - * - * Finishes an asynchronous operation started by - * gcr_trust_add_pinned_certificate_async(). - * - * Returns: %TRUE if the pinned certificate is recorded successfully - */ -gboolean -gcr_trust_add_pinned_certificate_finish (GAsyncResult *result, GError **error) -{ - g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, - gcr_trust_add_pinned_certificate_async), FALSE); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return FALSE; - - return TRUE; -} - -/* ----------------------------------------------------------------------- - * REMOVE PINNED CERTIFICATE - */ - -static GckAttributes * -prepare_remove_pinned_certificate (GcrCertificate *certificate, const gchar *purpose, - const gchar *peer) -{ - GckAttributes *attrs; - - attrs = prepare_trust_attrs (certificate, CKT_X_PINNED_CERTIFICATE); - g_return_val_if_fail (attrs, NULL); - - gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose); - gck_attributes_add_string (attrs, CKA_X_PEER, peer); - - return attrs; -} - -static gboolean -perform_remove_pinned_certificate (GckAttributes *attrs, - GCancellable *cancellable, - GError **error) -{ - GList *objects, *l; - GError *lerr = NULL; - GckEnumerator *en; - GList *slots; - - if (!gcr_pkcs11_initialize (cancellable, error)) - return FALSE; - - slots = gcr_pkcs11_get_trust_lookup_slots (); - en = gck_slots_enumerate_objects (slots, attrs, CKF_RW_SESSION); - gck_list_unref_free (slots); - - /* We need an error below */ - if (error && !*error) - *error = lerr; - - objects = gck_enumerator_next_n (en, -1, cancellable, error); - g_object_unref (en); - - if (*error) - return FALSE; - - for (l = objects; l; l = g_list_next (l)) { - if (!gck_object_destroy (l->data, cancellable, error)) { - - /* In case there's a race condition */ - if (g_error_matches (*error, GCK_ERROR, CKR_OBJECT_HANDLE_INVALID)) { - g_clear_error (error); - continue; - } - - gck_list_unref_free (objects); - return FALSE; - } - } - - gck_list_unref_free (objects); - return TRUE; -} - -/** - * gcr_trust_remove_pinned_certificate: - * @certificate: a #GcrCertificate - * @purpose: the purpose string - * @peer: the peer for this pinned certificate - * @cancellable: a #GCancellable - * @error: a #GError, or NULL - * - * Remove a pinned certificate for communication with @peer for @purpose. - * - * If the same pinned certificate does not exist, or was already removed, - * then this operation succeeds without error. - * - * This call may block, see gcr_trust_remove_pinned_certificate_async() for the - * non-blocking version. - * - * Returns: %TRUE if the pinned certificate no longer exists - */ -gboolean -gcr_trust_remove_pinned_certificate (GcrCertificate *certificate, const gchar *purpose, const gchar *peer, - GCancellable *cancellable, GError **error) -{ - GckAttributes *search; - gboolean ret; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), FALSE); - g_return_val_if_fail (purpose, FALSE); - g_return_val_if_fail (peer, FALSE); - - search = prepare_remove_pinned_certificate (certificate, purpose, peer); - g_return_val_if_fail (search, FALSE); - - ret = perform_remove_pinned_certificate (search, cancellable, error); - gck_attributes_unref (search); - - return ret; -} - -static void -thread_remove_pinned_certificate (GSimpleAsyncResult *result, GObject *object, GCancellable *cancel) -{ - GError *error = NULL; - trust_closure *closure; - - closure = g_simple_async_result_get_op_res_gpointer (result); - perform_remove_pinned_certificate (closure->attrs, cancel, &error); - - if (error != NULL) { - g_simple_async_result_set_from_error (result, error); - g_clear_error (&error); - } -} - -/** - * gcr_trust_remove_pinned_certificate_async: - * @certificate: a #GcrCertificate - * @purpose: the purpose string - * @peer: the peer for this pinned certificate - * @cancellable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation completes - * @user_data: the data to pass to callback function - * - * Remove a pinned certificate for communication with @peer for @purpose. - * - * If the same pinned certificate does not exist, or was already removed, - * then this operation succeeds without error. - * - * When the operation is finished, callback will be called. You can then call - * gcr_trust_remove_pinned_certificate_finish() to get the result of the - * operation. - */ -void -gcr_trust_remove_pinned_certificate_async (GcrCertificate *certificate, const gchar *purpose, - const gchar *peer, GCancellable *cancellable, - GAsyncReadyCallback callback, gpointer user_data) -{ - GSimpleAsyncResult *async; - trust_closure *closure; - - g_return_if_fail (GCR_IS_CERTIFICATE (certificate)); - g_return_if_fail (purpose); - g_return_if_fail (peer); - - async = g_simple_async_result_new (NULL, callback, user_data, - gcr_trust_remove_pinned_certificate_async); - closure = g_new0 (trust_closure, 1); - closure->attrs = prepare_remove_pinned_certificate (certificate, purpose, peer); - g_return_if_fail (closure->attrs); - g_simple_async_result_set_op_res_gpointer (async, closure, trust_closure_free); - - g_simple_async_result_run_in_thread (async, thread_remove_pinned_certificate, - G_PRIORITY_DEFAULT, cancellable); - - g_object_unref (async); -} - -/** - * gcr_trust_remove_pinned_certificate_finish: - * @result: the #GAsyncResult passed to the callback - * @error: a #GError, or NULL - * - * Finishes an asynchronous operation started by - * gcr_trust_remove_pinned_certificate_async(). - * - * Returns: %TRUE if the pinned certificate no longer exists - */ -gboolean -gcr_trust_remove_pinned_certificate_finish (GAsyncResult *result, GError **error) -{ - g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, - gcr_trust_remove_pinned_certificate_async), FALSE); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return FALSE; - - return TRUE; -} - -/* ---------------------------------------------------------------------------------- - * CERTIFICATE ROOT - */ - -static GckAttributes * -prepare_is_certificate_anchored (GcrCertificate *certificate, const gchar *purpose) -{ - GckAttributes *attrs; - - attrs = prepare_trust_attrs (certificate, CKT_X_ANCHORED_CERTIFICATE); - g_return_val_if_fail (attrs, NULL); - - gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose); - - return attrs; -} - -static gboolean -perform_is_certificate_anchored (GckAttributes *attrs, - GCancellable *cancellable, - GError **error) -{ - GckEnumerator *en; - GList *slots; - GckObject *object; - - if (!gcr_pkcs11_initialize (cancellable, error)) - return FALSE; - - slots = gcr_pkcs11_get_trust_lookup_slots (); - _gcr_debug ("searching for certificate anchor in %d slots", - g_list_length (slots)); - en = gck_slots_enumerate_objects (slots, attrs, 0); - gck_list_unref_free (slots); - - object = gck_enumerator_next (en, cancellable, error); - g_object_unref (en); - - if (object != NULL) - g_object_unref (object); - - _gcr_debug ("%s certificate anchor", object ? "found" : "did not find"); - return (object != NULL); -} - -/** - * gcr_trust_is_certificate_anchored: - * @certificate: a #GcrCertificate to check - * @purpose: the purpose string - * @cancellable: a #GCancellable - * @error: a #GError, or NULL - * - * Check if the @certificate is a trust anchor for the given @purpose. A trust - * anchor is used to verify the signatures on other certificates when verifying - * a certificate chain. Also known as a trusted certificate authority. - * - * This call may block, see gcr_trust_is_certificate_anchored_async() for the - * non-blocking version. - * - * In the case of an error, %FALSE is also returned. Check @error to detect - * if an error occurred. - * - * Returns: %TRUE if the certificate is a trust anchor - */ -gboolean -gcr_trust_is_certificate_anchored (GcrCertificate *certificate, const gchar *purpose, - GCancellable *cancellable, GError **error) -{ - GckAttributes *search; - gboolean ret; - - g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), FALSE); - g_return_val_if_fail (purpose, FALSE); - - search = prepare_is_certificate_anchored (certificate, purpose); - g_return_val_if_fail (search, FALSE); - - ret = perform_is_certificate_anchored (search, cancellable, error); - gck_attributes_unref (search); - - return ret; -} - -static void -thread_is_certificate_anchored (GSimpleAsyncResult *result, GObject *object, GCancellable *cancel) -{ - GError *error = NULL; - trust_closure *closure; - - closure = g_simple_async_result_get_op_res_gpointer (result); - closure->found = perform_is_certificate_anchored (closure->attrs, cancel, &error); - - if (error != NULL) { - g_simple_async_result_set_from_error (result, error); - g_clear_error (&error); - } -} - -/** - * gcr_trust_is_certificate_anchored_async: - * @certificate: a #GcrCertificate to check - * @purpose: the purpose string - * @cancellable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation completes - * @user_data: the data to pass to callback function - * - * Check if the @certificate is a trust anchor for the given @purpose. A trust - * anchor is used to verify the signatures on other certificates when verifying - * a certificate chain. Also known as a trusted certificate authority. - * - * When the operation is finished, callback will be called. You can then call - * gcr_trust_is_certificate_anchored_finish() to get the result of the operation. - */ -void -gcr_trust_is_certificate_anchored_async (GcrCertificate *certificate, const gchar *purpose, - GCancellable *cancellable, GAsyncReadyCallback callback, - gpointer user_data) -{ - GSimpleAsyncResult *async; - trust_closure *closure; - - g_return_if_fail (GCR_IS_CERTIFICATE (certificate)); - g_return_if_fail (purpose); - - async = g_simple_async_result_new (NULL, callback, user_data, - gcr_trust_is_certificate_anchored_async); - closure = g_new0 (trust_closure, 1); - closure->attrs = prepare_is_certificate_anchored (certificate, purpose); - g_return_if_fail (closure->attrs); - g_simple_async_result_set_op_res_gpointer (async, closure, trust_closure_free); - - g_simple_async_result_run_in_thread (async, thread_is_certificate_anchored, - G_PRIORITY_DEFAULT, cancellable); - - g_object_unref (async); -} - -/** - * gcr_trust_is_certificate_anchored_finish: - * @result: the #GAsyncResult passed to the callback - * @error: a #GError, or NULL - * - * Finishes an asynchronous operation started by - * gcr_trust_is_certificate_anchored_async(). - * - * In the case of an error, %FALSE is also returned. Check @error to detect - * if an error occurred. - * - * Returns: %TRUE if the certificate is a trust anchor - */ -gboolean -gcr_trust_is_certificate_anchored_finish (GAsyncResult *result, GError **error) -{ - trust_closure *closure; - - g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - - g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, - gcr_trust_is_certificate_anchored_async), FALSE); - - if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) - return FALSE; - - closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); - return closure->found; -} diff --git a/gcr/gcr-trust.h b/gcr/gcr-trust.h deleted file mode 100644 index 79db47fd..00000000 --- a/gcr/gcr-trust.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_TRUST_H__ -#define __GCR_TRUST_H__ - -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_PURPOSE_SERVER_AUTH "1.3.6.1.5.5.7.3.1" -#define GCR_PURPOSE_CLIENT_AUTH "1.3.6.1.5.5.7.3.2" -#define GCR_PURPOSE_CODE_SIGNING "1.3.6.1.5.5.7.3.3" -#define GCR_PURPOSE_EMAIL "1.3.6.1.5.5.7.3.4" - -gboolean gcr_trust_is_certificate_pinned (GcrCertificate *certificate, - const gchar *purpose, - const gchar *peer, - GCancellable *cancellable, - GError **error); - -void gcr_trust_is_certificate_pinned_async (GcrCertificate *certificate, - const gchar *purpose, - const gchar *peer, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean gcr_trust_is_certificate_pinned_finish (GAsyncResult *result, - GError **error); - -gboolean gcr_trust_add_pinned_certificate (GcrCertificate *certificate, - const gchar *purpose, - const gchar *peer, - GCancellable *cancellable, - GError **error); - -void gcr_trust_add_pinned_certificate_async (GcrCertificate *certificate, - const gchar *purpose, - const gchar *peer, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean gcr_trust_add_pinned_certificate_finish (GAsyncResult *result, - GError **error); - -gboolean gcr_trust_remove_pinned_certificate (GcrCertificate *certificate, - const gchar *purpose, - const gchar *peer, - GCancellable *cancellable, - GError **error); - -void gcr_trust_remove_pinned_certificate_async (GcrCertificate *certificate, - const gchar *purpose, - const gchar *peer, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean gcr_trust_remove_pinned_certificate_finish (GAsyncResult *result, - GError **error); - -gboolean gcr_trust_is_certificate_anchored (GcrCertificate *certificate, - const gchar *purpose, - GCancellable *cancellable, - GError **error); - -void gcr_trust_is_certificate_anchored_async (GcrCertificate *certificate, - const gchar *purpose, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - -gboolean gcr_trust_is_certificate_anchored_finish (GAsyncResult *result, - GError **error); - -G_END_DECLS - -#endif /* __GCR_TOKEN_MANAGER_H__ */ diff --git a/gcr/gcr-types.h b/gcr/gcr-types.h deleted file mode 100644 index cffed10d..00000000 --- a/gcr/gcr-types.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef GCRTYPES_H_ -#define GCRTYPES_H_ - -#include <glib.h> - -#ifndef GCK_API_SUBJECT_TO_CHANGE - -/** - * GCK_API_SUBJECT_TO_CHANGE: (skip) - * - * skip for gir introspection - */ -#define GCK_API_SUBJECT_TO_CHANGE 1 - -/** - * __GCR_DEFINED_GCK_SUBJECT_TO_CHANGE__: (skip) - * - * skip for gir introspection - */ -#define __GCR_DEFINED_GCK_SUBJECT_TO_CHANGE__ 1 - -#endif - -#include <gck/gck.h> - -#ifdef __GCR_DEFINED_GCK_SUBJECT_TO_CHANGE__ -#undef GCK_API_SUBJECT_TO_CHANGE -#endif - -G_BEGIN_DECLS - -#define GCR_DATA_ERROR (gcr_data_error_get_domain ()) - -GQuark gcr_data_error_get_domain (void) G_GNUC_CONST; - -typedef enum { - GCR_ERROR_FAILURE = -1, - GCR_ERROR_UNRECOGNIZED = 1, - GCR_ERROR_CANCELLED = 2, - GCR_ERROR_LOCKED = 3 -} GcrDataError; - -typedef enum { - GCR_FORMAT_ALL = -1, - GCR_FORMAT_INVALID = 0, - - GCR_FORMAT_DER_PRIVATE_KEY = 100, - GCR_FORMAT_DER_PRIVATE_KEY_RSA, - GCR_FORMAT_DER_PRIVATE_KEY_DSA, - - GCR_FORMAT_DER_CERTIFICATE_X509 = 200, - - GCR_FORMAT_DER_PKCS7 = 300, - - GCR_FORMAT_DER_PKCS8 = 400, - GCR_FORMAT_DER_PKCS8_PLAIN, - GCR_FORMAT_DER_PKCS8_ENCRYPTED, - - GCR_FORMAT_DER_PKCS12 = 500, - - GCR_FORMAT_OPENSSH_PUBLIC = 600, - - GCR_FORMAT_OPENPGP_PACKET = 700, - GCR_FORMAT_OPENPGP_ARMOR, - - GCR_FORMAT_PEM = 1000, - GCR_FORMAT_PEM_PRIVATE_KEY_RSA, - GCR_FORMAT_PEM_PRIVATE_KEY_DSA, - GCR_FORMAT_PEM_CERTIFICATE_X509, - GCR_FORMAT_PEM_PKCS7, - GCR_FORMAT_PEM_PKCS8_PLAIN, - GCR_FORMAT_PEM_PKCS8_ENCRYPTED, - GCR_FORMAT_PEM_PKCS12, - GCR_FORMAT_PEM_PRIVATE_KEY -} GcrDataFormat; - -/* - * Special PKCS#11 style attributes that we use internally in GCR. - * These are used by GcrParser the most - */ - -enum { - /* An object class representing GcrRecord/gnupg-colons style data */ - CKO_GCR_GNUPG_RECORDS = (CKO_VENDOR_DEFINED | 0x47435200UL /* GCR0 */) -}; - -G_END_DECLS - -#endif /* GCRTYPES_H_ */ diff --git a/gcr/gcr-union-collection.c b/gcr/gcr-union-collection.c deleted file mode 100644 index 459fbcc0..00000000 --- a/gcr/gcr-union-collection.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-collection.h" -#include "gcr-internal.h" -#include "gcr-union-collection.h" - -#include <string.h> - -/** - * SECTION:gcr-union-collection - * @title: GcrUnionCollection - * @short_description: A GcrCollection which combines other collections - * - * An implementation of #GcrCollection, which combines the objects in - * other #GcrCollections. Use gcr_union_collection_add() to add and - * gcr_union_collection_remove() to remove them. - */ - -/** - * GcrUnionCollection: - * - * A union implementation of #GcrCollection. - */ - -/** - * GcrUnionCollectionClass: - * @parent_class: The parent class - * - * The class for #GcrUnionCollection. - */ - -struct _GcrUnionCollectionPrivate { - GHashTable *items; - GHashTable *collections; -}; - -static void gcr_collection_iface (GcrCollectionIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrUnionCollection, gcr_union_collection, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_COLLECTION, gcr_collection_iface)); - -static void -on_collection_added (GcrCollection *collection, - GObject *object, - gpointer user_data) -{ - GcrUnionCollection *self = GCR_UNION_COLLECTION (user_data); - gint *count; - - g_object_ref (object); - - count = g_hash_table_lookup (self->pv->items, object); - if (count == NULL) { - count = g_new0 (gint, 1); - *count = 1; - g_hash_table_insert (self->pv->items, object, count); - gcr_collection_emit_added (GCR_COLLECTION (self), object); - } else { - g_assert (*count > 0); - (*count)++; - } - - g_object_unref (object); -} - -static void -on_collection_removed (GcrCollection *collection, - GObject *object, - gpointer user_data) -{ - GcrUnionCollection *self = GCR_UNION_COLLECTION (user_data); - gint *count; - - g_object_ref (object); - - count = g_hash_table_lookup (self->pv->items, object); - if (count != NULL) { - g_assert (*count > 0); - (*count)--; - - if (*count == 0) { - g_hash_table_remove (self->pv->items, object); - gcr_collection_emit_removed (GCR_COLLECTION (self), object); - } - } else { - g_warning ("Object of type %s that exists in an underlying " - "collection of a GcrUnionCollection appeared without " - "emitting 'added' signal.", G_OBJECT_TYPE_NAME (object)); - } - - g_object_unref (object); - -} - -static void -connect_to_collection (GcrUnionCollection *self, - GcrCollection *collection) -{ - g_signal_connect (collection, "added", G_CALLBACK (on_collection_added), self); - g_signal_connect (collection, "removed", G_CALLBACK (on_collection_removed), self); -} - -static void -disconnect_from_collection (GcrUnionCollection *self, - GcrCollection *collection) -{ - g_signal_handlers_disconnect_by_func (collection, on_collection_added, self); - g_signal_handlers_disconnect_by_func (collection, on_collection_removed, self); -} - -static void -gcr_union_collection_init (GcrUnionCollection *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_UNION_COLLECTION, GcrUnionCollectionPrivate); - self->pv->items = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, g_free); - self->pv->collections = g_hash_table_new_full (g_direct_hash, g_direct_equal, - g_object_unref, NULL); -} - -static void -gcr_union_collection_dispose (GObject *obj) -{ - GcrUnionCollection *self = GCR_UNION_COLLECTION (obj); - GHashTableIter iter; - GcrCollection *collection; - - g_hash_table_iter_init (&iter, self->pv->collections); - while (g_hash_table_iter_next (&iter, (gpointer *)&collection, NULL)) - disconnect_from_collection (self, collection); - g_hash_table_remove_all (self->pv->collections); - g_hash_table_remove_all (self->pv->items); - - G_OBJECT_CLASS (gcr_union_collection_parent_class)->dispose (obj); -} - -static void -gcr_union_collection_finalize (GObject *obj) -{ - GcrUnionCollection *self = GCR_UNION_COLLECTION (obj); - - g_assert (g_hash_table_size (self->pv->items) == 0); - g_hash_table_destroy (self->pv->items); - - g_assert (g_hash_table_size (self->pv->collections) == 0); - g_hash_table_destroy (self->pv->collections); - - G_OBJECT_CLASS (gcr_union_collection_parent_class)->finalize (obj); -} - -static void -gcr_union_collection_class_init (GcrUnionCollectionClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gobject_class->dispose = gcr_union_collection_dispose; - gobject_class->finalize = gcr_union_collection_finalize; - g_type_class_add_private (gobject_class, sizeof (GcrUnionCollectionPrivate)); -} - -static guint -gcr_union_collection_real_get_length (GcrCollection *coll) -{ - GcrUnionCollection *self = GCR_UNION_COLLECTION (coll); - return g_hash_table_size (self->pv->items); -} - -static GList* -gcr_union_collection_real_get_objects (GcrCollection *coll) -{ - GcrUnionCollection *self = GCR_UNION_COLLECTION (coll); - return g_hash_table_get_keys (self->pv->items); -} - -static gboolean -gcr_union_collection_real_contains (GcrCollection *collection, - GObject *object) -{ - GcrUnionCollection *self = GCR_UNION_COLLECTION (collection); - return g_hash_table_lookup (self->pv->items, object) ? TRUE : FALSE; -} - -static void -gcr_collection_iface (GcrCollectionIface *iface) -{ - iface->get_length = gcr_union_collection_real_get_length; - iface->get_objects = gcr_union_collection_real_get_objects; - iface->contains = gcr_union_collection_real_contains; -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_union_collection_new: - * - * Create a new #GcrUnionCollection. - * - * Returns: (transfer full) (type Gcr.UnionCollection): a newly allocated - * collection, which should be freed with g_object_unref() - */ -GcrCollection * -gcr_union_collection_new (void) -{ - return g_object_new (GCR_TYPE_UNION_COLLECTION, NULL); -} - -/** - * gcr_union_collection_add: - * @self: The union collection - * @collection: The collection whose objects to add - * - * Add objects from this collection to the union - */ -void -gcr_union_collection_add (GcrUnionCollection *self, - GcrCollection *collection) -{ - g_return_if_fail (GCR_IS_UNION_COLLECTION (self)); - g_return_if_fail (GCR_IS_COLLECTION (collection)); - gcr_union_collection_take (self, g_object_ref (collection)); -} - -/** - * gcr_union_collection_take: - * @self: The union collection - * @collection: The collection whose objects to add - * - * Add objects from this collection to the union. Do not add an additional - * reference to the collection. - */ -void -gcr_union_collection_take (GcrUnionCollection *self, - GcrCollection *collection) -{ - GList *objects, *l; - - g_return_if_fail (GCR_IS_UNION_COLLECTION (self)); - g_return_if_fail (GCR_IS_COLLECTION (collection)); - g_return_if_fail (!g_hash_table_lookup (self->pv->collections, collection)); - - g_object_ref (collection); - - g_hash_table_insert (self->pv->collections, collection, collection); - connect_to_collection (self, collection); - - objects = gcr_collection_get_objects (collection); - for (l = objects; l != NULL; l = g_list_next (l)) - on_collection_added (collection, l->data, self); - g_list_free (objects); - - g_object_unref (collection); -} - -/** - * gcr_union_collection_remove: - * @self: The collection - * @collection: The collection whose objects to remove - * - * Remove an object from the collection. - */ -void -gcr_union_collection_remove (GcrUnionCollection *self, - GcrCollection *collection) -{ - GList *objects, *l; - - g_return_if_fail (GCR_IS_UNION_COLLECTION (self)); - g_return_if_fail (GCR_IS_COLLECTION (collection)); - g_return_if_fail (g_hash_table_lookup (self->pv->collections, collection)); - - g_object_ref (collection); - - g_hash_table_remove (self->pv->collections, collection); - disconnect_from_collection (self, collection); - - objects = gcr_collection_get_objects (collection); - for (l = objects; l != NULL; l = g_list_next (l)) - on_collection_removed (collection, l->data, self); - g_list_free (objects); - - g_object_unref (collection); -} - -/** - * gcr_union_collection_have: - * @self: the union collection - * @collection: the collection to check - * - * Check whether the collection is present in the union. - * - * Returns: whether present or not - */ -gboolean -gcr_union_collection_have (GcrUnionCollection *self, - GcrCollection *collection) -{ - g_return_val_if_fail (GCR_IS_UNION_COLLECTION (self), FALSE); - g_return_val_if_fail (GCR_IS_COLLECTION (collection), FALSE); - return g_hash_table_lookup (self->pv->collections, collection) != NULL; -} - -/** - * gcr_union_collection_size: - * @self: the union collection - * - * Return the number of collections in this union. This does not reflect - * the number of objects in the combined collection. - * - * Returns: number of collections inlcuded - */ -guint -gcr_union_collection_size (GcrUnionCollection *self) -{ - g_return_val_if_fail (GCR_IS_UNION_COLLECTION (self), FALSE); - return g_hash_table_size (self->pv->collections); -} diff --git a/gcr/gcr-union-collection.h b/gcr/gcr-union-collection.h deleted file mode 100644 index 4628799b..00000000 --- a/gcr/gcr-union-collection.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef __GCR_UNION_COLLECTION_H__ -#define __GCR_UNION_COLLECTION_H__ - -#include "gcr-base.h" -#include "gcr-collection.h" - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define GCR_TYPE_UNION_COLLECTION (gcr_union_collection_get_type ()) -#define GCR_UNION_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_COLLECTION, GcrUnionCollection)) -#define GCR_UNION_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_COLLECTION, GcrUnionCollectionClass)) -#define GCR_IS_UNION_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_COLLECTION)) -#define GCR_IS_UNION_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_COLLECTION)) -#define GCR_UNION_COLLECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_COLLECTION, GcrUnionCollectionClass)) - -typedef struct _GcrUnionCollection GcrUnionCollection; -typedef struct _GcrUnionCollectionClass GcrUnionCollectionClass; -typedef struct _GcrUnionCollectionPrivate GcrUnionCollectionPrivate; - -struct _GcrUnionCollection { - GObject parent; - - /*< private >*/ - GcrUnionCollectionPrivate *pv; -}; - -struct _GcrUnionCollectionClass { - GObjectClass parent_class; -}; - -GType gcr_union_collection_get_type (void); - -GcrCollection* gcr_union_collection_new (void); - -void gcr_union_collection_add (GcrUnionCollection *self, - GcrCollection *collection); - -void gcr_union_collection_take (GcrUnionCollection *self, - GcrCollection *collection); - -void gcr_union_collection_remove (GcrUnionCollection *self, - GcrCollection *collection); - -gboolean gcr_union_collection_have (GcrUnionCollection *self, - GcrCollection *collection); - -guint gcr_union_collection_size (GcrUnionCollection *self); - -G_END_DECLS - -#endif /* __GCR_UNION_COLLECTION_H__ */ diff --git a/gcr/gcr-unlock-options-widget.c b/gcr/gcr-unlock-options-widget.c deleted file mode 100644 index 5721cafa..00000000 --- a/gcr/gcr-unlock-options-widget.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-unlock-options-widget.h" - -#include <glib/gi18n-lib.h> - -/** - * SECTION:gcr-unlock-options-widget - * @title: GcrUnlockOptionsWidget - * @short_description: A widget for unlock options - * - * This widget displays a set of unlock options for the user to select. The user - * can choose between keeping caching the unlock indefinitely, or for a given - * amount of time. - * - * Each option has a different name, for example #GCR_UNLOCK_OPTION_ALWAYS. These - * names are used together with the various functions like - * gcr_unlock_options_widget_get_choice(). - */ - -/** - * GCR_UNLOCK_OPTION_ALWAYS: - * - * Option name for caching unlock indefinitely. - */ - -/** - * GCR_UNLOCK_OPTION_IDLE: - * - * Option name for caching unlock for a certain amount of idle time. - */ - -/** - * GCR_UNLOCK_OPTION_SESSION: - * - * Option name for caching unlock for the current session. - */ - -/** - * GCR_UNLOCK_OPTION_TIMEOUT: - * - * Option name for caching unlock for a certain amount of time. - */ - -/** - * GcrUnlockOptionsWidget: - * - * An unlock options widget. - */ - -/** - * GcrUnlockOptionsWidgetClass: - * - * Class for #GcrUnlockOptionsWidget. - */ - -enum { - PROP_0, - PROP_CHOICE, - PROP_TTL -}; - -struct _GcrUnlockOptionsWidget { - GtkAlignment parent; - - /*< private >*/ - GcrUnlockOptionsWidgetPrivate *pv; -}; - -struct _GcrUnlockOptionsWidgetClass { - GtkAlignmentClass parent_class; -}; - -struct _GcrUnlockOptionsWidgetPrivate { - GtkBuilder *builder; - gchar *choice; -}; - -G_DEFINE_TYPE (GcrUnlockOptionsWidget, gcr_unlock_options_widget, GTK_TYPE_ALIGNMENT); - -/* ----------------------------------------------------------------------------- - * INTERNAL - */ - -static GtkToggleButton* -builder_get_toggle_button (GtkBuilder *builder, const gchar *name) -{ - GObject *object = gtk_builder_get_object (builder, name); - g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (object), NULL); - return GTK_TOGGLE_BUTTON (object); -} - -static GtkSpinButton* -builder_get_spin_button (GtkBuilder *builder, const gchar *name) -{ - GObject *object = gtk_builder_get_object (builder, name); - g_return_val_if_fail (GTK_IS_SPIN_BUTTON (object), NULL); - return GTK_SPIN_BUTTON (object); -} - -static const gchar* -widget_name_for_option (const gchar *option) -{ - g_return_val_if_fail (option, NULL); - if (g_str_equal (option, GCR_UNLOCK_OPTION_ALWAYS)) - return "lock_always_choice"; - else if (g_str_equal (option, GCR_UNLOCK_OPTION_SESSION)) - return "lock_session_choice"; - else if (g_str_equal (option, GCR_UNLOCK_OPTION_TIMEOUT)) - return "lock_timeout_choice"; - else if (g_str_equal (option, GCR_UNLOCK_OPTION_IDLE)) - return "lock_idle_choice"; - else - return NULL; -} - -static GtkToggleButton* -widget_button_for_option (GcrUnlockOptionsWidget *self, const gchar *option) -{ - const gchar *name = widget_name_for_option (option); - g_return_val_if_fail (name, NULL); - return builder_get_toggle_button (self->pv->builder, name); -} - -static const gchar* -widget_button_to_option (GcrUnlockOptionsWidget *self, GtkToggleButton *button) -{ - const gchar *option; - g_return_val_if_fail (button, NULL); - option = g_object_get_data (G_OBJECT (button), "unlock-choice"); - g_return_val_if_fail (option, NULL); - return option; -} - -static void -on_choice_toggled (GtkToggleButton *button, GcrUnlockOptionsWidget *self) -{ - GtkWidget *spin; - GtkToggleButton *after, *idle; - - spin = GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "lock_minutes_spin")); - after = builder_get_toggle_button (self->pv->builder, "lock_timeout_choice"); - idle = builder_get_toggle_button (self->pv->builder, "lock_idle_choice"); - gtk_widget_set_sensitive (spin, gtk_toggle_button_get_active (after) || - gtk_toggle_button_get_active (idle)); - - if (gtk_toggle_button_get_active (button)) { - g_free (self->pv->choice); - self->pv->choice = g_strdup (widget_button_to_option (self, button)); - } -} - -/* ----------------------------------------------------------------------------- - * OBJECT - */ - - -static GObject* -gcr_unlock_options_widget_constructor (GType type, guint n_props, GObjectConstructParam *props) -{ - GObject *obj = G_OBJECT_CLASS (gcr_unlock_options_widget_parent_class)->constructor (type, n_props, props); - GcrUnlockOptionsWidget *self = NULL; - GtkToggleButton *button; - GtkWidget *widget; - - if (obj) { - self = GCR_UNLOCK_OPTIONS_WIDGET (obj); - - if (!gtk_builder_add_from_file (self->pv->builder, UIDIR "gcr-unlock-options-widget.ui", NULL)) - g_return_val_if_reached (obj); - - widget = GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "unlock-options-widget")); - g_return_val_if_fail (GTK_IS_WIDGET (widget), obj); - gtk_container_add (GTK_CONTAINER (self), widget); - gtk_widget_show (widget); - - button = builder_get_toggle_button (self->pv->builder, "lock_always_choice"); - g_signal_connect (button, "toggled", G_CALLBACK (on_choice_toggled), self); - g_object_set_data (G_OBJECT (button), "unlock-choice", GCR_UNLOCK_OPTION_ALWAYS); - - button = builder_get_toggle_button (self->pv->builder, "lock_session_choice"); - g_signal_connect (button, "toggled", G_CALLBACK (on_choice_toggled), self); - g_object_set_data (G_OBJECT (button), "unlock-choice", GCR_UNLOCK_OPTION_SESSION); - on_choice_toggled (button, self); - - button = builder_get_toggle_button (self->pv->builder, "lock_timeout_choice"); - g_signal_connect (button, "toggled", G_CALLBACK (on_choice_toggled), self); - g_object_set_data (G_OBJECT (button), "unlock-choice", GCR_UNLOCK_OPTION_TIMEOUT); - - button = builder_get_toggle_button (self->pv->builder, "lock_idle_choice"); - g_signal_connect (button, "toggled", G_CALLBACK (on_choice_toggled), self); - g_object_set_data (G_OBJECT (button), "unlock-choice", GCR_UNLOCK_OPTION_IDLE); - } - - return obj; -} - -static void -gcr_unlock_options_widget_init (GcrUnlockOptionsWidget *self) -{ - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_UNLOCK_OPTIONS_WIDGET, GcrUnlockOptionsWidgetPrivate)); - self->pv->builder = gtk_builder_new (); -} - -static void -gcr_unlock_options_widget_dispose (GObject *obj) -{ - GcrUnlockOptionsWidget *self = GCR_UNLOCK_OPTIONS_WIDGET (obj); - - if (self->pv->builder) - g_object_unref (self->pv->builder); - self->pv->builder = NULL; - - G_OBJECT_CLASS (gcr_unlock_options_widget_parent_class)->dispose (obj); -} - -static void -gcr_unlock_options_widget_finalize (GObject *obj) -{ - GcrUnlockOptionsWidget *self = GCR_UNLOCK_OPTIONS_WIDGET (obj); - - g_assert (!self->pv->builder); - g_free (self->pv->choice); - self->pv->choice = NULL; - - G_OBJECT_CLASS (gcr_unlock_options_widget_parent_class)->finalize (obj); -} - -static void -gcr_unlock_options_widget_set_property (GObject *obj, guint prop_id, const GValue *value, - GParamSpec *pspec) -{ - GcrUnlockOptionsWidget *self = GCR_UNLOCK_OPTIONS_WIDGET (obj); - - switch (prop_id) { - case PROP_CHOICE: - gcr_unlock_options_widget_set_choice (self, g_value_get_string (value)); - break; - case PROP_TTL: - gcr_unlock_options_widget_set_ttl (self, g_value_get_uint (value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_unlock_options_widget_get_property (GObject *obj, guint prop_id, GValue *value, - GParamSpec *pspec) -{ - GcrUnlockOptionsWidget *self = GCR_UNLOCK_OPTIONS_WIDGET (obj); - - switch (prop_id) { - case PROP_CHOICE: - g_value_set_string (value, gcr_unlock_options_widget_get_choice (self)); - break; - case PROP_TTL: - g_value_set_uint (value, gcr_unlock_options_widget_get_ttl (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_unlock_options_widget_class_init (GcrUnlockOptionsWidgetClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gcr_unlock_options_widget_parent_class = g_type_class_peek_parent (klass); - g_type_class_add_private (klass, sizeof (GcrUnlockOptionsWidgetPrivate)); - - gobject_class->constructor = gcr_unlock_options_widget_constructor; - gobject_class->dispose = gcr_unlock_options_widget_dispose; - gobject_class->finalize = gcr_unlock_options_widget_finalize; - gobject_class->set_property = gcr_unlock_options_widget_set_property; - gobject_class->get_property = gcr_unlock_options_widget_get_property; - - g_object_class_install_property (gobject_class, PROP_CHOICE, - g_param_spec_string ("choice", "Choice", "Unlock Option Choice", - NULL, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_TTL, - g_param_spec_uint ("ttl", "TTL", "Unlock Option Timeout in Seconds", - 0, G_MAXUINT, 0, G_PARAM_READWRITE)); -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_unlock_options_widget_new: - * - * Create a new #GcrUnlockOptionsWidget. - * - * Returns: (transfer full) (type Gcr.UnlockOptionsWidget): a new #GcrUnlockOptionsWidget - */ -GtkWidget * -gcr_unlock_options_widget_new (void) -{ - return g_object_new (GCR_TYPE_UNLOCK_OPTIONS_WIDGET, NULL); -} - -/** - * gcr_unlock_options_widget_get_choice: - * @self: The unlock options widget - * - * Get the currently selected option, like %GCR_UNLOCK_OPTION_ALWAYS. - * - * Returns: The currently selected option name. - */ -const gchar* -gcr_unlock_options_widget_get_choice (GcrUnlockOptionsWidget *self) -{ - g_return_val_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self), NULL); - return self->pv->choice; -} - -/** - * gcr_unlock_options_widget_set_choice: - * @self: The unlock options widget - * @option: The option name - * - * Set the currently selected option. Use an option name like - * %GCR_UNLOCK_OPTION_ALWAYS. - */ -void -gcr_unlock_options_widget_set_choice (GcrUnlockOptionsWidget *self, const gchar *option) -{ - GtkToggleButton *button; - - g_return_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self)); - g_return_if_fail (option); - - button = widget_button_for_option (self, option); - gtk_toggle_button_set_active (button, TRUE); -} - -/** - * gcr_unlock_options_widget_get_ttl: - * @self: The unlock options widget - * - * Get the timeout setting set for unlock options that have a timeout. - * This will also return a valid value if the currently selected option - * does not have a timeout. - * - * Returns: The unlock timeout in seconds. - */ -guint -gcr_unlock_options_widget_get_ttl (GcrUnlockOptionsWidget *self) -{ - GtkSpinButton *spin; - gint amount; - - g_return_val_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self), 0); - - spin = builder_get_spin_button (self->pv->builder, "lock_minutes_spin"); - amount = gtk_spin_button_get_value_as_int (spin); - return amount * 60; -} - -/** - * gcr_unlock_options_widget_set_ttl: - * @self: The unlock options widget - * @ttl: The timeout to set, in seconds - * - * Set the current setting for the timeout. This can be set even when the - * currently selected option does not have a timeout. - */ -void -gcr_unlock_options_widget_set_ttl (GcrUnlockOptionsWidget *self, guint ttl) -{ - GtkSpinButton *spin; - guint amount; - - g_return_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self)); - - amount = ttl / 60; - if (!amount || ttl % 60) - amount += 1; - - spin = builder_get_spin_button (self->pv->builder, "lock_minutes_spin"); - gtk_spin_button_set_value (spin, amount); -} - -/** - * gcr_unlock_options_widget_get_label: - * @self: The unlock options widget - * @option: The option name - * - * Get the label for one of the options. Use an option name like - * %GCR_UNLOCK_OPTION_ALWAYS. - * - * Returns: The current label for the option. - */ -const gchar* -gcr_unlock_options_widget_get_label (GcrUnlockOptionsWidget *self, const gchar *option) -{ - GtkToggleButton *button; - const gchar *name; - - g_return_val_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self), NULL); - g_return_val_if_fail (option, NULL); - - name = widget_name_for_option (option); - g_return_val_if_fail (name, NULL); - - button = builder_get_toggle_button (self->pv->builder, name); - g_return_val_if_fail (button, NULL); - - return gtk_button_get_label (GTK_BUTTON (button)); -} - -/** - * gcr_unlock_options_widget_set_label: - * @self: The unlock options widget - * @option: The option name - * @text: The new label - * - * Set the label for one of the options. Use an option name like - * %GCR_UNLOCK_OPTION_ALWAYS. - */ -void -gcr_unlock_options_widget_set_label (GcrUnlockOptionsWidget *self, const gchar *option, - const gchar *text) -{ - GtkToggleButton *button; - const gchar *name; - - g_return_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self)); - g_return_if_fail (option); - g_return_if_fail (text); - - name = widget_name_for_option (option); - g_return_if_fail (name); - - button = builder_get_toggle_button (self->pv->builder, name); - g_return_if_fail (button); - - gtk_button_set_label (GTK_BUTTON (button), text); -} - -/** - * gcr_unlock_options_widget_get_sensitive: - * @self: The unlock options widget - * @option: The option name - * - * Get the sensitivity state for one of the options. Use an option name like - * %GCR_UNLOCK_OPTION_ALWAYS. - * - * Returns: Whether the option is sensitive or not. - */ -gboolean -gcr_unlock_options_widget_get_sensitive (GcrUnlockOptionsWidget *self, const gchar *option) -{ - GtkToggleButton *button; - GtkStateType state; - - g_return_val_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self), FALSE); - g_return_val_if_fail (option, FALSE); - - button = widget_button_for_option (self, option); - state = gtk_widget_get_state (GTK_WIDGET (button)); - return (state & GTK_STATE_INSENSITIVE) != GTK_STATE_INSENSITIVE; -} - -/** - * gcr_unlock_options_widget_set_sensitive: - * @self: The unlock options widget - * @option: The option name - * @sensitive: The sensitivity state. - * @reason: A user displayable string which contains the reason for the sensitivity. - * - * Set the sensitivity state for one of the options. Use an option name like - * %GCR_UNLOCK_OPTION_ALWAYS. The reason will be displayed as a tooltip. - */ -void -gcr_unlock_options_widget_set_sensitive (GcrUnlockOptionsWidget *self, const gchar *option, - gboolean sensitive, const gchar *reason) -{ - GtkToggleButton *button; - - g_return_if_fail (GCR_IS_UNLOCK_OPTIONS_WIDGET (self)); - g_return_if_fail (option); - - button = widget_button_for_option (self, option); - gtk_widget_set_sensitive (GTK_WIDGET (button), sensitive); - - if (!sensitive && reason) - gtk_widget_set_tooltip_text (GTK_WIDGET (button), reason); - else if (sensitive) - gtk_widget_set_has_tooltip (GTK_WIDGET (button), FALSE); -} diff --git a/gcr/gcr-unlock-options-widget.h b/gcr/gcr-unlock-options-widget.h deleted file mode 100644 index ca274f5c..00000000 --- a/gcr/gcr-unlock-options-widget.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_UNLOCK_OPTIONS_WIDGET_H__ -#define __GCR_UNLOCK_OPTIONS_WIDGET_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-types.h" -#include "gcr-unlock-options.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_UNLOCK_OPTIONS_WIDGET (gcr_unlock_options_widget_get_type ()) -#define GCR_UNLOCK_OPTIONS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_UNLOCK_OPTIONS_WIDGET, GcrUnlockOptionsWidget)) -#define GCR_UNLOCK_OPTIONS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_UNLOCK_OPTIONS_WIDGET, GcrUnlockOptionsWidgetClass)) -#define GCR_IS_UNLOCK_OPTIONS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_UNLOCK_OPTIONS_WIDGET)) -#define GCR_IS_UNLOCK_OPTIONS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_UNLOCK_OPTIONS_WIDGET)) -#define GCR_UNLOCK_OPTIONS_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_UNLOCK_OPTIONS_WIDGET, GcrUnlockOptionsWidgetClass)) - -typedef struct _GcrUnlockOptionsWidget GcrUnlockOptionsWidget; -typedef struct _GcrUnlockOptionsWidgetClass GcrUnlockOptionsWidgetClass; -typedef struct _GcrUnlockOptionsWidgetPrivate GcrUnlockOptionsWidgetPrivate; - -/* - * TODO: GcrUnlockOptionsWidget and GcrUnlockOptionsWidgetClass are hidden until - * we can figure out what they should be derived from. - */ - -GType gcr_unlock_options_widget_get_type (void); - -GtkWidget* gcr_unlock_options_widget_new (void); - -const gchar* gcr_unlock_options_widget_get_choice (GcrUnlockOptionsWidget *self); - -void gcr_unlock_options_widget_set_choice (GcrUnlockOptionsWidget *self, - const gchar *option); - -guint gcr_unlock_options_widget_get_ttl (GcrUnlockOptionsWidget *self); - -void gcr_unlock_options_widget_set_ttl (GcrUnlockOptionsWidget *self, - guint ttl); - -const gchar* gcr_unlock_options_widget_get_label (GcrUnlockOptionsWidget *self, - const gchar *option); - -void gcr_unlock_options_widget_set_label (GcrUnlockOptionsWidget *self, - const gchar *option, - const gchar *text); - -gboolean gcr_unlock_options_widget_get_sensitive (GcrUnlockOptionsWidget *self, - const gchar *option); - -void gcr_unlock_options_widget_set_sensitive (GcrUnlockOptionsWidget *self, - const gchar *option, - gboolean sensitive, - const gchar *reason); - -G_END_DECLS - -#endif /* __GCR_UNLOCK_OPTIONS_WIDGET_H__ */ diff --git a/gcr/gcr-unlock-options-widget.ui b/gcr/gcr-unlock-options-widget.ui deleted file mode 100644 index ef59144d..00000000 --- a/gcr/gcr-unlock-options-widget.ui +++ /dev/null @@ -1,117 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - <requires lib="gtk+" version="2.16"/> - <!-- interface-naming-policy project-wide --> - <object class="GtkAdjustment" id="spin_adjustment"> - <property name="lower">1</property> - <property name="upper">999</property> - <property name="step_increment">1</property> - <property name="page_increment">10</property> - </object> - <object class="GtkVBox" id="unlock-options-widget"> - <property name="visible">True</property> - <property name="spacing">6</property> - <child> - <object class="GtkRadioButton" id="lock_always_choice"> - <property name="label" translatable="yes">Automatically unlock this keyring whenever I'm logged in</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="active">True</property> - <property name="draw_indicator">True</property> - <property name="group">lock_session_choice</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkRadioButton" id="lock_session_choice"> - <property name="label" translatable="yes">Lock this keyring when I log out</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="active">True</property> - <property name="draw_indicator">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkHBox" id="hbox2"> - <property name="visible">True</property> - <property name="spacing">6</property> - <child> - <object class="GtkVBox" id="vbox5"> - <property name="visible">True</property> - <property name="spacing">6</property> - <child> - <object class="GtkRadioButton" id="lock_timeout_choice"> - <property name="label" translatable="yes">Lock this keyring after</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="draw_indicator">True</property> - <property name="group">lock_session_choice</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkRadioButton" id="lock_idle_choice"> - <property name="label" translatable="yes">Lock this keyring if idle for</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="draw_indicator">True</property> - <property name="group">lock_session_choice</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSpinButton" id="lock_minutes_spin"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">•</property> - <property name="adjustment">spin_adjustment</property> - <property name="climb_rate">1</property> - <property name="numeric">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkLabel" id="label2"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes" comments="Translators: The 'minutes' from 'Lock this keyring if idle for x minutes'.">minutes</property> - </object> - <packing> - <property name="expand">False</property> - <property name="position">2</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="position">2</property> - </packing> - </child> - </object> -</interface> diff --git a/gcr/gcr-unlock-options.h b/gcr/gcr-unlock-options.h deleted file mode 100644 index e4ec6705..00000000 --- a/gcr/gcr-unlock-options.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_UNLOCK_OPTIONS_H__ -#define __GCR_UNLOCK_OPTIONS_H__ - -G_BEGIN_DECLS - -#define GCR_UNLOCK_OPTION_ALWAYS "always" -#define GCR_UNLOCK_OPTION_SESSION "session" -#define GCR_UNLOCK_OPTION_TIMEOUT "timeout" -#define GCR_UNLOCK_OPTION_IDLE "idle" - -G_END_DECLS - -#endif /* __GCR_UNLOCK_OPTIONS_H__ */ diff --git a/gcr/gcr-unlock-renderer.c b/gcr/gcr-unlock-renderer.c deleted file mode 100644 index 4615057f..00000000 --- a/gcr/gcr-unlock-renderer.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-display-view.h" -#include "gcr-icons.h" -#include "gcr-parser.h" -#include "gcr-unlock-renderer.h" - -#include "egg/egg-entry-buffer.h" - -#include <gdk/gdk.h> -#include <glib/gi18n-lib.h> - -enum { - PROP_0, - PROP_LABEL, - PROP_ATTRIBUTES -}; - -struct _GcrUnlockRendererPrivate { - GtkEntry *entry; - GtkLabel *warning; - - gpointer locked_data; - gsize n_locked_data; - gchar *label; - gboolean unlocked; - GList *renderers; - guint unlock_tries; - - /* block widget destroys during render */ - gint no_destroy; -}; - -enum { - UNLOCK_CLICKED, - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static void gcr_renderer_iface_init (GcrRendererIface *iface); - -G_DEFINE_TYPE_WITH_CODE (GcrUnlockRenderer, _gcr_unlock_renderer, GTK_TYPE_ALIGNMENT, - G_IMPLEMENT_INTERFACE (GCR_TYPE_RENDERER, gcr_renderer_iface_init); -); - -static gchar* -calculate_label (GcrUnlockRenderer *self) -{ - if (self->pv->label) - return g_strdup_printf (_("Unlock: %s"), self->pv->label); - - return g_strdup (_("Unlock")); -} - -void -_gcr_unlock_renderer_show_warning (GcrUnlockRenderer *self, - const gchar *message) -{ - gchar *text; - - g_return_if_fail (GCR_UNLOCK_RENDERER (self)); - g_return_if_fail (message != NULL); - - text = g_strdup_printf ("<i>%s</i>", message); - gtk_label_set_markup (self->pv->warning, text); - g_free (text); - - gtk_widget_show (GTK_WIDGET (self->pv->warning)); -} - -static void -on_unlock_button_clicked (GtkButton *button, - gpointer user_data) -{ - GcrUnlockRenderer *self = GCR_UNLOCK_RENDERER (user_data); - g_signal_emit (self, signals[UNLOCK_CLICKED], 0); -} - -static void -on_entry_activated (GtkEntry *entry, - gpointer user_data) -{ - GtkButton *button = GTK_BUTTON (user_data); - gtk_button_clicked (button); -} - -static void -_gcr_unlock_renderer_init (GcrUnlockRenderer *self) -{ - GtkWidget *box, *vbox; - GtkWidget *button; - GtkEntryBuffer *buffer; - - self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_UNLOCK_RENDERER, - GcrUnlockRendererPrivate)); - - box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); - - buffer = egg_entry_buffer_new (); - self->pv->entry = GTK_ENTRY (gtk_entry_new_with_buffer (buffer)); - gtk_entry_set_visibility (self->pv->entry, FALSE); - gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (self->pv->entry), TRUE, FALSE, 0); - gtk_widget_show (GTK_WIDGET (self->pv->entry)); - g_object_unref (buffer); -#if GTK_CHECK_VERSION (3,1,1) - gtk_entry_set_placeholder_text (self->pv->entry, _("Password")); -#endif - - button = gtk_button_new_with_label (_("Unlock")); - gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0); - g_signal_connect (button, "clicked", G_CALLBACK (on_unlock_button_clicked), self); - g_signal_connect (self->pv->entry, "activate", G_CALLBACK (on_entry_activated), button); - gtk_widget_show (button); - - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); - gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0); - gtk_widget_show (box); - - self->pv->warning = GTK_LABEL (gtk_label_new ("")); - gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (self->pv->warning), FALSE, FALSE, 0); - gtk_widget_hide (GTK_WIDGET (self->pv->warning)); - - gtk_container_add (GTK_CONTAINER (self), vbox); - gtk_widget_show (vbox); -} - -static void -_gcr_unlock_renderer_finalize (GObject *obj) -{ - GcrUnlockRenderer *self = GCR_UNLOCK_RENDERER (obj); - - g_free (self->pv->locked_data); - g_free (self->pv->label); - g_list_free_full (self->pv->renderers, g_object_unref); - - G_OBJECT_CLASS (_gcr_unlock_renderer_parent_class)->finalize (obj); -} - -static void -_gcr_unlock_renderer_set_property (GObject *obj, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GcrUnlockRenderer *self = GCR_UNLOCK_RENDERER (obj); - - switch (prop_id) { - case PROP_LABEL: - g_free (self->pv->label); - self->pv->label = g_value_dup_string (value); - g_object_notify (obj, "label"); - gcr_renderer_emit_data_changed (GCR_RENDERER (self)); - break; - case PROP_ATTRIBUTES: - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_unlock_renderer_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GcrUnlockRenderer *self = GCR_UNLOCK_RENDERER (obj); - - switch (prop_id) { - case PROP_LABEL: - g_value_take_string (value, calculate_label (self)); - break; - case PROP_ATTRIBUTES: - g_value_set_boxed (value, NULL); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -_gcr_unlock_renderer_class_init (GcrUnlockRendererClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (GcrUnlockRendererPrivate)); - - gobject_class->finalize = _gcr_unlock_renderer_finalize; - gobject_class->set_property = _gcr_unlock_renderer_set_property; - gobject_class->get_property = _gcr_unlock_renderer_get_property; - - g_object_class_install_property (gobject_class, PROP_LABEL, - g_param_spec_string ("label", "Label", "Unlock Label", - "", G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, - g_param_spec_boxed ("attributes", "Attributes", "Certificate pkcs11 attributes", - GCK_TYPE_ATTRIBUTES, G_PARAM_READWRITE)); - - signals[UNLOCK_CLICKED] = g_signal_new ("unlock-clicked", GCR_TYPE_UNLOCK_RENDERER, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GcrUnlockRendererClass, unlock_clicked), - NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); -} - -static void -gcr_unlock_renderer_render (GcrRenderer *renderer, - GcrViewer *viewer) -{ - GcrUnlockRenderer *self = GCR_UNLOCK_RENDERER (renderer); - GcrDisplayView *view; - gchar *display; - GList *renderers; - GIcon *icon; - GList *l; - - if (GCR_IS_DISPLAY_VIEW (viewer)) { - view = GCR_DISPLAY_VIEW (viewer); - - } else { - g_warning ("GcrUnlockRenderer only works with internal specific " - "GcrViewer returned by gcr_viewer_new()."); - return; - } - - /* - * If we were successfully unlocked, then this will contain a list of - * renderers to add to the viewer. - */ - if (self->pv->unlocked) { - - /* We used prepend above, so list is backwards */ - renderers = g_list_reverse (self->pv->renderers); - self->pv->renderers = NULL; - - for (l = renderers; l != NULL; l = g_list_next (l)) - gcr_viewer_insert_renderer (viewer, l->data, renderer); - g_list_free_full (renderers, g_object_unref); - - /* And finally remove ourselves from the viewer */ - gcr_viewer_remove_renderer (viewer, GCR_RENDERER (self)); - /* - * Not yet unlocked, display the unlock dialog. - */ - } else { - - _gcr_display_view_begin (view, renderer); - - icon = g_themed_icon_new ("emblem-readonly"); - _gcr_display_view_set_icon (view, renderer, icon); - g_object_unref (icon); - - display = calculate_label (self); - _gcr_display_view_append_title (view, renderer, display); - g_free (display); - - if (self->pv->label) - display = g_strdup_printf (_("The contents of '%s' are locked. In order to view the contents, enter the correct password."), - self->pv->label); - else - display = g_strdup (_("The contents are locked. In order to view the contents, enter the correct password.")); - _gcr_display_view_append_content (view, renderer, display, NULL); - g_free (display); - - _gcr_display_view_add_widget_area (view, renderer, GTK_WIDGET (self)); - gtk_widget_show (GTK_WIDGET (self)); - - _gcr_display_view_end (view, renderer); - } -} - -static void -gcr_renderer_iface_init (GcrRendererIface *iface) -{ - iface->render_view = gcr_unlock_renderer_render; -} - -GcrUnlockRenderer* -_gcr_unlock_renderer_new (const gchar *label, - gconstpointer locked_data, - gsize n_locked_data) -{ - GcrUnlockRenderer *renderer; - - renderer = g_object_new (GCR_TYPE_UNLOCK_RENDERER, - "label", label, - NULL); - g_object_ref_sink (renderer); - - renderer->pv->locked_data = g_memdup (locked_data, n_locked_data); - renderer->pv->n_locked_data = n_locked_data; - - return renderer; -} - -GcrUnlockRenderer * -_gcr_unlock_renderer_new_for_parsed (GcrParser *parser) -{ - gconstpointer block; - gsize n_block; - - g_return_val_if_fail (GCR_IS_PARSER (parser), NULL); - - block = gcr_parser_get_parsed_block (parser, &n_block); - return _gcr_unlock_renderer_new (gcr_parser_get_parsed_label (parser), - block, n_block); -} - -const gchar * -_gcr_unlock_renderer_get_password (GcrUnlockRenderer *self) -{ - g_return_val_if_fail (GCR_IS_UNLOCK_RENDERER (self), NULL); - return gtk_entry_get_text (self->pv->entry); -} - -gconstpointer -_gcr_unlock_renderer_get_locked_data (GcrUnlockRenderer *self, - gsize *n_data) -{ - g_return_val_if_fail (GCR_IS_UNLOCK_RENDERER (self), NULL); - g_return_val_if_fail (n_data != NULL, NULL); - *n_data = self->pv->n_locked_data; - return self->pv->locked_data; -} diff --git a/gcr/gcr-unlock-renderer.h b/gcr/gcr-unlock-renderer.h deleted file mode 100644 index bc695b13..00000000 --- a/gcr/gcr-unlock-renderer.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION) -#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly." -#endif - -#ifndef __GCR_UNLOCK_RENDERER_H__ -#define __GCR_UNLOCK_RENDERER_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-renderer.h" -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_UNLOCK_RENDERER (_gcr_unlock_renderer_get_type ()) -#define GCR_UNLOCK_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_UNLOCK_RENDERER, GcrUnlockRenderer)) -#define GCR_UNLOCK_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_UNLOCK_RENDERER, GcrUnlockRendererClass)) -#define GCR_IS_UNLOCK_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_UNLOCK_RENDERER)) -#define GCR_IS_UNLOCK_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_UNLOCK_RENDERER)) -#define GCR_UNLOCK_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_UNLOCK_RENDERER, GcrUnlockRendererClass)) - -typedef struct _GcrUnlockRenderer GcrUnlockRenderer; -typedef struct _GcrUnlockRendererClass GcrUnlockRendererClass; -typedef struct _GcrUnlockRendererPrivate GcrUnlockRendererPrivate; - -struct _GcrUnlockRenderer { - /*< private >*/ - GtkAlignment parent; - GcrUnlockRendererPrivate *pv; -}; - -struct _GcrUnlockRendererClass { - GtkAlignmentClass parent_class; - - /* signals */ - void (*unlock_clicked) (GcrUnlockRenderer *unlock); -}; - -GType _gcr_unlock_renderer_get_type (void); - -GcrUnlockRenderer * _gcr_unlock_renderer_new (const gchar *label, - gconstpointer locked_data, - gsize n_locked_data); - -GcrUnlockRenderer * _gcr_unlock_renderer_new_for_parsed (GcrParser *parser); - -const gchar * _gcr_unlock_renderer_get_password (GcrUnlockRenderer *self); - -void _gcr_unlock_renderer_show_warning (GcrUnlockRenderer *self, - const gchar *message); - -gconstpointer _gcr_unlock_renderer_get_locked_data (GcrUnlockRenderer *self, - gsize *n_data); - -G_END_DECLS - -#endif /* __GCR_UNLOCK_RENDERER_H__ */ diff --git a/gcr/gcr-util.c b/gcr/gcr-util.c deleted file mode 100644 index 418b73cb..00000000 --- a/gcr/gcr-util.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr-util.h" - -#include <string.h> - -/** - * _gcr_util_parse_lines: - * @string: The string to parse lines from, will be modified - * @last_line: Whether or not we should run for last line or not - * @callback: Call for each line - * @user_data: Data for callback - * - * Calls callback for each line. If last_line, also sends the remainder - * data that comes after the last line break. \n and \r\n are line separators. - * Neither are included in data passed to callback. - */ -void -_gcr_util_parse_lines (GString *string, gboolean last_line, - GcrLineCallback callback, gpointer user_data) -{ - gchar *ptr; - gchar *prev; - - g_return_if_fail (string); - g_return_if_fail (callback); - - /* Print all stderr lines as messages */ - while ((ptr = strchr (string->str, '\n')) != NULL) { - *ptr = '\0'; - prev = ptr - 1; - if (*prev == '\r') - *prev = '\0'; - - (callback) (string->str, user_data); - g_string_erase (string, 0, ptr - string->str + 1); - } - - if (last_line && string->len) { - (callback) (string->str, user_data); - g_string_erase (string, 0, string->len); - } -} diff --git a/gcr/gcr-util.h b/gcr/gcr-util.h deleted file mode 100644 index a104a8ec..00000000 --- a/gcr/gcr-util.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef GCR_UTIL_H -#define GCR_UTIL_H - -#include <glib.h> - -G_BEGIN_DECLS - -typedef void (*GcrLineCallback) (const gchar *line, - gpointer user_data); - -void _gcr_util_parse_lines (GString *string, - gboolean last_line, - GcrLineCallback callback, - gpointer user_data); - -G_END_DECLS - -#endif /* __GCR_TOKEN_MANAGER_H__ */ diff --git a/gcr/gcr-viewer-tool.c b/gcr/gcr-viewer-tool.c deleted file mode 100644 index e3510f45..00000000 --- a/gcr/gcr-viewer-tool.c +++ /dev/null @@ -1,130 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* gcr-viewer-tool.c: Command line utility - - Copyright (C) 2011 Collabora Ltd. - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr-viewer-window.h" - -#include <glib/gi18n.h> -#include <gtk/gtk.h> - -#include <locale.h> -#include <stdlib.h> -#include <string.h> - -static gchar **remaining_args = NULL; - -static gboolean -print_version_and_exit (const gchar *option_name, const gchar *value, - gpointer data, GError **error) -{ - g_print("%s -- %s\n", _("GCR Certificate and Key Viewer"), VERSION); - exit (0); - return TRUE; -} - -static const GOptionEntry options[] = { - { "version", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, - print_version_and_exit, N_("Show the application's version"), NULL}, - { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, - &remaining_args, NULL, N_("[file...]") }, - { NULL } -}; - -static gboolean -on_idle_load_files (gpointer user_data) -{ - GcrViewerWindow *window = GCR_VIEWER_WINDOW (user_data); - GFile *file; - gint i; - - if (remaining_args) { - for (i = 0; remaining_args[i] != NULL; ++i) { - file = g_file_new_for_commandline_arg (remaining_args[i]); - gcr_viewer_window_load (window, file); - g_object_unref (file); - } - - g_strfreev (remaining_args); - remaining_args = NULL; - } - - return FALSE; /* Don't run this again */ -} - -static void -on_window_destroy (GtkWidget *widget, - gpointer unused) -{ - gtk_widget_hide (widget); - gtk_main_quit (); -} - -int -main (int argc, char *argv[]) -{ - GOptionContext *context; - GError *error = NULL; - GtkWindow *window; - - g_type_init (); - g_thread_init (NULL); - -#ifdef HAVE_LOCALE_H - /* internationalisation */ - setlocale (LC_ALL, ""); -#endif - -#ifdef HAVE_GETTEXT - bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); - textdomain (GETTEXT_PACKAGE); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); -#endif - - context = g_option_context_new (N_("- View certificate and key files")); - g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); - g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE); - - g_option_context_add_group (context, gtk_get_option_group (TRUE)); - - if (! g_option_context_parse (context, &argc, &argv, &error)) { - g_critical ("Failed to parse arguments: %s", error->message); - g_error_free (error); - g_option_context_free (context); - return 1; - } - - g_option_context_free (context); - g_set_application_name (_("Certificate Viewer")); - - gtk_init (&argc, &argv); - - window = gcr_viewer_window_new (); - gtk_widget_show (GTK_WIDGET (window)); - - g_idle_add (on_idle_load_files, window); - g_signal_connect (window, "destroy", G_CALLBACK (on_window_destroy), NULL); - gtk_main (); - - return 0; -} diff --git a/gcr/gcr-viewer-widget.c b/gcr/gcr-viewer-widget.c deleted file mode 100644 index 6e065994..00000000 --- a/gcr/gcr-viewer-widget.c +++ /dev/null @@ -1,504 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* gcr-viewer-widget: Widget for viewer - - Copyright (C) 2011 Collabora Ltd. - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr-display-scrolled.h" -#include "gcr-failure-renderer.h" -#include "gcr-importer.h" -#include "gcr-marshal.h" -#include "gcr-parser.h" -#include "gcr-renderer.h" -#include "gcr-unlock-renderer.h" -#include "gcr-viewer-widget.h" -#include "gcr-viewer.h" - -#include <glib/gi18n-lib.h> -#include <gtk/gtk.h> - -#include <locale.h> -#include <string.h> - -/** - * SECTION:gcr-viewer-widget - * @title: GcrViewerWidget - * @short_description: A widget which shows certificates or keys - * - * A viewer widget which can display certificates and keys that are - * located in files. - */ - -enum { - PROP_0, - PROP_PARSER -}; - -/** - * GcrViewerWidget: - * - * A viewer widget object. - */ - -/** - * GcrViewerWidgetClass: - * - * Class for #GcrViewerWidget - */ - -/* - * Not yet figured out how to expose these without locking down our - * implementation, the parent class we derive from. - */ - -struct _GcrViewerWidget { - /*< private >*/ - GcrDisplayScrolled parent; - GcrViewerWidgetPrivate *pv; -}; - -struct _GcrViewerWidgetClass { - GcrDisplayScrolledClass parent_class; - - void (*added) (GcrViewerWidget *widget, - GcrRenderer *renderer, - GcrParsed *parsed); -}; - -struct _GcrViewerWidgetPrivate { - GQueue *files_to_load; - GcrParser *parser; - GCancellable *cancellable; - GList *unlocks; - gboolean loading; - gchar *display_name; -}; - -enum { - ADDED, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0, }; - -static void viewer_load_next_file (GcrViewerWidget *self); -static void viewer_stop_loading_files (GcrViewerWidget *self); - -G_DEFINE_TYPE (GcrViewerWidget, gcr_viewer_widget, GCR_TYPE_DISPLAY_SCROLLED); - -static const gchar * -get_parsed_label_or_display_name (GcrViewerWidget *self, - GcrParser *parser) -{ - const gchar *label; - - label = gcr_parser_get_parsed_label (parser); - if (label == NULL) - label = self->pv->display_name; - - return label; -} - -static void -on_parser_parsed (GcrParser *parser, - gpointer user_data) -{ - GcrViewerWidget *self = GCR_VIEWER_WIDGET (user_data); - GckAttributes *attrs; - GcrRenderer *renderer; - const gchar *label; - gboolean actual = TRUE; - - label = get_parsed_label_or_display_name (self, parser); - attrs = gcr_parser_get_parsed_attributes (parser); - - renderer = gcr_renderer_create (label, attrs); - - if (renderer == NULL) { - renderer = gcr_failure_renderer_new_unsupported (label); - actual = FALSE; - } - - /* And show the data */ - gcr_viewer_add_renderer (GCR_VIEWER (self), renderer); - - /* Let callers know we're rendering data */ - if (actual == TRUE) - g_signal_emit (self, signals[ADDED], 0, renderer, - gcr_parser_get_parsed (parser)); - - g_object_unref (renderer); -} - -static gboolean -on_parser_authenticate_for_unlock (GcrParser *parser, - guint count, - gpointer user_data) -{ - GcrUnlockRenderer *unlock = GCR_UNLOCK_RENDERER (user_data); - const gchar *password; - - if (count == 0) { - password = _gcr_unlock_renderer_get_password (unlock); - gcr_parser_add_password (parser, password); - } - - return TRUE; -} - -static void -on_unlock_renderer_clicked (GcrUnlockRenderer *unlock, - gpointer user_data) -{ - GcrViewerWidget *self = GCR_VIEWER_WIDGET (user_data); - GError *error = NULL; - gconstpointer data; - gsize n_data; - gulong sig; - - /* Override our main authenticate signal handler */ - sig = g_signal_connect (self->pv->parser, "authenticate", - G_CALLBACK (on_parser_authenticate_for_unlock), unlock); - - data = _gcr_unlock_renderer_get_locked_data (unlock, &n_data); - if (gcr_parser_parse_data (self->pv->parser, data, n_data, &error)) { - - /* Done with this unlock renderer */ - gcr_viewer_remove_renderer (GCR_VIEWER (self), GCR_RENDERER (unlock)); - self->pv->unlocks = g_list_remove (self->pv->unlocks, unlock); - g_object_unref (unlock); - - } else if (g_error_matches (error, GCR_DATA_ERROR, GCR_ERROR_LOCKED)){ - _gcr_unlock_renderer_show_warning (unlock, _("The password was incorrect")); - g_error_free (error); - - } else { - _gcr_unlock_renderer_show_warning (unlock, error->message); - g_error_free (error); - } - - g_signal_handler_disconnect (self->pv->parser, sig); -} - -static gboolean -on_parser_authenticate_for_data (GcrParser *parser, - guint count, - gpointer user_data) -{ - GcrViewerWidget *self = GCR_VIEWER_WIDGET (user_data); - GcrUnlockRenderer *unlock; - - unlock = _gcr_unlock_renderer_new_for_parsed (parser); - if (unlock != NULL) { - g_object_set (unlock, "label", get_parsed_label_or_display_name (self, parser), NULL); - gcr_viewer_add_renderer (GCR_VIEWER (self), GCR_RENDERER (unlock)); - g_signal_connect (unlock, "unlock-clicked", G_CALLBACK (on_unlock_renderer_clicked), self); - self->pv->unlocks = g_list_prepend (self->pv->unlocks, unlock); - } - - return TRUE; -} - -static void -gcr_viewer_widget_init (GcrViewerWidget *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_VIEWER_WIDGET, - GcrViewerWidgetPrivate); - - self->pv->files_to_load = g_queue_new (); - self->pv->parser = gcr_parser_new (); - self->pv->cancellable = g_cancellable_new (); - self->pv->unlocks = NULL; - - g_signal_connect (self->pv->parser, "parsed", G_CALLBACK (on_parser_parsed), self); - g_signal_connect_after (self->pv->parser, "authenticate", G_CALLBACK (on_parser_authenticate_for_data), self); -} - -static void -gcr_viewer_widget_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GcrViewerWidget *self = GCR_VIEWER_WIDGET (obj); - - switch (prop_id) { - case PROP_PARSER: - g_value_set_object (value, gcr_viewer_widget_get_parser (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -gcr_viewer_widget_dispose (GObject *obj) -{ - GcrViewerWidget *self = GCR_VIEWER_WIDGET (obj); - GList *l; - - g_signal_handlers_disconnect_by_func (self->pv->parser, on_parser_parsed, self); - - for (l = self->pv->unlocks; l != NULL; l = g_list_next (l)) { - g_signal_handlers_disconnect_by_func (l->data, on_unlock_renderer_clicked, self); - g_object_unref (l->data); - } - g_list_free (self->pv->unlocks); - self->pv->unlocks = NULL; - - while (!g_queue_is_empty (self->pv->files_to_load)) - g_object_unref (g_queue_pop_head (self->pv->files_to_load)); - - g_cancellable_cancel (self->pv->cancellable); - - G_OBJECT_CLASS (gcr_viewer_widget_parent_class)->dispose (obj); -} - -static void -gcr_viewer_widget_finalize (GObject *obj) -{ - GcrViewerWidget *self = GCR_VIEWER_WIDGET (obj); - - g_assert (g_queue_is_empty (self->pv->files_to_load)); - g_queue_free (self->pv->files_to_load); - - g_free (self->pv->display_name); - g_object_unref (self->pv->cancellable); - g_object_unref (self->pv->parser); - - G_OBJECT_CLASS (gcr_viewer_widget_parent_class)->finalize (obj); -} - -static void -gcr_viewer_widget_class_init (GcrViewerWidgetClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->dispose = gcr_viewer_widget_dispose; - gobject_class->finalize = gcr_viewer_widget_finalize; - gobject_class->get_property = gcr_viewer_widget_get_property; - - /** - * GcrViewerWidget:parser: - * - * The parser used to parse loaded data into viewable items. - */ - g_object_class_install_property (gobject_class, PROP_PARSER, - g_param_spec_object ("parser", "Parser", "Parser used to parse viewable items", - GCR_TYPE_PARSER, G_PARAM_READABLE)); - - g_type_class_add_private (klass, sizeof (GcrViewerWidget)); - - /** - * GcrViewerWidget::added: - * @self: the viewer widget - * @renderer: (type Gcr.Renderer): the renderer that was added - * @parsed: (type Gcr.Parsed): the parsed item that was added - * - * This signal is emitted when an item is added to the viewer widget. - */ - signals[ADDED] = g_signal_new ("added", GCR_TYPE_VIEWER_WIDGET, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GcrViewerWidgetClass, added), - NULL, NULL, _gcr_marshal_VOID__OBJECT_BOXED, - G_TYPE_NONE, 2, G_TYPE_OBJECT, GCR_TYPE_PARSED); -} - -static void -on_parser_parse_stream_returned (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GcrViewerWidget *self = GCR_VIEWER_WIDGET (user_data); - GError *error = NULL; - GcrRenderer *renderer; - - gcr_parser_parse_stream_finish (self->pv->parser, result, &error); - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) || - g_error_matches (error, GCR_DATA_ERROR, GCR_ERROR_CANCELLED)) { - viewer_stop_loading_files (self); - - } else if (g_error_matches (error, GCR_DATA_ERROR, GCR_ERROR_LOCKED)) { - /* Just skip this one, an unlock renderer was added */ - - } else if (error) { - renderer = gcr_failure_renderer_new (self->pv->display_name, error); - gcr_viewer_add_renderer (GCR_VIEWER (self), renderer); - g_object_unref (renderer); - g_error_free (error); - } - - viewer_load_next_file (self); -} - -static void -update_display_name (GcrViewerWidget *self, - GFile *file) -{ - gchar *basename; - - basename = g_file_get_basename (file); - - g_free (self->pv->display_name); - self->pv->display_name = g_filename_display_name (basename); - - g_free (basename); -} - -static void -on_file_read_returned (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GcrViewerWidget *self = GCR_VIEWER_WIDGET (user_data); - GFile *file = G_FILE (source); - GError *error = NULL; - GFileInputStream *fis; - GcrRenderer *renderer; - - fis = g_file_read_finish (file, result, &error); - update_display_name (self, file); - - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - viewer_stop_loading_files (self); - - } else if (error) { - renderer = gcr_failure_renderer_new (self->pv->display_name, error); - gcr_viewer_add_renderer (GCR_VIEWER (self), renderer); - g_object_unref (renderer); - g_error_free (error); - - viewer_load_next_file (self); - - } else { - gcr_parser_parse_stream_async (self->pv->parser, G_INPUT_STREAM (fis), - self->pv->cancellable, on_parser_parse_stream_returned, - self); - g_object_unref (fis); - } -} - -static void -viewer_stop_loading_files (GcrViewerWidget *self) -{ - self->pv->loading = FALSE; -} - -static void -viewer_load_next_file (GcrViewerWidget *self) -{ - GFile* file; - - file = g_queue_pop_head (self->pv->files_to_load); - if (file == NULL) { - viewer_stop_loading_files (self); - return; - } - - g_file_read_async (file, G_PRIORITY_DEFAULT, self->pv->cancellable, - on_file_read_returned, self); - - g_object_unref (file); -} - -/** - * gcr_viewer_widget_new: - * - * Create a new viewer widget. - * - * Returns: (transfer full): A new #GcrViewerWidget object - */ -GcrViewerWidget * -gcr_viewer_widget_new (void) -{ - return g_object_new (GCR_TYPE_VIEWER_WIDGET, NULL); -} - -/** - * gcr_viewer_widget_load_file: - * @self: a viewer widget - * @file: a file to load - * - * Display contents of a file in the viewer widget. Multiple files can - * be loaded. - */ -void -gcr_viewer_widget_load_file (GcrViewerWidget *self, - GFile *file) -{ - g_return_if_fail (GCR_IS_VIEWER_WIDGET (self)); - g_return_if_fail (G_IS_FILE (file)); - - g_queue_push_tail (self->pv->files_to_load, g_object_ref (file)); - - if (!self->pv->loading) - viewer_load_next_file (self); -} - -/** - * gcr_viewer_widget_load_data: - * @self: a viewer widget - * @display_name: (allow-none): label for the loaded data - * @data: (array length=n_data): data to load - * @n_data: length of data to load - * - * Parse and load some data to be displayed into the viewer widgets. The data - * may contain multiple parseable items if the format can contain multiple - * items. - */ -void -gcr_viewer_widget_load_data (GcrViewerWidget *self, - const gchar *display_name, - const guchar *data, - gsize n_data) -{ - GError *error = NULL; - GcrRenderer *renderer; - - g_return_if_fail (GCR_IS_VIEWER_WIDGET (self)); - - g_free (self->pv->display_name); - self->pv->display_name = g_strdup (display_name); - - if (!gcr_parser_parse_data (self->pv->parser, data, n_data, &error)) { - renderer = gcr_failure_renderer_new (display_name, error); - gcr_viewer_add_renderer (GCR_VIEWER (self), renderer); - g_object_unref (renderer); - g_error_free (error); - } -} - -/** - * gcr_viewer_widget_get_parser: - * @self: a viewer widget - * - * Get the parser used to parse loaded data into viewable items. - * - * Returns: (transfer none): the parser - */ -GcrParser * -gcr_viewer_widget_get_parser (GcrViewerWidget *self) -{ - g_return_val_if_fail (GCR_IS_VIEWER_WIDGET (self), NULL); - return self->pv->parser; -} diff --git a/gcr/gcr-viewer-widget.h b/gcr/gcr-viewer-widget.h deleted file mode 100644 index 3e1e17e7..00000000 --- a/gcr/gcr-viewer-widget.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* gcr-viewer-widget.h: Widget for viewer - - Copyright (C) 2011 Collabora Ltd. - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#ifndef GCR_VIEWER_WIDGET_H -#define GCR_VIEWER_WIDGET_H - -#include <gtk/gtk.h> - -#define GCR_TYPE_VIEWER_WIDGET (gcr_viewer_widget_get_type ()) -#define GCR_VIEWER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_VIEWER_WIDGET, GcrViewerWidget)) -#define GCR_VIEWER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_VIEWER_WIDGET, GcrViewerWidgetClass)) -#define GCR_IS_VIEWER_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_VIEWER_WIDGET)) -#define GCR_IS_VIEWER_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_VIEWER_WIDGET)) -#define GCR_VIEWER_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_VIEWER_WIDGET, GcrViewerWidgetClass)) - -typedef struct _GcrViewerWidget GcrViewerWidget; -typedef struct _GcrViewerWidgetClass GcrViewerWidgetClass; -typedef struct _GcrViewerWidgetPrivate GcrViewerWidgetPrivate; - - -GType gcr_viewer_widget_get_type (void); - -GcrViewerWidget * gcr_viewer_widget_new (void); - -void gcr_viewer_widget_load_file (GcrViewerWidget *self, - GFile *file); - -void gcr_viewer_widget_load_data (GcrViewerWidget *self, - const gchar *display_name, - const guchar *data, - gsize n_data); - -GcrParser * gcr_viewer_widget_get_parser (GcrViewerWidget *self); - -#endif /* GCR_VIEWER_WIDGET_H */ diff --git a/gcr/gcr-viewer-window.c b/gcr/gcr-viewer-window.c deleted file mode 100644 index c604d18d..00000000 --- a/gcr/gcr-viewer-window.c +++ /dev/null @@ -1,178 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* gcr-viewer-window.c: Window for viewer - - Copyright (C) 2011 Collabora Ltd. - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr-viewer-window.h" - -#include <glib/gi18n-lib.h> -#include <gtk/gtk.h> - -#include <locale.h> -#include <string.h> - -struct _GcrViewerWindowPrivate { - GcrViewerWidget *viewer; - GcrImportButton *import; -}; - -G_DEFINE_TYPE (GcrViewerWindow, gcr_viewer_window, GTK_TYPE_WINDOW); - -static void -on_viewer_renderer_added (GcrViewerWidget *viewer, - GcrRenderer *renderer, - GcrParsed *parsed, - gpointer user_data) -{ - GcrViewerWindow *self = GCR_VIEWER_WINDOW (user_data); - gcr_import_button_add_parsed (self->pv->import, parsed); -} - -static void -gcr_viewer_window_init (GcrViewerWindow *self) -{ - self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_VIEWER_WINDOW, - GcrViewerWindowPrivate); -} - -static void -on_import_button_imported (GcrImportButton *button, - GcrImporter *importer, - GError *error, - gpointer user_data) -{ - GcrViewerWindow *self = GCR_VIEWER_WINDOW (user_data); - GcrRenderer *renderer; - - if (error == NULL) { - g_object_set (button, "label", _("Imported"), NULL); - - } else { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - renderer = gcr_failure_renderer_new (_("Import failed"), error); - gcr_viewer_add_renderer (GCR_VIEWER (self->pv->viewer), renderer); - g_object_unref (renderer); - } - } -} - -static void -on_close_clicked (GtkButton *button, - gpointer user_data) -{ - GcrViewerWindow *self = GCR_VIEWER_WINDOW (user_data); - gtk_widget_destroy (GTK_WIDGET (self)); -} - -static void -gcr_viewer_window_constructed (GObject *obj) -{ - GcrViewerWindow *self = GCR_VIEWER_WINDOW (obj); - GtkWidget *bbox; - GtkWidget *box; - GtkWidget *button; - GtkWidget *align; - - G_OBJECT_CLASS (gcr_viewer_window_parent_class)->constructed (obj); - - bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); - gtk_box_set_spacing (GTK_BOX (bbox), 12); - gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); - gtk_widget_show (bbox); - - self->pv->import = gcr_import_button_new (_("Import")); - g_signal_connect_object (self->pv->import, "imported", - G_CALLBACK (on_import_button_imported), - self, 0); - gtk_widget_show (GTK_WIDGET (self->pv->import)); - - button = gtk_button_new_from_stock (GTK_STOCK_CLOSE); - g_signal_connect_object (button, "clicked", - G_CALLBACK (on_close_clicked), - self, 0); - gtk_widget_show (button); - - gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (bbox), GTK_WIDGET (self->pv->import), FALSE, TRUE, 0); - - align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); - gtk_alignment_set_padding (GTK_ALIGNMENT (align), 0, 0, 0, 12); - gtk_widget_show (align); - gtk_container_add (GTK_CONTAINER (align), bbox); - - self->pv->viewer = gcr_viewer_widget_new (); - g_signal_connect_object (self->pv->viewer, "added", - G_CALLBACK (on_viewer_renderer_added), - self, 0); - gtk_widget_show (GTK_WIDGET (self->pv->viewer)); - - box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_show (box); - - gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (self->pv->viewer), TRUE, TRUE, 0); - gtk_box_pack_start (GTK_BOX (box), align, FALSE, FALSE, 6); - - gtk_container_add (GTK_CONTAINER (self), box); - - gtk_window_set_default_size (GTK_WINDOW (self), 250, 400); -} - -static void -gcr_viewer_window_class_init (GcrViewerWindowClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->constructed = gcr_viewer_window_constructed; - - g_type_class_add_private (klass, sizeof (GcrViewerWindow)); -} - -/** - * gcr_viewer_window_new: - * - * Create a new viewer window. - * - * Returns: (transfer full) (type Gcr.ViewerWindow): a new viewer window - */ -GtkWindow * -gcr_viewer_window_new (void) -{ - return g_object_new (GCR_TYPE_VIEWER_WINDOW, NULL); -} - -/** - * gcr_viewer_window_load: - * @self: a viewer window - * @file: file to load - * - * Load a file into a viewer window. It may not appear immediately. - */ -void -gcr_viewer_window_load (GcrViewerWindow *self, - GFile *file) -{ - g_return_if_fail (GCR_IS_VIEWER_WINDOW (self)); - g_return_if_fail (G_IS_FILE (file)); - - return gcr_viewer_widget_load_file (self->pv->viewer, file); -} diff --git a/gcr/gcr-viewer-window.h b/gcr/gcr-viewer-window.h deleted file mode 100644 index 4ec24203..00000000 --- a/gcr/gcr-viewer-window.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* gcr-viewer-window.h: Window for viewer - - Copyright (C) 2011 Collabora Ltd. - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#ifndef GCR_VIEWER_WINDOW_H -#define GCR_VIEWER_WINDOW_H - -#include <gtk/gtk.h> - -#ifndef GCR_DISABLE_DEPRECATED - -#include "gcr/gcr.h" - -#define GCR_TYPE_VIEWER_WINDOW (gcr_viewer_window_get_type ()) -#define GCR_VIEWER_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_VIEWER_WINDOW, GcrViewerWindow)) -#define GCR_VIEWER_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_VIEWER_WINDOW, GcrViewerWindowClass)) -#define GCR_IS_VIEWER_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_VIEWER_WINDOW)) -#define GCR_IS_VIEWER_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_VIEWER_WINDOW)) -#define GCR_VIEWER_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_VIEWER_WINDOW, GcrViewerWindowClass)) - -typedef struct _GcrViewerWindow GcrViewerWindow; -typedef struct _GcrViewerWindowClass GcrViewerWindowClass; -typedef struct _GcrViewerWindowPrivate GcrViewerWindowPrivate; - -struct _GcrViewerWindow { - /*< private >*/ - GtkWindow parent; - GcrViewerWindowPrivate *pv; -}; - -struct _GcrViewerWindowClass { - /*< private >*/ - GtkWindowClass parent_class; -}; - -GType gcr_viewer_window_get_type (void); - -GtkWindow * gcr_viewer_window_new (void); - -void gcr_viewer_window_load (GcrViewerWindow *self, - GFile *file); - -#endif /* GCR_DISABLE_DEPRECATED */ - -#endif /* GCR_VIEWER_WINDOW_H */ diff --git a/gcr/gcr-viewer.c b/gcr/gcr-viewer.c deleted file mode 100644 index 9cc2ceca..00000000 --- a/gcr/gcr-viewer.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2008 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include "config.h" - -#include "gcr-display-scrolled.h" -#include "gcr-display-view.h" -#include "gcr-renderer.h" -#include "gcr-viewer.h" - -/** - * SECTION:gcr-viewer - * @title: GcrViewer - * @short_description: A viewer which can hold renderers - * - * A #GcrViewer is an abstract interface that represents a widget that can hold - * various renderers and display their contents. - * - * The interaction between #GcrRenderer and #GcrViewer is not stable yet, and - * so viewers cannot be implemented outside the Gcr library at this time. - * - * Use the gcr_viewer_new() and gcr_viewer_new_scrolled() to get default - * implementations of viewers. - */ - -/** - * GcrViewer: - * - * An abstract viewer which displays renderers contents. - */ - -/** - * GcrViewerIface: - * @parent: The parent interface - * @add_renderer: Virtual method to add a renderer - * @insert_renderer: Virtual method to insert a renderer - * @remove_renderer: Virtual method to remove a renderer - * @count_renderers: Virtual method to count renderers - * @get_renderer: Virtual method to get a renderer - * - * The interface for #GcrViewer - */ - -typedef GcrViewerIface GcrViewerInterface; - -G_DEFINE_INTERFACE (GcrViewer, gcr_viewer, GTK_TYPE_WIDGET); - -static void -gcr_viewer_default_init (GcrViewerIface *iface) -{ - -} - -/* ----------------------------------------------------------------------------- - * PUBLIC - */ - -/** - * gcr_viewer_new: - * - * Get an implementation of #GcrViewer that supports a view - * of multiple renderers. - * - * Returns: (transfer full): a newly allocated #GcrViewer, which should be - * released with g_object_unref() - */ -GcrViewer * -gcr_viewer_new (void) -{ - return GCR_VIEWER (_gcr_display_view_new ()); -} - -/** - * gcr_viewer_new_scrolled: - * - * Get an implementation of #GcrViewer that supports a scrolled view - * of multiple renderers. - * - * Returns: (transfer full): a newly allocated #GcrViewer, which should be - * released with g_object_unref() - */ -GcrViewer* -gcr_viewer_new_scrolled (void) -{ - return GCR_VIEWER (_gcr_display_scrolled_new ()); -} - -/** - * gcr_viewer_add_renderer: - * @viewer: The viewer - * @renderer: The renderer to add - * - * Add a renderer to this viewer. - */ -void -gcr_viewer_add_renderer (GcrViewer *viewer, - GcrRenderer *renderer) -{ - g_return_if_fail (GCR_IS_VIEWER (viewer)); - g_return_if_fail (GCR_IS_RENDERER (renderer)); - g_return_if_fail (GCR_VIEWER_GET_INTERFACE (viewer)->add_renderer); - GCR_VIEWER_GET_INTERFACE (viewer)->add_renderer (viewer, renderer); -} - -/** - * gcr_viewer_insert_renderer: - * @viewer: the viewer - * @renderer: the renderer to insert - * @before: (allow-none): the renderer to insert before - * - * Insert a renderer at a specific point in the viewer - */ -void -gcr_viewer_insert_renderer (GcrViewer *viewer, - GcrRenderer *renderer, - GcrRenderer *before) -{ - g_return_if_fail (GCR_IS_VIEWER (viewer)); - g_return_if_fail (GCR_IS_RENDERER (renderer)); - g_return_if_fail (!before || GCR_IS_RENDERER (before)); - g_return_if_fail (GCR_VIEWER_GET_INTERFACE (viewer)->insert_renderer); - GCR_VIEWER_GET_INTERFACE (viewer)->insert_renderer (viewer, renderer, before); -} - -/** - * gcr_viewer_remove_renderer: - * @viewer: The viewer - * @renderer: The renderer to remove - * - * Remove a renderer from this viewer. - */ -void -gcr_viewer_remove_renderer (GcrViewer *viewer, - GcrRenderer *renderer) -{ - g_return_if_fail (GCR_IS_VIEWER (viewer)); - g_return_if_fail (GCR_IS_RENDERER (renderer)); - g_return_if_fail (GCR_VIEWER_GET_INTERFACE (viewer)->remove_renderer); - GCR_VIEWER_GET_INTERFACE (viewer)->remove_renderer (viewer, renderer); -} - -/** - * gcr_viewer_count_renderers: - * @viewer: The viewer - * - * Get the number of renderers present in the viewer. - * - * Returns: The number of renderers. - */ -guint -gcr_viewer_count_renderers (GcrViewer *viewer) -{ - g_return_val_if_fail (GCR_IS_VIEWER (viewer), 0); - g_return_val_if_fail (GCR_VIEWER_GET_INTERFACE (viewer)->count_renderers, 0); - return GCR_VIEWER_GET_INTERFACE (viewer)->count_renderers (viewer); -} - -/** - * gcr_viewer_get_renderer: - * @viewer: The viewer - * @index_: The index of the renderer to get - * - * Get a pointer to the renderer at the given index. It is an error to request - * an index that is out of bounds. - * - * Returns: (transfer none): the render, owned by the viewer - */ -GcrRenderer* -gcr_viewer_get_renderer (GcrViewer *viewer, - guint index_) -{ - g_return_val_if_fail (GCR_IS_VIEWER (viewer), NULL); - g_return_val_if_fail (GCR_VIEWER_GET_INTERFACE (viewer)->get_renderer, NULL); - return GCR_VIEWER_GET_INTERFACE (viewer)->get_renderer (viewer, index_); -} diff --git a/gcr/gcr-viewer.desktop.in.in b/gcr/gcr-viewer.desktop.in.in deleted file mode 100644 index 6cd913a1..00000000 --- a/gcr/gcr-viewer.desktop.in.in +++ /dev/null @@ -1,10 +0,0 @@ -[Desktop Entry] -Name=View file -MimeType=application/pkcs12;application/pkcs12+pem;application/pkcs7-mime;application/pkcs7-mime+pem;application/pkcs8;application/pkcs8+pem;application/pkix-cert;application/pkix-cert+pem;application/pkix-crl;application/pkix-crl+pem;application/x-pem-file;application/x-pem-key;application/x-pkcs12;application/x-pkcs7-certificates;application/x-x509-ca-cert;application/x-x509-user-cert; -Exec=gcr-viewer -Type=Application -Terminal=false -NoDisplay=true -X-GNOME-Bugzilla-Bugzilla=GNOME -X-GNOME-Bugzilla-Product=gnome-keyring -X-GNOME-Bugzilla-Component=gcr
\ No newline at end of file diff --git a/gcr/gcr-viewer.h b/gcr/gcr-viewer.h deleted file mode 100644 index b806cdae..00000000 --- a/gcr/gcr-viewer.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2010 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#ifndef __GCR_VIEWER_H__ -#define __GCR_VIEWER_H__ - -#include <glib-object.h> -#include <gtk/gtk.h> - -#include "gcr-types.h" - -G_BEGIN_DECLS - -#define GCR_TYPE_VIEWER (gcr_viewer_get_type()) -#define GCR_VIEWER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_VIEWER, GcrViewer)) -#define GCR_IS_VIEWER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_VIEWER)) -#define GCR_VIEWER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GCR_TYPE_VIEWER, GcrViewerIface)) - -typedef struct _GcrRenderer GcrRenderer; -typedef struct _GcrViewer GcrViewer; -typedef struct _GcrViewerIface GcrViewerIface; - -struct _GcrViewerIface { - GTypeInterface parent; - - void (*add_renderer) (GcrViewer *viewer, - GcrRenderer *renderer); - - void (*insert_renderer) (GcrViewer *viewer, - GcrRenderer *renderer, - GcrRenderer *before); - - void (*remove_renderer) (GcrViewer *viewer, - GcrRenderer *renderer); - - guint (*count_renderers) (GcrViewer *viewer); - - GcrRenderer* (*get_renderer) (GcrViewer *viewer, - guint index_); - - /*< private >*/ - gpointer dummy1; - gpointer dummy2; - gpointer dummy3; - gpointer dummy4; -}; - -GType gcr_viewer_get_type (void); - -GcrViewer* gcr_viewer_new (void); - -GcrViewer* gcr_viewer_new_scrolled (void); - -void gcr_viewer_add_renderer (GcrViewer *viewer, - GcrRenderer *renderer); - -void gcr_viewer_insert_renderer (GcrViewer *viewer, - GcrRenderer *renderer, - GcrRenderer *before); - -void gcr_viewer_remove_renderer (GcrViewer *viewer, - GcrRenderer *renderer); - -guint gcr_viewer_count_renderers (GcrViewer *viewer); - -GcrRenderer* gcr_viewer_get_renderer (GcrViewer *viewer, - guint index_); - -G_END_DECLS - -#endif /* __GCR_VIEWER_H__ */ diff --git a/gcr/gcr.h b/gcr/gcr.h deleted file mode 100644 index ec150a94..00000000 --- a/gcr/gcr.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#ifndef GCR_API_SUBJECT_TO_CHANGE -#error "This API has not yet reached stability." -#endif - -#ifndef __GCR_H__ -#define __GCR_H__ - -#include <glib.h> - -#include "gcr-base.h" - -#define __GCR_INSIDE_HEADER__ - -#include "gcr-certificate-renderer.h" -#include "gcr-certificate-widget.h" -#include "gcr-collection-model.h" -#include "gcr-column.h" -#include "gcr-combo-selector.h" -#include "gcr-deprecated.h" -#include "gcr-key-renderer.h" -#include "gcr-key-widget.h" -#include "gcr-enum-types.h" -#include "gcr-failure-renderer.h" -#include "gcr-key-renderer.h" -#include "gcr-key-widget.h" -#include "gcr-import-button.h" -#include "gcr-list-selector.h" -#include "gcr-renderer.h" -#include "gcr-tree-selector.h" -#include "gcr-union-collection.h" -#include "gcr-unlock-options-widget.h" -#include "gcr-viewer.h" -#include "gcr-viewer-widget.h" - -#undef __GCR_INSIDE_HEADER__ - -#endif /* __GCR_H__ */ diff --git a/gcr/gcr.pc.in b/gcr/gcr.pc.in deleted file mode 100644 index 47f89358..00000000 --- a/gcr/gcr.pc.in +++ /dev/null @@ -1,16 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ -datarootdir=@datarootdir@ -datadir=@datadir@ -sysconfdir=@sysconfdir@ -pkcs11dir=@P11_MODULE_PATH@ -pkcs11standalonedir=@pkcs11standalonedir@ - -Name: gcr-@GCR_MAJOR@ -Description: GObject and GUI library for high level crypto parsing and display -Version: @VERSION@ -Requires: glib-2.0 gtk+-3.0 gcr-base-@GCR_MAJOR@ gck-@GCK_MAJOR@ p11-kit-1 -Libs: -L${libdir} -lgcr-@GCR_MAJOR@ -Cflags: -I${includedir}/gcr-@GCR_MAJOR@ diff --git a/gcr/gcr.symbols b/gcr/gcr.symbols deleted file mode 100644 index 4cb927e1..00000000 --- a/gcr/gcr.symbols +++ /dev/null @@ -1,103 +0,0 @@ -/* This file lists all exported symbols. It is used to guarantee that we - * only consciously change our ABI. - */ - -gcr_certificate_basics_widget_get_certificate -gcr_certificate_basics_widget_get_type -gcr_certificate_basics_widget_new -gcr_certificate_basics_widget_set_certificate -gcr_certificate_details_widget_get_certificate -gcr_certificate_details_widget_get_type -gcr_certificate_details_widget_new -gcr_certificate_details_widget_set_certificate -gcr_certificate_renderer_get_attributes -gcr_certificate_renderer_get_certificate -gcr_certificate_renderer_get_type -gcr_certificate_renderer_new -gcr_certificate_renderer_new_for_attributes -gcr_certificate_renderer_set_attributes -gcr_certificate_renderer_set_certificate -gcr_certificate_widget_get_attributes -gcr_certificate_widget_get_certificate -gcr_certificate_widget_get_type -gcr_certificate_widget_new -gcr_certificate_widget_set_attributes -gcr_certificate_widget_set_certificate -gcr_collection_model_change_selected -gcr_collection_model_column_for_selected -gcr_collection_model_get_collection -gcr_collection_model_get_selected_objects -gcr_collection_model_get_type -gcr_collection_model_is_selected -gcr_collection_model_iter_for_object -gcr_collection_model_new -gcr_collection_model_new_full -gcr_collection_model_object_for_iter -gcr_collection_model_set_columns -gcr_collection_model_set_selected_objects -gcr_collection_model_toggle_selected -gcr_column_flags_get_type -gcr_combo_selector_get_collection -gcr_combo_selector_get_selected -gcr_combo_selector_get_type -gcr_combo_selector_new -gcr_combo_selector_set_selected -gcr_failure_renderer_get_type -gcr_failure_renderer_new -gcr_failure_renderer_new_unsupported -gcr_import_button_add_parsed -gcr_import_button_get_type -gcr_import_button_new -gcr_key_renderer_get_attributes -gcr_key_renderer_get_type -gcr_key_renderer_new -gcr_key_renderer_set_attributes -gcr_key_widget_get_attributes -gcr_key_widget_get_type -gcr_key_widget_new -gcr_key_widget_set_attributes -gcr_list_selector_get_collection -gcr_list_selector_get_selected -gcr_list_selector_get_type -gcr_list_selector_new -gcr_list_selector_set_selected -gcr_renderer_create -gcr_renderer_emit_data_changed -gcr_renderer_get_type -gcr_renderer_popuplate_popup -gcr_renderer_register -gcr_renderer_register_well_known -gcr_renderer_render -gcr_renderer_render_view -gcr_tree_selector_get_collection -gcr_tree_selector_get_columns -gcr_tree_selector_get_selected -gcr_tree_selector_get_type -gcr_tree_selector_new -gcr_tree_selector_set_selected -gcr_unlock_options_widget_get_choice -gcr_unlock_options_widget_get_label -gcr_unlock_options_widget_get_sensitive -gcr_unlock_options_widget_get_ttl -gcr_unlock_options_widget_get_type -gcr_unlock_options_widget_new -gcr_unlock_options_widget_set_choice -gcr_unlock_options_widget_set_label -gcr_unlock_options_widget_set_sensitive -gcr_unlock_options_widget_set_ttl -gcr_viewer_add_renderer -gcr_viewer_insert_renderer -gcr_viewer_count_renderers -gcr_viewer_get_renderer -gcr_viewer_get_type -gcr_viewer_new -gcr_viewer_new_scrolled -gcr_viewer_remove_renderer -gcr_viewer_window_get_type -gcr_viewer_window_load -gcr_viewer_window_new -gcr_viewer_widget_get_parser -gcr_viewer_widget_get_type -gcr_viewer_widget_load_data -gcr_viewer_widget_load_file -gcr_viewer_widget_new diff --git a/gcr/icons/16x16/Makefile.am b/gcr/icons/16x16/Makefile.am deleted file mode 100644 index ab9cd709..00000000 --- a/gcr/icons/16x16/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -NULL = - -icondir = $(datadir)/icons/hicolor/16x16/apps -icon_DATA = \ - gcr-key.png \ - gcr-key-pair.png \ - gcr-smart-card.png \ - $(NULL) - -EXTRA_DIST = \ - $(icon_DATA) diff --git a/gcr/icons/16x16/gcr-key-pair.png b/gcr/icons/16x16/gcr-key-pair.png Binary files differdeleted file mode 100644 index 01df7686..00000000 --- a/gcr/icons/16x16/gcr-key-pair.png +++ /dev/null diff --git a/gcr/icons/16x16/gcr-key.png b/gcr/icons/16x16/gcr-key.png Binary files differdeleted file mode 100644 index fd056b71..00000000 --- a/gcr/icons/16x16/gcr-key.png +++ /dev/null diff --git a/gcr/icons/16x16/gcr-smart-card.png b/gcr/icons/16x16/gcr-smart-card.png Binary files differdeleted file mode 100644 index 2860eb44..00000000 --- a/gcr/icons/16x16/gcr-smart-card.png +++ /dev/null diff --git a/gcr/icons/22x22/Makefile.am b/gcr/icons/22x22/Makefile.am deleted file mode 100644 index a4d1ba84..00000000 --- a/gcr/icons/22x22/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -NULL = - -icondir = $(datadir)/icons/hicolor/22x22/apps -icon_DATA = \ - gcr-smart-card.png \ - $(NULL) - -EXTRA_DIST = \ - $(icon_DATA) diff --git a/gcr/icons/22x22/gcr-smart-card.png b/gcr/icons/22x22/gcr-smart-card.png Binary files differdeleted file mode 100644 index 65cbcf89..00000000 --- a/gcr/icons/22x22/gcr-smart-card.png +++ /dev/null diff --git a/gcr/icons/24x24/Makefile.am b/gcr/icons/24x24/Makefile.am deleted file mode 100644 index 87c90ad1..00000000 --- a/gcr/icons/24x24/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -NULL = - -icondir = $(datadir)/icons/hicolor/24x24/apps -icon_DATA = \ - gcr-key.png \ - gcr-key-pair.png \ - gcr-smart-card.png \ - $(NULL) - -EXTRA_DIST = \ - $(icon_DATA) diff --git a/gcr/icons/24x24/gcr-key-pair.png b/gcr/icons/24x24/gcr-key-pair.png Binary files differdeleted file mode 100644 index 8ebe2f78..00000000 --- a/gcr/icons/24x24/gcr-key-pair.png +++ /dev/null diff --git a/gcr/icons/24x24/gcr-key.png b/gcr/icons/24x24/gcr-key.png Binary files differdeleted file mode 100644 index 441737c0..00000000 --- a/gcr/icons/24x24/gcr-key.png +++ /dev/null diff --git a/gcr/icons/24x24/gcr-smart-card.png b/gcr/icons/24x24/gcr-smart-card.png Binary files differdeleted file mode 100644 index 833a811e..00000000 --- a/gcr/icons/24x24/gcr-smart-card.png +++ /dev/null diff --git a/gcr/icons/256x256/Makefile.am b/gcr/icons/256x256/Makefile.am deleted file mode 100644 index ee3525ed..00000000 --- a/gcr/icons/256x256/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -NULL = - -icondir = $(datadir)/icons/hicolor/256x256/apps -icon_DATA = \ - gcr-smart-card.png \ - $(NULL) - -EXTRA_DIST = \ - $(icon_DATA) diff --git a/gcr/icons/256x256/gcr-smart-card.png b/gcr/icons/256x256/gcr-smart-card.png Binary files differdeleted file mode 100644 index 156933e1..00000000 --- a/gcr/icons/256x256/gcr-smart-card.png +++ /dev/null diff --git a/gcr/icons/32x32/Makefile.am b/gcr/icons/32x32/Makefile.am deleted file mode 100644 index d19b370b..00000000 --- a/gcr/icons/32x32/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -NULL = - -icondir = $(datadir)/icons/hicolor/32x32/apps -icon_DATA = \ - gcr-key.png \ - gcr-key-pair.png \ - gcr-smart-card.png \ - $(NULL) - -EXTRA_DIST = \ - $(icon_DATA) diff --git a/gcr/icons/32x32/gcr-key-pair.png b/gcr/icons/32x32/gcr-key-pair.png Binary files differdeleted file mode 100644 index e8c5dc2c..00000000 --- a/gcr/icons/32x32/gcr-key-pair.png +++ /dev/null diff --git a/gcr/icons/32x32/gcr-key.png b/gcr/icons/32x32/gcr-key.png Binary files differdeleted file mode 100644 index 29806e8e..00000000 --- a/gcr/icons/32x32/gcr-key.png +++ /dev/null diff --git a/gcr/icons/32x32/gcr-smart-card.png b/gcr/icons/32x32/gcr-smart-card.png Binary files differdeleted file mode 100644 index b4eaa92d..00000000 --- a/gcr/icons/32x32/gcr-smart-card.png +++ /dev/null diff --git a/gcr/icons/48x48/Makefile.am b/gcr/icons/48x48/Makefile.am deleted file mode 100644 index bbfbc075..00000000 --- a/gcr/icons/48x48/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -NULL = - -icondir = $(datadir)/icons/hicolor/48x48/apps -icon_DATA = \ - gcr-key.png \ - gcr-key-pair.png \ - gcr-smart-card.png \ - $(NULL) - -EXTRA_DIST = \ - $(icon_DATA) diff --git a/gcr/icons/48x48/gcr-key-pair.png b/gcr/icons/48x48/gcr-key-pair.png Binary files differdeleted file mode 100644 index 7b623d2f..00000000 --- a/gcr/icons/48x48/gcr-key-pair.png +++ /dev/null diff --git a/gcr/icons/48x48/gcr-key.png b/gcr/icons/48x48/gcr-key.png Binary files differdeleted file mode 100644 index c4ca3557..00000000 --- a/gcr/icons/48x48/gcr-key.png +++ /dev/null diff --git a/gcr/icons/48x48/gcr-smart-card.png b/gcr/icons/48x48/gcr-smart-card.png Binary files differdeleted file mode 100644 index 18f139b1..00000000 --- a/gcr/icons/48x48/gcr-smart-card.png +++ /dev/null diff --git a/gcr/icons/Makefile.am b/gcr/icons/Makefile.am deleted file mode 100644 index cdc16c52..00000000 --- a/gcr/icons/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ - -SUBDIRS = 16x16 22x22 24x24 32x32 48x48 256x256 - -EXTRA_DIST = \ - src \ - render-icons.py - -gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor - -install-data-hook: - @-if test -z "$(DESTDIR)"; then \ - echo "Updating Gtk icon cache."; \ - $(gtk_update_icon_cache); \ - else \ - echo "*** Icon cache not updated. After install, run this:"; \ - echo "*** $(gtk_update_icon_cache)"; \ - fi - -render: - python render-icons.py diff --git a/gcr/icons/key-and-keypair.svg b/gcr/icons/key-and-keypair.svg deleted file mode 100644 index 9fc45b12..00000000 --- a/gcr/icons/key-and-keypair.svg +++ /dev/null @@ -1,3921 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - inkscape:export-ydpi="90.000000" - inkscape:export-xdpi="90.000000" - inkscape:export-filename="/home/lapo/firewall.png" - width="400" - height="300" - id="svg11300" - sodipodi:version="0.32" - inkscape:version="0.48.1 r9760" - sodipodi:docname="seahorse.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - version="1.0" - style="display:inline;enable-background:new"> - <title - id="title4872">Firewall</title> - <sodipodi:namedview - stroke="#ef2929" - fill="#f57900" - id="base" - pagecolor="#474747" - bordercolor="#666666" - borderopacity="0.25490196" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:zoom="4" - inkscape:cx="344.14948" - inkscape:cy="153.42666" - inkscape:current-layer="layer4" - showgrid="true" - inkscape:grid-bbox="true" - inkscape:document-units="px" - inkscape:showpageshadow="false" - inkscape:window-width="1343" - inkscape:window-height="967" - inkscape:window-x="1615" - inkscape:window-y="52" - width="400px" - height="300px" - inkscape:snap-nodes="false" - inkscape:snap-bbox="true" - gridtolerance="10000" - inkscape:object-nodes="true" - inkscape:snap-grids="true" - showguides="true" - inkscape:guide-bbox="true" - inkscape:window-maximized="0" - inkscape:snap-global="true"> - <inkscape:grid - spacingy="1px" - spacingx="1px" - id="grid5883" - type="xygrid" - enabled="true" - visible="true" - empspacing="4" - snapvisiblegridlinesonly="true" /> - <inkscape:grid - type="xygrid" - id="grid11592" - empspacing="2" - visible="true" - enabled="false" - spacingx="0.5px" - spacingy="0.5px" - color="#ff0000" - opacity="0.1254902" - empcolor="#ff0000" - empopacity="0.25098039" - snapvisiblegridlinesonly="true" /> - <sodipodi:guide - orientation="-0.70710678,0.70710678" - position="309.8125,173.625" - id="guide9630" /> - <sodipodi:guide - orientation="1,0" - position="299.99005,217.08178" - id="guide5162" /> - <sodipodi:guide - orientation="0,1" - position="301,232" - id="guide5182" /> - <sodipodi:guide - orientation="0,1" - position="305,165" - id="guide5184" /> - <sodipodi:guide - orientation="0,1" - position="303,114" - id="guide5186" /> - <sodipodi:guide - orientation="0,1" - position="306,81" - id="guide5188" /> - </sodipodi:namedview> - <defs - id="defs3"> - <linearGradient - inkscape:collect="always" - id="linearGradient8002"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop8004" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop8006" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient7994"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop7996" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop7998" /> - </linearGradient> - <linearGradient - id="linearGradient7419" - inkscape:collect="always"> - <stop - id="stop7421" - offset="0" - style="stop-color:#ffffff;stop-opacity:1;" /> - <stop - id="stop7423" - offset="1" - style="stop-color:#e0d684;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient6249"> - <stop - style="stop-color:#c49f00;stop-opacity:0.627451" - offset="0" - id="stop6251" /> - <stop - style="stop-color:#fceca6;stop-opacity:1" - offset="1" - id="stop6253" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient6156"> - <stop - style="stop-color:#c4a000;stop-opacity:1;" - offset="0" - id="stop6158" /> - <stop - style="stop-color:#ffe365;stop-opacity:1" - offset="1" - id="stop6160" /> - </linearGradient> - <linearGradient - id="linearGradient6107"> - <stop - id="stop6109" - offset="0" - style="stop-color:#e0d684;stop-opacity:1" /> - <stop - style="stop-color:#f7f5e3;stop-opacity:1" - offset="0.25" - id="stop6115" /> - <stop - style="stop-color:#e5e3ae;stop-opacity:1;" - offset="0.5" - id="stop6113" /> - <stop - id="stop6111" - offset="1" - style="stop-color:#ebf0d8;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient17780"> - <stop - style="stop-color:#888a85;stop-opacity:1;" - offset="0" - id="stop17782" /> - <stop - style="stop-color:#e2e2e1;stop-opacity:1" - offset="1" - id="stop17784" /> - </linearGradient> - <linearGradient - id="linearGradient17752"> - <stop - style="stop-color:#d3d7cf;stop-opacity:1" - offset="0" - id="stop17754" /> - <stop - style="stop-color:#f6f6f5;stop-opacity:1" - offset="0.28330287" - id="stop17756" /> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="0.33564273" - id="stop17758" /> - <stop - id="stop17760" - offset="0.6530382" - style="stop-color:#ffffff;stop-opacity:1" /> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="1" - id="stop17762" /> - </linearGradient> - <linearGradient - id="linearGradient17498"> - <stop - id="stop17500" - offset="0" - style="stop-color:#d3d7cf;stop-opacity:1" /> - <stop - id="stop17502" - offset="0.28330287" - style="stop-color:#eeeeec;stop-opacity:1" /> - <stop - id="stop17504" - offset="0.33564273" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - style="stop-color:#ffffff;stop-opacity:1" - offset="0.6530382" - id="stop17512" /> - <stop - id="stop17514" - offset="1" - style="stop-color:#babdb6;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient14960"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop14962" /> - <stop - style="stop-color:#d7d9d5;stop-opacity:1" - offset="1" - id="stop14964" /> - </linearGradient> - <linearGradient - id="linearGradient13770"> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="0" - id="stop13772" /> - <stop - id="stop13780" - offset="0.19258282" - style="stop-color:#f2f2f1;stop-opacity:1" /> - <stop - id="stop13774" - offset="0.23801444" - style="stop-color:#edeeec;stop-opacity:1" /> - <stop - id="stop13776" - offset="0.27069226" - style="stop-color:#dcdeda;stop-opacity:1;" /> - <stop - style="stop-color:#ffffff;stop-opacity:1" - offset="1" - id="stop13778" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient4262"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop4264" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop4266" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient4203"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop4205" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop4207" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient12494"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop12496" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop12498" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient11491"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop11493" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop11495" /> - </linearGradient> - <pattern - inkscape:stockid="Sand (bitmap)" - id="sand_bitmap" - height="256" - width="256" - patternUnits="userSpaceOnUse"> - <!-- Seamless texture provided by FreeSeamlessTextures.com --> - <!-- License: creative commons attribution --> - <image - xlink:href="data:image/jpeg;base64,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 /p1//9k= " - y="0" - x="0" - id="image9" - height="260" - width="260" /> - </pattern> - <linearGradient - inkscape:collect="always" - id="linearGradient3916"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3918" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3920" /> - </linearGradient> - <linearGradient - id="linearGradient3894"> - <stop - style="stop-color:#b7beb0;stop-opacity:1" - offset="0" - id="stop3896" /> - <stop - id="stop3898" - offset="0.15504535" - style="stop-color:#f9f9f9;stop-opacity:1" /> - <stop - style="stop-color:#f9f9f8;stop-opacity:1" - offset="0.2005571" - id="stop3900" /> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="0.37639078" - id="stop3906" /> - <stop - id="stop3908" - offset="0.50482041" - style="stop-color:#888a85;stop-opacity:1" /> - <stop - style="stop-color:#888a85;stop-opacity:1" - offset="0.66817862" - id="stop3910" /> - <stop - style="stop-color:#eeeeec;stop-opacity:1" - offset="1" - id="stop3912" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3859"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3861" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3863" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient3831"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop3833" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop3835" /> - </linearGradient> - <linearGradient - id="linearGradient6219"> - <stop - id="stop6221" - offset="0" - style="stop-color:#b7beb0;stop-opacity:1" /> - <stop - style="stop-color:#f9f9f9;stop-opacity:1" - offset="0.05144871" - id="stop6227" /> - <stop - id="stop6229" - offset="0.09541478" - style="stop-color:#e7e7e4;stop-opacity:1" /> - <stop - style="stop-color:#fafafa;stop-opacity:1" - offset="0.12829006" - id="stop6231" /> - <stop - id="stop6417" - offset="0.16864988" - style="stop-color:#ffffff;stop-opacity:1" /> - <stop - id="stop6233" - offset="0.3383725" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - style="stop-color:#888a85;stop-opacity:1" - offset="0.46680215" - id="stop6235" /> - <stop - id="stop6832" - offset="0.66817862" - style="stop-color:#888a85;stop-opacity:1" /> - <stop - id="stop6223" - offset="1" - style="stop-color:#eeeeec;stop-opacity:1" /> - </linearGradient> - <linearGradient - gradientTransform="matrix(1,0,0,1.0793362,-124.58426,148.9484)" - y2="-18.526932" - x2="142.09839" - y1="-138.38556" - x1="142.09839" - gradientUnits="userSpaceOnUse" - id="linearGradient9527" - xlink:href="#linearGradient6219" - inkscape:collect="always" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3894" - id="linearGradient9572" - gradientUnits="userSpaceOnUse" - x1="77" - y1="106" - x2="119.61018" - y2="266.47308" - gradientTransform="translate(-10,-7)" /> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath3813"> - <path - id="path3815" - d="m 85.46875,105.625 -1.78125,2.46875 -8.46875,15.1875 -6.375,1.0625 -2.46875,3.53125 -6.03125,0.71875 -0.6875,2.125 -4.59375,2.125 -1.78125,9.1875 4.25,6.71875 4.9375,1.0625 2.84375,4.25 -0.34375,8.84375 4.9375,3.15625 -3.1875,10.625 3.90625,3.1875 -0.71875,-1.78125 2.8125,-11.3125 1.4375,2.46875 -1.4375,9.90625 1.4375,0.71875 -11.6875,73.53125 8.84375,7.40625 2.46875,0 0,-1.75 0.8125,-0.78125 -0.625,2.53125 9.1875,-8.28125 -1.3125,-1.1875 0.09375,-0.0625 -2.0625,-2.5625 1.53125,-4.15625 5.28125,-4.25 -1.09375,-0.90625 0.21875,-0.15625 -2.09375,-2.3125 1.375,-4.5625 L 89.6875,229 88.90625,228 89,227.9375 l -2.09375,-2.84375 0.3125,-4.40625 4.125,-4.1875 -0.96875,-1.25 0.03125,-0.0312 -2.3125,-4.0938 L 94.25,204 l -0.6875,-1.46875 0.03125,-0.0312 -0.375,-0.75 -1.03125,-2.25 4.9375,-6.5625 2.84375,-10.96875 6,0.1875 1.9375,-10.78125 5.125,-3.875 2.46875,-9.90625 5.3125,-4.78125 4.59375,-0.71875 1.78125,-3.6875 3.71875,-1.0625 2.09375,-8.65625 -1.40625,-4.25 -0.21875,0 0.0312,-0.1875 -4.9375,-1.40625 L 125.75,130 l -6,-1.40625 0.34375,-3.53125 -7.0625,-3.1875 -4.9375,-13.4375 -4.25,-2.46875 -18.375,-0.34375 z m 15.90625,8.125 3.875,8.84375 -4.9375,2.8125 -13.78125,-0.34375 -1.0625,-3.53125 5.65625,-7.4375 10.25,-0.34375 z" - style="fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - inkscape:connector-curvature="0" /> - </clipPath> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3831" - id="linearGradient3837" - x1="80.78125" - y1="243.79688" - x2="80" - y2="246.60938" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3831" - id="linearGradient3841" - gradientUnits="userSpaceOnUse" - x1="80.78125" - y1="243.79688" - x2="80" - y2="246.60938" - gradientTransform="translate(3.875,-12.21875)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3831" - id="linearGradient3845" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-1,0,0,-1,167.5,463.5)" - x1="80.78125" - y1="243.79688" - x2="80" - y2="246.60938" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3831" - id="linearGradient3849" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-1,0,0,-1,168.5,453.625)" - x1="80.78125" - y1="243.79688" - x2="80" - y2="246.60938" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3831" - id="linearGradient3853" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-1,0,0,-1,172.59375,442.1875)" - x1="80.78125" - y1="243.79688" - x2="80" - y2="246.60938" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3831" - id="linearGradient3857" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(-1,0,0,-1,180.5625,423.65625)" - x1="80.78125" - y1="243.79688" - x2="79.28125" - y2="244.35938" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3859" - id="linearGradient3865" - x1="107.53125" - y1="157.21875" - x2="53.28125" - y2="142.03125" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3916" - id="linearGradient3922" - x1="60.34375" - y1="128.59375" - x2="65.822327" - y2="134.79822" - gradientUnits="userSpaceOnUse" /> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath6088"> - <path - sodipodi:nodetypes="cccccccscccccccccccc" - inkscape:connector-curvature="0" - id="path6090" - d="m 102.125,114.75 3.375,7.75 -4.75,3 L 67,99 95.75,46.5 161,54 l 15.75,54.5 c 0,0 -9.20083,-8.2747 -22.75,-8.5 -3.89033,-0.06469 -13.75,1.75 -13.75,1.75 l -10,13.5 13.5,-1 -6,10.75 -5.75,0.25 -12.125,2.75 0.25,-2.5 -0.75,-0.625 -6.625,-3.125 -1.75,-5.25 -5,-1.375 z" - style="opacity:0.45614038;color:#000000;fill:#75507b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - </clipPath> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath6230"> - <path - sodipodi:nodetypes="ssssssssssss" - clip-path="none" - inkscape:connector-curvature="0" - id="path6232" - d="m 100.57289,62.541562 c 9.48984,-5.464319 21.33605,-6.200507 31.7778,-0.907186 16.70676,8.469299 23.42235,29.155172 15.00603,46.222194 -8.41633,17.06699 -28.75204,24.0104 -45.45881,15.54111 C 85.191127,114.92838 78.475532,94.242505 86.891873,77.175486 90.047996,70.775374 94.878999,65.820152 100.57289,62.541562 z m 6.9728,5.220359 c -5.96406,3.340783 -10.900661,9.170026 -13.378439,16.619864 -4.955579,14.899702 1.771155,30.814335 15.017289,35.518325 13.24609,4.70395 27.99598,-3.61355 32.95155,-18.51325 4.95556,-14.899695 -1.77117,-30.814334 -15.01728,-35.518318 -6.62305,-2.351969 -13.60904,-1.447398 -19.57312,1.893379 z" - style="color:#000000;fill:#c9c9c9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999982px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - </clipPath> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient11491" - id="radialGradient11497" - cx="89.221237" - cy="158.54852" - fx="89.221237" - fy="158.54852" - r="27.316811" - gradientTransform="matrix(7.792316,-0.25732976,0.04413985,1.3366185,-614.65762,-38.072453)" - gradientUnits="userSpaceOnUse" /> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath11525"> - <path - sodipodi:nodetypes="ssssssssssss" - clip-path="none" - inkscape:connector-curvature="0" - id="path11527" - d="m 100.57289,62.541565 c 9.48984,-5.464319 21.33605,-6.200507 31.7778,-0.907186 16.70676,8.469299 23.42235,29.155172 15.00603,46.222191 -8.41633,17.06699 -28.75204,24.0104 -45.45881,15.54111 C 85.191127,114.92838 78.475532,94.242508 86.891873,77.175489 90.047996,70.775377 94.878999,65.820155 100.57289,62.541565 z m 6.9728,5.220359 c -5.96406,3.340783 -10.900661,9.170026 -13.378439,16.619864 -4.955579,14.899702 1.771155,30.814332 15.017289,35.518322 13.24609,4.70395 27.99598,-3.61355 32.95155,-18.51325 4.95556,-14.899692 -1.77117,-30.814331 -15.01728,-35.518315 -6.62305,-2.351969 -13.60904,-1.447398 -19.57312,1.893379 z" - style="color:#000000;fill:none;stroke:#000000;stroke-width:0.99999982px;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - </clipPath> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3263-6" - id="linearGradient565-7" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,0.8160225)" - x1="-868.11768" - y1="1159.4119" - x2="-243.19453" - y2="1326.8596" /> - <linearGradient - id="linearGradient3263-6" - inkscape:collect="always"> - <stop - id="stop3265-8" - offset="0" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - id="stop3267-41" - offset="1" - style="stop-color:#ffffff;stop-opacity:1" /> - </linearGradient> - <linearGradient - y2="1326.8596" - x2="-243.19453" - y1="1159.4119" - x1="-868.11768" - gradientTransform="matrix(0.08620296,0.08620294,-0.08620296,0.08620294,74.48657,-3.091602)" - gradientUnits="userSpaceOnUse" - id="linearGradient12312" - xlink:href="#linearGradient3263-6" - inkscape:collect="always" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3263-6-9" - id="linearGradient565-7-7" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,0.8160225)" - x1="-868.11768" - y1="1159.4119" - x2="-243.19453" - y2="1326.8596" /> - <linearGradient - id="linearGradient3263-6-9" - inkscape:collect="always"> - <stop - id="stop3265-8-4" - offset="0" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - id="stop3267-41-9" - offset="1" - style="stop-color:#ffffff;stop-opacity:1" /> - </linearGradient> - <linearGradient - y2="1326.8596" - x2="-243.19453" - y1="1159.4119" - x1="-868.11768" - gradientTransform="matrix(0.08620296,0.08620294,-0.08620296,0.08620294,84.986565,-15.091602)" - gradientUnits="userSpaceOnUse" - id="linearGradient12312-5" - xlink:href="#linearGradient3263-6-9" - inkscape:collect="always" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3263-6-1" - id="linearGradient565-7-75" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,0.8160225)" - x1="-1726.1508" - y1="5055.0815" - x2="476.7652" - y2="5321.1538" /> - <linearGradient - id="linearGradient3263-6-1" - inkscape:collect="always"> - <stop - id="stop3265-8-1" - offset="0" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - id="stop3267-41-3" - offset="1" - style="stop-color:#ffffff;stop-opacity:1" /> - </linearGradient> - <linearGradient - y2="1326.8596" - x2="-243.19453" - y1="1159.4119" - x1="-868.11768" - gradientTransform="matrix(0.08620296,0.08620294,-0.08620296,0.08620294,227.41356,-13.853323)" - gradientUnits="userSpaceOnUse" - id="linearGradient12312-7" - xlink:href="#linearGradient3263-6-1" - inkscape:collect="always" /> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath12461"> - <path - sodipodi:nodetypes="ssscccccccccccccccccccss" - inkscape:connector-curvature="0" - id="path12463" - d="m -52.298199,90.961216 c -14.221332,0 -25.747088,11.549034 -25.747088,25.770364 0,14.22134 11.525756,25.74709 25.747088,25.74709 3.878336,0 7.549624,-0.88545 10.848231,-2.42106 l 37.8989687,37.92225 4.51621619,0 -0.51214823,-1.2571 2.25810814,0 0.7449428,1.2571 5.8431458,-1.58301 -0.6518251,-0.65182 -1.1872527,-7.2632 -5.4939537,-5.51723 -5.2611591,0.25608 0,-6.00611 -3.7479939,-3.74799 -4.2601419,0.74494 -0.232795,-5.75003 -16.08611,-15.15493 1.583003,-1.583 0.488869,-2.00204 -2.909933,-3.30568 c 1.215993,-2.99138 1.908916,-6.25621 1.908916,-9.68426 0,-14.22133 -11.525756,-25.770364 -25.747088,-25.770364 z" - style="fill:none;stroke:#000000;stroke-width:1.48988581;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> - </clipPath> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient12494" - id="linearGradient12500" - x1="-19.567272" - y1="146.57585" - x2="23.103989" - y2="188.40904" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3263-6-1" - id="linearGradient12502" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,0.8160225)" - x1="-1726.1508" - y1="5055.0815" - x2="476.7652" - y2="5321.1538" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient12494" - id="linearGradient12504" - gradientUnits="userSpaceOnUse" - x1="-19.567272" - y1="146.57585" - x2="23.103989" - y2="188.40904" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3894-6" - id="linearGradient9572-3" - gradientUnits="userSpaceOnUse" - x1="77" - y1="106" - x2="119.61018" - y2="266.47308" - gradientTransform="translate(-10,-7)" /> - <linearGradient - id="linearGradient3894-6"> - <stop - style="stop-color:#b7beb0;stop-opacity:1" - offset="0" - id="stop3896-3" /> - <stop - id="stop3898-2" - offset="0.15504535" - style="stop-color:#f9f9f9;stop-opacity:1" /> - <stop - style="stop-color:#f9f9f8;stop-opacity:1" - offset="0.2005571" - id="stop3900-3" /> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="0.37639078" - id="stop3906-1" /> - <stop - id="stop3908-2" - offset="0.50482041" - style="stop-color:#888a85;stop-opacity:1" /> - <stop - style="stop-color:#888a85;stop-opacity:1" - offset="0.66817862" - id="stop3910-7" /> - <stop - style="stop-color:#eeeeec;stop-opacity:1" - offset="1" - id="stop3912-4" /> - </linearGradient> - <linearGradient - id="linearGradient3263-6-1-8"> - <stop - id="stop3265-8-1-3" - offset="0" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - style="stop-color:#cbcdc8;stop-opacity:1;" - offset="0.25" - id="stop13768" /> - <stop - style="stop-color:#dcdeda;stop-opacity:1;" - offset="0.5" - id="stop13766" /> - <stop - id="stop3267-41-3-7" - offset="1" - style="stop-color:#ffffff;stop-opacity:1" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath6088-5"> - <path - sodipodi:nodetypes="cccccccscccccccccccc" - inkscape:connector-curvature="0" - id="path6090-7" - d="m 102.125,114.75 3.375,7.75 -4.75,3 L 67,99 95.75,46.5 161,54 l 15.75,54.5 c 0,0 -9.20083,-8.2747 -22.75,-8.5 -3.89033,-0.06469 -13.75,1.75 -13.75,1.75 l -9.125,14.875 c 4.47535,-3.19478 8.82199,-2.60624 12.625,-2.375 l -6,10.75 -5.75,0.25 -12.125,2.75 0.25,-2.5 -0.75,-0.625 -6.625,-3.125 -1.75,-5.25 -5,-1.375 z" - style="opacity:0.45614038;color:#000000;fill:#75507b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - </clipPath> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath6230-2"> - <path - sodipodi:nodetypes="ssssssssssss" - clip-path="none" - inkscape:connector-curvature="0" - id="path6232-2" - d="m 100.57289,62.541562 c 9.48984,-5.464319 21.33605,-6.200507 31.7778,-0.907186 16.70676,8.469299 23.42235,29.155172 15.00603,46.222194 -8.41633,17.06699 -28.75204,24.0104 -45.45881,15.54111 C 85.191127,114.92838 78.475532,94.242505 86.891873,77.175486 90.047996,70.775374 94.878999,65.820152 100.57289,62.541562 z m 6.9728,5.220359 c -5.96406,3.340783 -10.900661,9.170026 -13.378439,16.619864 -4.955579,14.899702 1.771155,30.814335 15.017289,35.518325 13.24609,4.70395 27.99598,-3.61355 32.95155,-18.51325 4.95556,-14.899695 -1.77117,-30.814334 -15.01728,-35.518318 -6.62305,-2.351969 -13.60904,-1.447398 -19.57312,1.893379 z" - style="color:#000000;fill:#c9c9c9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999982px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - </clipPath> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath11525-4"> - <path - sodipodi:nodetypes="ssssssssssss" - clip-path="none" - inkscape:connector-curvature="0" - id="path11527-1" - d="m 100.57289,62.541565 c 9.48984,-5.464319 21.33605,-6.200507 31.7778,-0.907186 16.70676,8.469299 23.42235,29.155172 15.00603,46.222191 -8.41633,17.06699 -28.75204,24.0104 -45.45881,15.54111 C 85.191127,114.92838 78.475532,94.242508 86.891873,77.175489 90.047996,70.775377 94.878999,65.820155 100.57289,62.541565 z m 6.9728,5.220359 c -5.96406,3.340783 -10.900661,9.170026 -13.378439,16.619864 -4.955579,14.899702 1.771155,30.814332 15.017289,35.518322 13.24609,4.70395 27.99598,-3.61355 32.95155,-18.51325 4.95556,-14.899692 -1.77117,-30.814331 -15.01728,-35.518315 -6.62305,-2.351969 -13.60904,-1.447398 -19.57312,1.893379 z" - style="color:#000000;fill:none;stroke:#000000;stroke-width:0.99999982px;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - </clipPath> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3859-9" - id="linearGradient3865-1" - x1="107.53125" - y1="157.21875" - x2="53.28125" - y2="142.03125" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - id="linearGradient3859-9"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3861-3" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3863-9" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath3813-9"> - <path - id="path3815-1" - d="m 85.46875,105.625 -1.78125,2.46875 -8.46875,15.1875 -6.375,1.0625 -2.46875,3.53125 -6.03125,0.71875 -0.6875,2.125 -4.59375,2.125 -1.78125,9.1875 4.25,6.71875 4.9375,1.0625 2.84375,4.25 -0.34375,8.84375 4.9375,3.15625 -3.1875,10.625 3.90625,3.1875 -0.71875,-1.78125 2.8125,-11.3125 1.4375,2.46875 -1.4375,9.90625 1.4375,0.71875 -11.6875,73.53125 8.84375,7.40625 2.46875,0 0,-1.75 0.8125,-0.78125 -0.625,2.53125 9.1875,-8.28125 -1.3125,-1.1875 0.09375,-0.0625 -2.0625,-2.5625 1.53125,-4.15625 5.28125,-4.25 -1.09375,-0.90625 0.21875,-0.15625 -2.09375,-2.3125 1.375,-4.5625 L 89.6875,229 88.90625,228 89,227.9375 l -2.09375,-2.84375 0.3125,-4.40625 4.125,-4.1875 -0.96875,-1.25 0.03125,-0.0312 -2.3125,-4.0938 L 94.25,204 l -0.6875,-1.46875 0.03125,-0.0312 -0.375,-0.75 -1.03125,-2.25 4.9375,-6.5625 2.84375,-10.96875 6,0.1875 1.9375,-10.78125 5.125,-3.875 2.46875,-9.90625 5.3125,-4.78125 4.59375,-0.71875 1.78125,-3.6875 3.71875,-1.0625 2.09375,-8.65625 -1.40625,-4.25 -0.21875,0 0.0312,-0.1875 -4.9375,-1.40625 L 125.75,130 l -6,-1.40625 0.34375,-3.53125 -7.0625,-3.1875 -4.9375,-13.4375 -4.25,-2.46875 -18.375,-0.34375 z m 15.90625,8.125 3.875,8.84375 -4.9375,2.8125 -13.78125,-0.34375 -1.0625,-3.53125 5.65625,-7.4375 10.25,-0.34375 z" - style="fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - inkscape:connector-curvature="0" /> - </clipPath> - <linearGradient - id="linearGradient3894-9"> - <stop - style="stop-color:#d3d7cf;stop-opacity:1" - offset="0" - id="stop3896-5" /> - <stop - style="stop-color:#eeeeec;stop-opacity:1" - offset="0.28330287" - id="stop3900-6" /> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="0.33564273" - id="stop3906-0" /> - <stop - id="stop4160" - offset="0.42023158" - style="stop-color:#eeeeec;stop-opacity:1" /> - <stop - id="stop3908-9" - offset="0.53767145" - style="stop-color:#888a85;stop-opacity:1" /> - <stop - style="stop-color:#888a85;stop-opacity:1" - offset="0.62985241" - id="stop3910-3" /> - <stop - id="stop4162" - offset="0.77754474" - style="stop-color:#ffffff;stop-opacity:1" /> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="1" - id="stop3912-0" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient12494-4" - id="linearGradient12500-6" - x1="-19.567272" - y1="146.57585" - x2="23.103989" - y2="188.40904" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - id="linearGradient12494-4"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop12496-8" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop12498-9" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath12461-5"> - <path - sodipodi:nodetypes="ssscccccccccccccccccccss" - inkscape:connector-curvature="0" - id="path12463-1" - d="m -52.298199,90.961216 c -14.221332,0 -25.747088,11.549034 -25.747088,25.770364 0,14.22134 11.525756,25.74709 25.747088,25.74709 3.878336,0 7.549624,-0.88545 10.848231,-2.42106 l 37.8989687,37.92225 4.51621619,0 -0.51214823,-1.2571 2.25810814,0 0.7449428,1.2571 5.8431458,-1.58301 -0.6518251,-0.65182 -1.1872527,-7.2632 -5.4939537,-5.51723 -5.2611591,0.25608 0,-6.00611 -3.7479939,-3.74799 -4.2601419,0.74494 -0.232795,-5.75003 -16.08611,-15.15493 1.583003,-1.583 0.488869,-2.00204 -2.909933,-3.30568 c 1.215993,-2.99138 1.908916,-6.25621 1.908916,-9.68426 0,-14.22133 -11.525756,-25.770364 -25.747088,-25.770364 z" - style="fill:none;stroke:#000000;stroke-width:1.48988581;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> - </clipPath> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4203" - id="linearGradient4209" - x1="130.10339" - y1="146.05803" - x2="125.68246" - y2="147.24261" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4262" - id="linearGradient4268" - x1="112.8125" - y1="153.96875" - x2="120.875" - y2="154.03125" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4262-2" - id="linearGradient4268-9" - x1="112.8125" - y1="153.96875" - x2="120.875" - y2="154.03125" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - id="linearGradient4262-2"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop4264-1" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop4266-5" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient13585-4"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop13587-7" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop13589-9" /> - </linearGradient> - <linearGradient - gradientTransform="translate(-182.43355,-157.87154)" - y2="170.51106" - x2="192.86339" - y1="168.56653" - x1="194.63113" - gradientUnits="userSpaceOnUse" - id="linearGradient13608" - xlink:href="#linearGradient13585-4" - inkscape:collect="always" /> - <linearGradient - inkscape:collect="always" - id="linearGradient13585-2"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop13587-8" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop13589-4" /> - </linearGradient> - <linearGradient - gradientTransform="translate(-182.43355,-157.87154)" - y2="170.51106" - x2="192.86339" - y1="168.56653" - x1="194.63113" - gradientUnits="userSpaceOnUse" - id="linearGradient13608-9" - xlink:href="#linearGradient13585-2" - inkscape:collect="always" /> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath13687"> - <path - d="m 180,135.625 a 28.375,28.375 0 1 1 -56.75,0 28.375,28.375 0 1 1 56.75,0 z" - sodipodi:ry="28.375" - sodipodi:rx="28.375" - sodipodi:cy="135.625" - sodipodi:cx="151.625" - id="path13689" - style="color:#000000;fill:none;stroke:#f9f9f8;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - sodipodi:type="arc" /> - </clipPath> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath13687-5"> - <path - d="m 180,135.625 a 28.375,28.375 0 1 1 -56.75,0 28.375,28.375 0 1 1 56.75,0 z" - sodipodi:ry="28.375" - sodipodi:rx="28.375" - sodipodi:cy="135.625" - sodipodi:cx="151.625" - id="path13689-5" - style="color:#000000;fill:none;stroke:#f9f9f8;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - sodipodi:type="arc" /> - </clipPath> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient12494-4-8" - id="linearGradient12500-6-3" - x1="-19.567272" - y1="146.57585" - x2="23.103989" - y2="188.40904" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - id="linearGradient12494-4-8"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop12496-8-9" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop12498-9-5" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath12461-5-4"> - <path - sodipodi:nodetypes="ssscccccccccccccccccccss" - inkscape:connector-curvature="0" - id="path12463-1-5" - d="m -52.298199,90.961216 c -14.221332,0 -25.747088,11.549034 -25.747088,25.770364 0,14.22134 11.525756,25.74709 25.747088,25.74709 3.878336,0 7.549624,-0.88545 10.848231,-2.42106 l 37.8989687,37.92225 4.51621619,0 -0.51214823,-1.2571 2.25810814,0 0.7449428,1.2571 5.8431458,-1.58301 -0.6518251,-0.65182 -1.1872527,-7.2632 -5.4939537,-5.51723 -5.2611591,0.25608 0,-6.00611 -3.7479939,-3.74799 -4.2601419,0.74494 -0.232795,-5.75003 -16.08611,-15.15493 1.583003,-1.583 0.488869,-2.00204 -2.909933,-3.30568 c 1.215993,-2.99138 1.908916,-6.25621 1.908916,-9.68426 0,-14.22133 -11.525756,-25.770364 -25.747088,-25.770364 z" - style="fill:none;stroke:#000000;stroke-width:1.48988581;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> - </clipPath> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient12494-4-8" - id="linearGradient12504-5-4" - gradientUnits="userSpaceOnUse" - x1="-19.567272" - y1="146.57585" - x2="23.103989" - y2="188.40904" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient12494-4-8" - id="linearGradient13987" - gradientUnits="userSpaceOnUse" - x1="-19.567272" - y1="146.57585" - x2="23.103989" - y2="188.40904" /> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath6088-5-0"> - <path - sodipodi:nodetypes="cccccccscccccccccccc" - inkscape:connector-curvature="0" - id="path6090-7-6" - d="m 102.125,114.75 3.375,7.75 -4.75,3 L 67,99 95.75,46.5 161,54 l 15.75,54.5 c 0,0 -9.20083,-8.2747 -22.75,-8.5 -3.89033,-0.06469 -13.75,1.75 -13.75,1.75 l -9.125,14.875 c 4.47535,-3.19478 8.82199,-2.60624 12.625,-2.375 l -6,10.75 -5.75,0.25 -12.125,2.75 0.25,-2.5 -0.75,-0.625 -6.625,-3.125 -1.75,-5.25 -5,-1.375 z" - style="opacity:0.45614038;color:#000000;fill:#75507b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - </clipPath> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath6230-2-1"> - <path - sodipodi:nodetypes="ssssssssssss" - clip-path="none" - inkscape:connector-curvature="0" - id="path6232-2-0" - d="m 100.57289,62.541562 c 9.48984,-5.464319 21.33605,-6.200507 31.7778,-0.907186 16.70676,8.469299 23.42235,29.155172 15.00603,46.222194 -8.41633,17.06699 -28.75204,24.0104 -45.45881,15.54111 C 85.191127,114.92838 78.475532,94.242505 86.891873,77.175486 90.047996,70.775374 94.878999,65.820152 100.57289,62.541562 z m 6.9728,5.220359 c -5.96406,3.340783 -10.900661,9.170026 -13.378439,16.619864 -4.955579,14.899702 1.771155,30.814335 15.017289,35.518325 13.24609,4.70395 27.99598,-3.61355 32.95155,-18.51325 4.95556,-14.899695 -1.77117,-30.814334 -15.01728,-35.518318 -6.62305,-2.351969 -13.60904,-1.447398 -19.57312,1.893379 z" - style="color:#000000;fill:#c9c9c9;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999982px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - </clipPath> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath11525-4-2"> - <path - sodipodi:nodetypes="ssssssssssss" - clip-path="none" - inkscape:connector-curvature="0" - id="path11527-1-6" - d="m 100.57289,62.541565 c 9.48984,-5.464319 21.33605,-6.200507 31.7778,-0.907186 16.70676,8.469299 23.42235,29.155172 15.00603,46.222191 -8.41633,17.06699 -28.75204,24.0104 -45.45881,15.54111 C 85.191127,114.92838 78.475532,94.242508 86.891873,77.175489 90.047996,70.775377 94.878999,65.820155 100.57289,62.541565 z m 6.9728,5.220359 c -5.96406,3.340783 -10.900661,9.170026 -13.378439,16.619864 -4.955579,14.899702 1.771155,30.814332 15.017289,35.518322 13.24609,4.70395 27.99598,-3.61355 32.95155,-18.51325 4.95556,-14.899692 -1.77117,-30.814331 -15.01728,-35.518315 -6.62305,-2.351969 -13.60904,-1.447398 -19.57312,1.893379 z" - style="color:#000000;fill:none;stroke:#000000;stroke-width:0.99999982px;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - </clipPath> - <filter - color-interpolation-filters="sRGB" - inkscape:collect="always" - id="filter11544-7-5"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="0.58922844" - id="feGaussianBlur11546-0-0" /> - </filter> - <linearGradient - id="linearGradient3894-9-9"> - <stop - style="stop-color:#d3d7cf;stop-opacity:1" - offset="0" - id="stop3896-5-6" /> - <stop - style="stop-color:#eeeeec;stop-opacity:1" - offset="0.28330287" - id="stop3900-6-6" /> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="0.33564273" - id="stop3906-0-9" /> - <stop - id="stop4160-0" - offset="0.42023158" - style="stop-color:#eeeeec;stop-opacity:1" /> - <stop - id="stop3908-9-6" - offset="0.53767145" - style="stop-color:#888a85;stop-opacity:1" /> - <stop - style="stop-color:#888a85;stop-opacity:1" - offset="0.62985241" - id="stop3910-3-0" /> - <stop - id="stop4162-8" - offset="0.77754474" - style="stop-color:#ffffff;stop-opacity:1" /> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="1" - id="stop3912-0-5" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient3859-9-6" - id="linearGradient3865-1-5" - x1="107.53125" - y1="157.21875" - x2="53.28125" - y2="142.03125" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - id="linearGradient3859-9-6"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop3861-3-7" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop3863-9-3" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath3813-9-8"> - <path - id="path3815-1-3" - d="m 85.46875,105.625 -1.78125,2.46875 -8.46875,15.1875 -6.375,1.0625 -2.46875,3.53125 -6.03125,0.71875 -0.6875,2.125 -4.59375,2.125 -1.78125,9.1875 4.25,6.71875 4.9375,1.0625 2.84375,4.25 -0.34375,8.84375 4.9375,3.15625 -3.1875,10.625 3.90625,3.1875 -0.71875,-1.78125 2.8125,-11.3125 1.4375,2.46875 -1.4375,9.90625 1.4375,0.71875 -11.6875,73.53125 8.84375,7.40625 2.46875,0 0,-1.75 0.8125,-0.78125 -0.625,2.53125 9.1875,-8.28125 -1.3125,-1.1875 0.09375,-0.0625 -2.0625,-2.5625 1.53125,-4.15625 5.28125,-4.25 -1.09375,-0.90625 0.21875,-0.15625 -2.09375,-2.3125 1.375,-4.5625 L 89.6875,229 88.90625,228 89,227.9375 l -2.09375,-2.84375 0.3125,-4.40625 4.125,-4.1875 -0.96875,-1.25 0.03125,-0.0312 -2.3125,-4.0938 L 94.25,204 l -0.6875,-1.46875 0.03125,-0.0312 -0.375,-0.75 -1.03125,-2.25 4.9375,-6.5625 2.84375,-10.96875 6,0.1875 1.9375,-10.78125 5.125,-3.875 2.46875,-9.90625 5.3125,-4.78125 4.59375,-0.71875 1.78125,-3.6875 3.71875,-1.0625 2.09375,-8.65625 -1.40625,-4.25 -0.21875,0 0.0312,-0.1875 -4.9375,-1.40625 L 125.75,130 l -6,-1.40625 0.34375,-3.53125 -7.0625,-3.1875 -4.9375,-13.4375 -4.25,-2.46875 -18.375,-0.34375 z m 15.90625,8.125 3.875,8.84375 -4.9375,2.8125 -13.78125,-0.34375 -1.0625,-3.53125 5.65625,-7.4375 10.25,-0.34375 z" - style="fill:none;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - inkscape:connector-curvature="0" /> - </clipPath> - <filter - color-interpolation-filters="sRGB" - inkscape:collect="always" - id="filter3825-6-1"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="0.50626347" - id="feGaussianBlur3827-5-5" /> - </filter> - <linearGradient - id="linearGradient3263-6-1-8-3"> - <stop - id="stop3265-8-1-3-1" - offset="0" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - style="stop-color:#cbcdc8;stop-opacity:1;" - offset="0.25" - id="stop13768-5" /> - <stop - style="stop-color:#dcdeda;stop-opacity:1;" - offset="0.5" - id="stop13766-1" /> - <stop - id="stop3267-41-3-7-6" - offset="1" - style="stop-color:#ffffff;stop-opacity:1" /> - </linearGradient> - <linearGradient - id="linearGradient13770-9"> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="0" - id="stop13772-1" /> - <stop - id="stop13780-9" - offset="0.17445399" - style="stop-color:#f2f2f1;stop-opacity:1" /> - <stop - id="stop13774-5" - offset="0.23801444" - style="stop-color:#edeeec;stop-opacity:1" /> - <stop - id="stop13776-7" - offset="0.27069226" - style="stop-color:#dcdeda;stop-opacity:1;" /> - <stop - style="stop-color:#ffffff;stop-opacity:1" - offset="1" - id="stop13778-9" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath13687-5-1"> - <path - d="m 180,135.625 a 28.375,28.375 0 1 1 -56.75,0 28.375,28.375 0 1 1 56.75,0 z" - sodipodi:ry="28.375" - sodipodi:rx="28.375" - sodipodi:cy="135.625" - sodipodi:cx="151.625" - id="path13689-5-4" - style="color:#000000;fill:none;stroke:#f9f9f8;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - sodipodi:type="arc" /> - </clipPath> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient12494-4-8-1" - id="linearGradient13987-9" - gradientUnits="userSpaceOnUse" - x1="-19.567272" - y1="146.57585" - x2="23.103989" - y2="188.40904" /> - <linearGradient - inkscape:collect="always" - id="linearGradient12494-4-8-1"> - <stop - style="stop-color:#000000;stop-opacity:1;" - offset="0" - id="stop12496-8-9-1" /> - <stop - style="stop-color:#000000;stop-opacity:0;" - offset="1" - id="stop12498-9-5-0" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath12461-5-4-5"> - <path - sodipodi:nodetypes="ssscccccccccccccccccccss" - inkscape:connector-curvature="0" - id="path12463-1-5-7" - d="m -52.298199,90.961216 c -14.221332,0 -25.747088,11.549034 -25.747088,25.770364 0,14.22134 11.525756,25.74709 25.747088,25.74709 3.878336,0 7.549624,-0.88545 10.848231,-2.42106 l 37.8989687,37.92225 4.51621619,0 -0.51214823,-1.2571 2.25810814,0 0.7449428,1.2571 5.8431458,-1.58301 -0.6518251,-0.65182 -1.1872527,-7.2632 -5.4939537,-5.51723 -5.2611591,0.25608 0,-6.00611 -3.7479939,-3.74799 -4.2601419,0.74494 -0.232795,-5.75003 -16.08611,-15.15493 1.583003,-1.583 0.488869,-2.00204 -2.909933,-3.30568 c 1.215993,-2.99138 1.908916,-6.25621 1.908916,-9.68426 0,-14.22133 -11.525756,-25.770364 -25.747088,-25.770364 z" - style="fill:none;stroke:#000000;stroke-width:1.48988581;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> - </clipPath> - <filter - color-interpolation-filters="sRGB" - inkscape:collect="always" - id="filter12480-2-4-0"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="0.56367413" - id="feGaussianBlur12482-5-6-5" /> - </filter> - <linearGradient - y2="188.40904" - x2="23.103989" - y1="146.57585" - x1="-19.567272" - gradientUnits="userSpaceOnUse" - id="linearGradient14313" - xlink:href="#linearGradient12494-4-8-1" - inkscape:collect="always" /> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath14890"> - <path - style="color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - d="m 179.63667,158.14666 0,-65.569995 -75.57667,0 0,65.569995 75.57667,0 z m -37.7225,-22.58083 c -5.74468,0 -10.40167,-4.65699 -10.40167,-10.40167 0,-5.74468 4.65699,-10.40166 10.40167,-10.40166 5.74468,0 10.40166,4.65698 10.40166,10.40166 0,5.74468 -4.65698,10.40167 -10.40166,10.40167 z" - id="path14892" - inkscape:connector-curvature="0" /> - </clipPath> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient14960" - id="linearGradient14966" - x1="-2.0341735" - y1="213.94829" - x2="-1.2096813" - y2="198.59221" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient14960" - id="linearGradient14992" - gradientUnits="userSpaceOnUse" - x1="-2.0341735" - y1="213.94829" - x2="-1.2096813" - y2="198.59221" /> - <filter - color-interpolation-filters="sRGB" - inkscape:collect="always" - id="filter14931-9"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="0.5341601" - id="feGaussianBlur14933-8" /> - </filter> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient14960-7" - id="linearGradient14992-4" - gradientUnits="userSpaceOnUse" - x1="-2.0341735" - y1="213.94829" - x2="-1.2096813" - y2="198.59221" /> - <linearGradient - inkscape:collect="always" - id="linearGradient14960-7"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop14962-1" /> - <stop - style="stop-color:#d7d9d5;stop-opacity:1" - offset="1" - id="stop14964-8" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath14890-4"> - <path - style="color:#000000;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - d="m 179.63667,158.14666 0,-65.569995 -75.57667,0 0,65.569995 75.57667,0 z m -37.7225,-22.58083 c -5.74468,0 -10.40167,-4.65699 -10.40167,-10.40167 0,-5.74468 4.65699,-10.40166 10.40167,-10.40166 5.74468,0 10.40166,4.65698 10.40166,10.40166 0,5.74468 -4.65698,10.40167 -10.40166,10.40167 z" - id="path14892-4" - inkscape:connector-curvature="0" /> - </clipPath> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient14915-2" - id="radialGradient14996-4" - gradientUnits="userSpaceOnUse" - cx="152.45" - cy="113.6" - fx="152.45" - fy="113.6" - r="25.799999" /> - <linearGradient - inkscape:collect="always" - id="linearGradient14915-2"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop14917-6" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop14919-7" /> - </linearGradient> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient14915-1" - id="radialGradient14921-5" - cx="152.45" - cy="113.6" - fx="152.45" - fy="113.6" - r="25.799999" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - id="linearGradient14915-1"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop14917-60" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop14919-5" /> - </linearGradient> - <linearGradient - id="linearGradient6762" - inkscape:collect="always"> - <stop - id="stop6764" - offset="0" - style="stop-color:#000000;stop-opacity:1;" /> - <stop - id="stop6766" - offset="1" - style="stop-color:#000000;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient6833" - inkscape:collect="always"> - <stop - id="stop6835" - offset="0" - style="stop-color:#ffffff;stop-opacity:1;" /> - <stop - id="stop6837" - offset="1" - style="stop-color:#ffffff;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient6753" - inkscape:collect="always"> - <stop - id="stop6755" - offset="0" - style="stop-color:#888a85;stop-opacity:1" /> - <stop - id="stop6757" - offset="1" - style="stop-color:#eeeeec;stop-opacity:1" /> - </linearGradient> - <linearGradient - id="linearGradient6837" - inkscape:collect="always"> - <stop - id="stop6839" - offset="0" - style="stop-color:#ffffff;stop-opacity:1;" /> - <stop - id="stop6841" - offset="1" - style="stop-color:#ffffff;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient7582" - inkscape:collect="always"> - <stop - id="stop7584" - offset="0" - style="stop-color:#ffffff;stop-opacity:1;" /> - <stop - id="stop7586" - offset="1" - style="stop-color:#ffffff;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient6958" - inkscape:collect="always"> - <stop - id="stop6960" - offset="0" - style="stop-color:#000000;stop-opacity:1" /> - <stop - id="stop6962" - offset="1" - style="stop-color:#888a85;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient2816" - inkscape:collect="always"> - <stop - id="stop2818" - offset="0" - style="stop-color:white;stop-opacity:1;" /> - <stop - id="stop2820" - offset="1" - style="stop-color:white;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient4542" - inkscape:collect="always"> - <stop - id="stop4544" - offset="0" - style="stop-color:#888a85;stop-opacity:1" /> - <stop - id="stop4546" - offset="1" - style="stop-color:#888a85;stop-opacity:0" /> - </linearGradient> - <linearGradient - id="linearGradient6762-2" - inkscape:collect="always"> - <stop - id="stop6764-9" - offset="0" - style="stop-color:#000000;stop-opacity:1;" /> - <stop - id="stop6766-9" - offset="1" - style="stop-color:#000000;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient6833-5" - inkscape:collect="always"> - <stop - id="stop6835-7" - offset="0" - style="stop-color:#ffffff;stop-opacity:1;" /> - <stop - id="stop6837-6" - offset="1" - style="stop-color:#ffffff;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient6742-8" - inkscape:collect="always"> - <stop - id="stop6744-9" - offset="0" - style="stop-color:#ffffff;stop-opacity:1;" /> - <stop - id="stop6746-2" - offset="1" - style="stop-color:#ffffff;stop-opacity:0;" /> - </linearGradient> - <linearGradient - gradientUnits="userSpaceOnUse" - id="linearGradient6127-5" - inkscape:collect="always" - x1="14.4375" - x2="8" - xlink:href="#linearGradient6753-1" - y1="13.8125" - y2="7.5" /> - <linearGradient - id="linearGradient6753-1" - inkscape:collect="always"> - <stop - id="stop6755-2" - offset="0" - style="stop-color:#888a85;stop-opacity:1" /> - <stop - id="stop6757-6" - offset="1" - style="stop-color:#eeeeec;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient7419" - id="linearGradient17359" - gradientUnits="userSpaceOnUse" - x1="-2.0341735" - y1="213.94829" - x2="-1.2096813" - y2="198.59221" /> - <filter - inkscape:collect="always" - id="filter17409"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="0.60698113" - id="feGaussianBlur17411" /> - </filter> - <linearGradient - id="linearGradient3894-9-9-0"> - <stop - style="stop-color:#d3d7cf;stop-opacity:1" - offset="0" - id="stop3896-5-6-3" /> - <stop - style="stop-color:#eeeeec;stop-opacity:1" - offset="0.28330287" - id="stop3900-6-6-4" /> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="0.33564273" - id="stop3906-0-9-9" /> - <stop - id="stop4160-0-3" - offset="0.42023158" - style="stop-color:#eeeeec;stop-opacity:1" /> - <stop - id="stop3908-9-6-9" - offset="0.53767145" - style="stop-color:#888a85;stop-opacity:1" /> - <stop - style="stop-color:#888a85;stop-opacity:1" - offset="0.62985241" - id="stop3910-3-0-5" /> - <stop - id="stop4162-8-4" - offset="0.77754474" - style="stop-color:#ffffff;stop-opacity:1" /> - <stop - style="stop-color:#babdb6;stop-opacity:1" - offset="1" - id="stop3912-0-5-9" /> - </linearGradient> - <linearGradient - y2="253.83969" - x2="116.61353" - y1="106" - x1="77" - gradientTransform="translate(-63.28125,-112.625)" - gradientUnits="userSpaceOnUse" - id="linearGradient17468" - xlink:href="#linearGradient3894-9-9-0" - inkscape:collect="always" /> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath17624"> - <path - style="color:#000000;fill:none;stroke:#888a85;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - d="m 314.04481,64.503538 c 3.04979,0.261024 2.71652,1.730288 3.6651,2.741745 l 1.31603,2.778302 -7.16509,2.558962 -15.13443,-9.358492 7.53066,-12.941037 19.375,-3.582547 2.04717,6.287735 0,12.575473 -2.48585,-4.31368 c -2.2239,-1.975914 -5.25311,-0.529264 -8.10614,0.168632 z" - id="path17626" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccccccccccc" /> - </clipPath> - <linearGradient - id="linearGradient17498-1"> - <stop - id="stop17500-1" - offset="0" - style="stop-color:#d3d7cf;stop-opacity:1" /> - <stop - id="stop17502-9" - offset="0.28330287" - style="stop-color:#eeeeec;stop-opacity:1" /> - <stop - id="stop17504-7" - offset="0.33564273" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - style="stop-color:#ffffff;stop-opacity:1" - offset="0.6530382" - id="stop17512-8" /> - <stop - id="stop17514-2" - offset="1" - style="stop-color:#babdb6;stop-opacity:1" /> - </linearGradient> - <linearGradient - id="linearGradient4542-7" - inkscape:collect="always"> - <stop - id="stop4544-6" - offset="0" - style="stop-color:#888a85;stop-opacity:1" /> - <stop - id="stop4546-6" - offset="1" - style="stop-color:#888a85;stop-opacity:0" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath17624-3"> - <path - style="color:#000000;fill:none;stroke:#888a85;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - d="m 314.04481,64.503538 c 3.04979,0.261024 2.71652,1.730288 3.6651,2.741745 l 1.31603,2.778302 -7.16509,2.558962 -15.13443,-9.358492 7.53066,-12.941037 19.375,-3.582547 2.04717,6.287735 0,12.575473 -2.19859,-5.175466 c -2.2239,-1.975914 -5.10948,-1.103789 -7.96251,-0.405893 z" - id="path17626-6" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccccccccccc" /> - </clipPath> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4542-7" - id="linearGradient17750" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.727273,0,0,0.999999,12.27273,-34.84375)" - x1="33.120464" - y1="20.5" - x2="22.328388" - y2="20.5" /> - <linearGradient - id="linearGradient17498-7"> - <stop - id="stop17500-8" - offset="0" - style="stop-color:#d3d7cf;stop-opacity:1" /> - <stop - id="stop17502-3" - offset="0.28330287" - style="stop-color:#eeeeec;stop-opacity:1" /> - <stop - id="stop17504-9" - offset="0.33564273" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - style="stop-color:#ffffff;stop-opacity:1" - offset="0.6530382" - id="stop17512-4" /> - <stop - id="stop17514-4" - offset="1" - style="stop-color:#babdb6;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient17780-3"> - <stop - style="stop-color:#888a85;stop-opacity:1;" - offset="0" - id="stop17782-6" /> - <stop - style="stop-color:#e2e2e1;stop-opacity:1" - offset="1" - id="stop17784-1" /> - </linearGradient> - <linearGradient - y2="51.558521" - x2="19.272995" - y1="25.183172" - x1="28.897871" - gradientTransform="matrix(-1.222459,-0.32755691,-0.32755691,1.222459,49.646976,-20.299048)" - gradientUnits="userSpaceOnUse" - id="linearGradient17810" - xlink:href="#linearGradient17498-7" - inkscape:collect="always" /> - <linearGradient - gradientTransform="matrix(-1.222459,-0.32755691,-0.32755691,1.222459,35.129488,-15.017404)" - y2="21.948019" - x2="21.54595" - y1="35.318134" - x1="12.744178" - gradientUnits="userSpaceOnUse" - id="linearGradient17812" - xlink:href="#linearGradient17780-3" - inkscape:collect="always" /> - <linearGradient - id="linearGradient17498-3"> - <stop - id="stop17500-3" - offset="0" - style="stop-color:#d3d7cf;stop-opacity:1" /> - <stop - id="stop17502-4" - offset="0.28330287" - style="stop-color:#eeeeec;stop-opacity:1" /> - <stop - id="stop17504-4" - offset="0.33564273" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - style="stop-color:#ffffff;stop-opacity:1" - offset="0.6530382" - id="stop17512-2" /> - <stop - id="stop17514-1" - offset="1" - style="stop-color:#babdb6;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient17780-6"> - <stop - style="stop-color:#888a85;stop-opacity:1;" - offset="0" - id="stop17782-8" /> - <stop - style="stop-color:#e2e2e1;stop-opacity:1" - offset="1" - id="stop17784-3" /> - </linearGradient> - <linearGradient - y2="51.558521" - x2="19.272995" - y1="25.183172" - x1="28.897871" - gradientTransform="matrix(-1.222459,-0.32755691,-0.32755691,1.222459,49.646976,-20.299048)" - gradientUnits="userSpaceOnUse" - id="linearGradient17810-0" - xlink:href="#linearGradient17498-3" - inkscape:collect="always" /> - <linearGradient - gradientTransform="matrix(-1.222459,-0.32755691,-0.32755691,1.222459,35.129488,-15.017404)" - y2="21.948019" - x2="21.54595" - y1="35.318134" - x1="12.744178" - gradientUnits="userSpaceOnUse" - id="linearGradient17812-7" - xlink:href="#linearGradient17780-6" - inkscape:collect="always" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17498-5" - id="linearGradient17518-1" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-10,-7.0000003)" - x1="28.897871" - y1="25.183172" - x2="19.272995" - y2="51.558521" /> - <linearGradient - id="linearGradient17498-5"> - <stop - id="stop17500-6" - offset="0" - style="stop-color:#d3d7cf;stop-opacity:1" /> - <stop - id="stop17502-2" - offset="0.28330287" - style="stop-color:#eeeeec;stop-opacity:1" /> - <stop - id="stop17504-8" - offset="0.33564273" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - style="stop-color:#ffffff;stop-opacity:1" - offset="0.6530382" - id="stop17512-6" /> - <stop - id="stop17514-9" - offset="1" - style="stop-color:#babdb6;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17780-7" - id="linearGradient17786-1" - x1="12.744178" - y1="35.318134" - x2="21.54595" - y2="21.948019" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - id="linearGradient17780-7"> - <stop - style="stop-color:#888a85;stop-opacity:1;" - offset="0" - id="stop17782-4" /> - <stop - style="stop-color:#e2e2e1;stop-opacity:1" - offset="1" - id="stop17784-7" /> - </linearGradient> - <linearGradient - y2="51.558521" - x2="19.272995" - y1="25.183172" - x1="28.897871" - gradientTransform="matrix(-1.222459,-0.32755691,-0.32755691,1.222459,49.646976,-20.299048)" - gradientUnits="userSpaceOnUse" - id="linearGradient17810-7" - xlink:href="#linearGradient17498-5" - inkscape:collect="always" /> - <linearGradient - gradientTransform="matrix(-1.222459,-0.32755691,-0.32755691,1.222459,35.129488,-15.017404)" - y2="21.948019" - x2="21.54595" - y1="35.318134" - x1="12.744178" - gradientUnits="userSpaceOnUse" - id="linearGradient17812-9" - xlink:href="#linearGradient17780-7" - inkscape:collect="always" /> - <linearGradient - id="linearGradient17498-6"> - <stop - id="stop17500-5" - offset="0" - style="stop-color:#d3d7cf;stop-opacity:1" /> - <stop - id="stop17502-8" - offset="0.28330287" - style="stop-color:#eeeeec;stop-opacity:1" /> - <stop - id="stop17504-6" - offset="0.33564273" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - style="stop-color:#ffffff;stop-opacity:1" - offset="0.6530382" - id="stop17512-3" /> - <stop - id="stop17514-5" - offset="1" - style="stop-color:#babdb6;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient17780-5"> - <stop - style="stop-color:#888a85;stop-opacity:1;" - offset="0" - id="stop17782-68" /> - <stop - style="stop-color:#e2e2e1;stop-opacity:1" - offset="1" - id="stop17784-4" /> - </linearGradient> - <linearGradient - y2="51.558521" - x2="19.272995" - y1="25.183172" - x1="28.897871" - gradientTransform="matrix(-1.222459,-0.32755691,-0.32755691,1.222459,49.646976,-20.299048)" - gradientUnits="userSpaceOnUse" - id="linearGradient17810-09" - xlink:href="#linearGradient17498-6" - inkscape:collect="always" /> - <linearGradient - gradientTransform="matrix(-1.222459,-0.32755691,-0.32755691,1.222459,35.129488,-15.017404)" - y2="21.948019" - x2="21.54595" - y1="35.318134" - x1="12.744178" - gradientUnits="userSpaceOnUse" - id="linearGradient17812-1" - xlink:href="#linearGradient17780-5" - inkscape:collect="always" /> - <linearGradient - inkscape:collect="always" - id="linearGradient5376-1-5-2"> - <stop - style="stop-color:#fce94f;stop-opacity:1;" - offset="0" - id="stop5378-1-7-2" /> - <stop - style="stop-color:#ffffff;stop-opacity:1" - offset="1" - id="stop5380-0-9-0" /> - </linearGradient> - <linearGradient - y2="1326.8596" - x2="-243.19453" - y1="1159.4119" - x1="-868.11768" - gradientTransform="matrix(0.08620296,0.08620294,-0.08620296,0.08620294,227.41356,-13.853324)" - gradientUnits="userSpaceOnUse" - id="linearGradient6089" - xlink:href="#linearGradient5376-1-5-2" - inkscape:collect="always" /> - <linearGradient - id="linearGradient6107-8"> - <stop - id="stop6109-3" - offset="0" - style="stop-color:#e0d684;stop-opacity:1" /> - <stop - style="stop-color:#f7f5e3;stop-opacity:1" - offset="0.25" - id="stop6115-8" /> - <stop - style="stop-color:#e5e3ae;stop-opacity:1;" - offset="0.5" - id="stop6113-7" /> - <stop - id="stop6111-3" - offset="1" - style="stop-color:#ebf0d8;stop-opacity:1" /> - </linearGradient> - <linearGradient - y2="1684.3187" - x2="3503.502" - y1="921.10638" - x1="1382.548" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,45.03819,-90.402987)" - gradientUnits="userSpaceOnUse" - id="linearGradient6134" - xlink:href="#linearGradient6107-8" - inkscape:collect="always" /> - <linearGradient - id="linearGradient6107-8-2"> - <stop - id="stop6109-3-0" - offset="0" - style="stop-color:#e0d684;stop-opacity:1" /> - <stop - style="stop-color:#f7f5e3;stop-opacity:1" - offset="0.25" - id="stop6115-8-6" /> - <stop - style="stop-color:#e5e3ae;stop-opacity:1;" - offset="0.5" - id="stop6113-7-3" /> - <stop - id="stop6111-3-6" - offset="1" - style="stop-color:#ebf0d8;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient6156-0"> - <stop - style="stop-color:#c4a000;stop-opacity:1;" - offset="0" - id="stop6158-5" /> - <stop - style="stop-color:#ffe365;stop-opacity:1" - offset="1" - id="stop6160-7" /> - </linearGradient> - <linearGradient - y2="1684.3187" - x2="3503.502" - y1="921.10638" - x1="1382.548" - gradientTransform="matrix(0,0.06759483,0.06759483,0,-134.30354,128.13852)" - gradientUnits="userSpaceOnUse" - id="linearGradient6185" - xlink:href="#linearGradient6107-8-2" - inkscape:collect="always" /> - <linearGradient - gradientTransform="matrix(-0.89490214,0.89490212,0.89490212,0.89490214,0.34336141,-23.651613)" - y2="21.641434" - x2="5.5136962" - y1="46.923531" - x1="16.843721" - gradientUnits="userSpaceOnUse" - id="linearGradient6187" - xlink:href="#linearGradient6156-0" - inkscape:collect="always" /> - <linearGradient - id="linearGradient6107-8-7"> - <stop - id="stop6109-3-6" - offset="0" - style="stop-color:#e0d684;stop-opacity:1" /> - <stop - style="stop-color:#f7f5e3;stop-opacity:1" - offset="0.25" - id="stop6115-8-3" /> - <stop - style="stop-color:#e5e3ae;stop-opacity:1;" - offset="0.5" - id="stop6113-7-9" /> - <stop - id="stop6111-3-1" - offset="1" - style="stop-color:#ebf0d8;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient6156-4"> - <stop - style="stop-color:#c4a000;stop-opacity:1;" - offset="0" - id="stop6158-1" /> - <stop - style="stop-color:#ffe365;stop-opacity:1" - offset="1" - id="stop6160-1" /> - </linearGradient> - <linearGradient - y2="1684.3187" - x2="3503.502" - y1="921.10638" - x1="1382.548" - gradientTransform="matrix(0,0.06759483,0.06759483,0,-134.30354,128.13852)" - gradientUnits="userSpaceOnUse" - id="linearGradient6185-8" - xlink:href="#linearGradient6107-8-7" - inkscape:collect="always" /> - <linearGradient - gradientTransform="matrix(-0.89490214,0.89490212,0.89490212,0.89490214,0.34336141,-23.651613)" - y2="21.641434" - x2="5.5136962" - y1="46.923531" - x1="16.843721" - gradientUnits="userSpaceOnUse" - id="linearGradient6187-6" - xlink:href="#linearGradient6156-4" - inkscape:collect="always" /> - <linearGradient - inkscape:collect="always" - id="linearGradient6249-2"> - <stop - style="stop-color:#c49f00;stop-opacity:0.627451" - offset="0" - id="stop6251-7" /> - <stop - style="stop-color:#fceca6;stop-opacity:1" - offset="1" - id="stop6253-0" /> - </linearGradient> - <linearGradient - gradientTransform="matrix(-1.34294e-8,1,1,1.34294e-8,-8.4999999,-9.0000001)" - y2="7.5" - x2="8" - y1="13.8125" - x1="14.4375" - gradientUnits="userSpaceOnUse" - id="linearGradient6270" - xlink:href="#linearGradient6249-2" - inkscape:collect="always" /> - <linearGradient - id="linearGradient6107-8-7-1"> - <stop - id="stop6109-3-6-5" - offset="0" - style="stop-color:#e0d684;stop-opacity:1" /> - <stop - style="stop-color:#f7f5e3;stop-opacity:1" - offset="0.25" - id="stop6115-8-3-1" /> - <stop - style="stop-color:#e5e3ae;stop-opacity:1;" - offset="0.5" - id="stop6113-7-9-4" /> - <stop - id="stop6111-3-1-8" - offset="1" - style="stop-color:#ebf0d8;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient6156-4-3"> - <stop - style="stop-color:#c4a000;stop-opacity:1;" - offset="0" - id="stop6158-1-7" /> - <stop - style="stop-color:#ffe365;stop-opacity:1" - offset="1" - id="stop6160-1-4" /> - </linearGradient> - <linearGradient - y2="1684.3187" - x2="3503.502" - y1="921.10638" - x1="1382.548" - gradientTransform="matrix(0.0377666,0.03776661,0.0377666,-0.03776661,9.578274,160.03315)" - gradientUnits="userSpaceOnUse" - id="linearGradient7446" - xlink:href="#linearGradient6107-8-7-1" - inkscape:collect="always" /> - <linearGradient - gradientTransform="matrix(-1.34294e-8,1,1,1.34294e-8,7.3861713e-8,-0.00503904)" - y2="11.641434" - x2="-1.2363037" - y1="14.923531" - x1="13.593721" - gradientUnits="userSpaceOnUse" - id="linearGradient7448" - xlink:href="#linearGradient6156-4-3" - inkscape:collect="always" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8002-5" - id="linearGradient8008-1" - x1="14.679631" - y1="16.403772" - x2="-6.3245316" - y2="46.160282" - gradientUnits="userSpaceOnUse" /> - <linearGradient - inkscape:collect="always" - id="linearGradient8002-5"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop8004-2" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop8006-6" /> - </linearGradient> - <linearGradient - y2="46.160282" - x2="-6.3245316" - y1="16.403772" - x1="14.679631" - gradientUnits="userSpaceOnUse" - id="linearGradient8025" - xlink:href="#linearGradient8002-5" - inkscape:collect="always" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient7419" - id="linearGradient8053" - gradientUnits="userSpaceOnUse" - x1="-2.0341735" - y1="213.94829" - x2="-1.2096813" - y2="198.59221" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6107-8" - id="linearGradient3907" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,9.5782761)" - x1="1382.548" - y1="921.10638" - x2="3503.502" - y2="1684.3187" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6156" - id="linearGradient3909" - gradientUnits="userSpaceOnUse" - x1="12.892972" - y1="33.490982" - x2="5.5136962" - y2="21.641434" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6958" - id="linearGradient3911" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,0.625,-0.676136,0,37.10227,15.875)" - x1="17" - y1="45.248375" - x2="17" - y2="30.759407" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2816" - id="linearGradient3913" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,0.673693,-0.676136,0,37.10227,14.81577)" - x1="15.406166" - y1="37.34367" - x2="16.864777" - y2="24.249567" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6249-2" - id="linearGradient3915" - gradientUnits="userSpaceOnUse" - x1="44.46957" - y1="-15.295949" - x2="31.692965" - y2="-15.121348" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient7994" - id="linearGradient3917" - gradientUnits="userSpaceOnUse" - x1="6.7611751" - y1="30.90625" - x2="19.926325" - y2="30.90625" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17498" - id="linearGradient3987" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-10,-7.0000003)" - x1="28.897871" - y1="25.183172" - x2="19.272995" - y2="51.558521" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17780" - id="linearGradient3989" - gradientUnits="userSpaceOnUse" - x1="17.291615" - y1="31.321718" - x2="23.125856" - y2="14.906891" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4542" - id="linearGradient3991" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.727273,0,0,0.999999,12.27273,-34.84375)" - x1="33.120464" - y1="20.5" - x2="22.328388" - y2="20.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8002" - id="linearGradient3993" - gradientUnits="userSpaceOnUse" - x1="14.679631" - y1="16.403772" - x2="-6.3245316" - y2="46.160282" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6107-8-7" - id="linearGradient4085" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,9.5782761)" - x1="1382.548" - y1="921.10638" - x2="3503.502" - y2="1684.3187" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6156-4" - id="linearGradient4087" - gradientUnits="userSpaceOnUse" - x1="13.593721" - y1="14.923531" - x2="-1.2363037" - y2="11.641434" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6762-2" - id="linearGradient4089" - gradientUnits="userSpaceOnUse" - x1="6.5" - y1="9" - x2="7.5" - y2="5.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6833-5" - id="linearGradient4091" - gradientUnits="userSpaceOnUse" - x1="8.7232523" - y1="6.2651649" - x2="5.9061942" - y2="5.2978506" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6742-8" - id="linearGradient4093" - gradientUnits="userSpaceOnUse" - x1="9.9340439" - y1="4.53125" - x2="10.562407" - y2="22.717516" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6249" - id="linearGradient4095" - gradientUnits="userSpaceOnUse" - x1="14.4375" - y1="13.8125" - x2="8" - y2="7.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17498-6" - id="linearGradient4097" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-10,-7.0000003)" - x1="6.6240072" - y1="10.33393" - x2="10.96449" - y2="28.577551" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17780-5" - id="linearGradient4099" - gradientUnits="userSpaceOnUse" - x1="0.36980912" - y1="9.6855135" - x2="-3.3759925" - y2="3.3339295" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6762" - id="linearGradient4101" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,-3.506058,-0.3596506)" - x1="6.4375" - y1="6.7797499" - x2="8.4537582" - y2="8.7975082" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6837" - id="linearGradient4103" - gradientUnits="userSpaceOnUse" - x1="-7.96875" - y1="11.5" - x2="0.96875" - y2="11.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6833" - id="linearGradient4105" - gradientUnits="userSpaceOnUse" - x1="8.7232523" - y1="6.2651649" - x2="6.1381931" - y2="6.2651649" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6753" - id="linearGradient4107" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,-3.506058,-0.3596506)" - x1="9.2127371" - y1="9.4198446" - x2="17.65192" - y2="17.15192" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7582" - id="radialGradient4113" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1,0,0,0.6206897,0,0.7823276)" - cx="11.15625" - cy="2.0625" - fx="11.15625" - fy="2.0625" - r="0.90625" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6107-8-2" - id="linearGradient4907" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,9.5782761)" - x1="1382.548" - y1="921.10638" - x2="3503.502" - y2="1684.3187" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6156-0" - id="linearGradient4909" - gradientUnits="userSpaceOnUse" - x1="16.843721" - y1="46.923531" - x2="5.5136962" - y2="21.641434" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6958" - id="linearGradient4911" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,0.625,-0.676136,0,37.10227,15.875)" - x1="17" - y1="45.248375" - x2="17" - y2="30.759407" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2816" - id="linearGradient4913" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,0.673693,-0.676136,0,37.10227,14.81577)" - x1="15.406166" - y1="37.34367" - x2="16.864777" - y2="24.249567" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6249-2" - id="linearGradient4915" - gradientUnits="userSpaceOnUse" - x1="14.4375" - y1="13.8125" - x2="8" - y2="7.5" /> - <linearGradient - id="linearGradient6107-8-7-3"> - <stop - id="stop6109-3-6-54" - offset="0" - style="stop-color:#e0d684;stop-opacity:1" /> - <stop - style="stop-color:#f7f5e3;stop-opacity:1" - offset="0.25" - id="stop6115-8-3-3" /> - <stop - style="stop-color:#e5e3ae;stop-opacity:1;" - offset="0.5" - id="stop6113-7-9-6" /> - <stop - id="stop6111-3-1-4" - offset="1" - style="stop-color:#ebf0d8;stop-opacity:1" /> - </linearGradient> - <linearGradient - id="linearGradient17498-6-8"> - <stop - id="stop17500-5-7" - offset="0" - style="stop-color:#d3d7cf;stop-opacity:1" /> - <stop - id="stop17502-8-4" - offset="0.28330287" - style="stop-color:#eeeeec;stop-opacity:1" /> - <stop - id="stop17504-6-9" - offset="0.33564273" - style="stop-color:#babdb6;stop-opacity:1" /> - <stop - style="stop-color:#ffffff;stop-opacity:1" - offset="0.6530382" - id="stop17512-3-3" /> - <stop - id="stop17514-5-1" - offset="1" - style="stop-color:#babdb6;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient17780-5-8"> - <stop - style="stop-color:#888a85;stop-opacity:1;" - offset="0" - id="stop17782-68-7" /> - <stop - style="stop-color:#e2e2e1;stop-opacity:1" - offset="1" - id="stop17784-4-9" /> - </linearGradient> - <linearGradient - id="linearGradient6762-8" - inkscape:collect="always"> - <stop - id="stop6764-8" - offset="0" - style="stop-color:#000000;stop-opacity:1;" /> - <stop - id="stop6766-4" - offset="1" - style="stop-color:#000000;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient6837-0" - inkscape:collect="always"> - <stop - id="stop6839-8" - offset="0" - style="stop-color:#ffffff;stop-opacity:1;" /> - <stop - id="stop6841-6" - offset="1" - style="stop-color:#ffffff;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient6833-2" - inkscape:collect="always"> - <stop - id="stop6835-3" - offset="0" - style="stop-color:#ffffff;stop-opacity:1;" /> - <stop - id="stop6837-8" - offset="1" - style="stop-color:#ffffff;stop-opacity:0;" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6753-0" - id="linearGradient4107-5" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,-3.506058,-0.3596506)" - x1="9.2127371" - y1="9.4198446" - x2="17.65192" - y2="17.15192" /> - <linearGradient - id="linearGradient6753-0" - inkscape:collect="always"> - <stop - id="stop6755-5" - offset="0" - style="stop-color:#888a85;stop-opacity:1" /> - <stop - id="stop6757-9" - offset="1" - style="stop-color:#eeeeec;stop-opacity:1" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17498" - id="linearGradient5212" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-10,-7.0000003)" - x1="28.897871" - y1="25.183172" - x2="19.272995" - y2="51.558521" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17780" - id="linearGradient5214" - gradientUnits="userSpaceOnUse" - x1="17.291615" - y1="31.321718" - x2="23.125856" - y2="14.906891" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4542" - id="linearGradient5216" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.727273,0,0,0.999999,12.27273,-34.84375)" - x1="33.120464" - y1="20.5" - x2="22.328388" - y2="20.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8002" - id="linearGradient5218" - gradientUnits="userSpaceOnUse" - x1="14.679631" - y1="16.403772" - x2="-6.3245316" - y2="46.160282" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6107-8" - id="linearGradient5220" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,9.5782761)" - x1="1382.548" - y1="921.10638" - x2="3503.502" - y2="1684.3187" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6156" - id="linearGradient5222" - gradientUnits="userSpaceOnUse" - x1="12.892972" - y1="33.490982" - x2="5.5136962" - y2="21.641434" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6958" - id="linearGradient5224" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,0.625,-0.676136,0,37.10227,15.875)" - x1="17" - y1="45.248375" - x2="17" - y2="30.759407" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2816" - id="linearGradient5226" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,0.673693,-0.676136,0,37.10227,14.81577)" - x1="15.406166" - y1="37.34367" - x2="16.864777" - y2="24.249567" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6249-2" - id="linearGradient5228" - gradientUnits="userSpaceOnUse" - x1="44.46957" - y1="-15.295949" - x2="31.692965" - y2="-15.121348" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient7994" - id="linearGradient5230" - gradientUnits="userSpaceOnUse" - x1="6.7611751" - y1="30.90625" - x2="19.926325" - y2="30.90625" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient7582" - id="radialGradient5256" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1,0,0,0.6206897,0,0.7823276)" - cx="11.15625" - cy="2.0625" - fx="11.15625" - fy="2.0625" - r="0.90625" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17498-5" - id="linearGradient5258" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-10,-7.0000003)" - x1="28.897871" - y1="25.183172" - x2="19.272995" - y2="51.558521" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17780-7" - id="linearGradient5260" - gradientUnits="userSpaceOnUse" - x1="12.744178" - y1="35.318134" - x2="21.54595" - y2="21.948019" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient4542-7" - id="linearGradient5262" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.727273,0,0,0.999999,12.27273,-34.84375)" - x1="33.120464" - y1="20.5" - x2="22.328388" - y2="20.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient8002-5" - id="linearGradient5264" - gradientUnits="userSpaceOnUse" - x1="14.679631" - y1="16.403772" - x2="-6.3245316" - y2="46.160282" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6107-8-2" - id="linearGradient5266" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,9.5782761)" - x1="1382.548" - y1="921.10638" - x2="3503.502" - y2="1684.3187" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6156-0" - id="linearGradient5268" - gradientUnits="userSpaceOnUse" - x1="16.843721" - y1="46.923531" - x2="5.5136962" - y2="21.641434" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6958" - id="linearGradient5270" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,0.625,-0.676136,0,37.10227,15.875)" - x1="17" - y1="45.248375" - x2="17" - y2="30.759407" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient2816" - id="linearGradient5272" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,0.673693,-0.676136,0,37.10227,14.81577)" - x1="15.406166" - y1="37.34367" - x2="16.864777" - y2="24.249567" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6249-2" - id="linearGradient5274" - gradientUnits="userSpaceOnUse" - x1="14.4375" - y1="13.8125" - x2="8" - y2="7.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17498-6" - id="linearGradient5304" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-10,-7.0000003)" - x1="6.6240072" - y1="10.33393" - x2="10.96449" - y2="28.577551" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17780-5" - id="linearGradient5306" - gradientUnits="userSpaceOnUse" - x1="0.36980912" - y1="9.6855135" - x2="-3.3759925" - y2="3.3339295" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6762" - id="linearGradient5308" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,-3.506058,-0.3596506)" - x1="6.4375" - y1="6.7797499" - x2="8.4537582" - y2="8.7975082" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6837" - id="linearGradient5310" - gradientUnits="userSpaceOnUse" - x1="-7.96875" - y1="11.5" - x2="0.96875" - y2="11.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6833" - id="linearGradient5312" - gradientUnits="userSpaceOnUse" - x1="8.7232523" - y1="6.2651649" - x2="6.1381931" - y2="6.2651649" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6753" - id="linearGradient5314" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,-3.506058,-0.3596506)" - x1="9.2127371" - y1="9.4198446" - x2="17.65192" - y2="17.15192" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6107-8-7" - id="linearGradient5316" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,9.5782761)" - x1="1382.548" - y1="921.10638" - x2="3503.502" - y2="1684.3187" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6156-4" - id="linearGradient5318" - gradientUnits="userSpaceOnUse" - x1="13.593721" - y1="14.923531" - x2="-1.2363037" - y2="11.641434" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6762-2" - id="linearGradient5320" - gradientUnits="userSpaceOnUse" - x1="6.5" - y1="9" - x2="7.5" - y2="5.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6833-5" - id="linearGradient5322" - gradientUnits="userSpaceOnUse" - x1="8.7232523" - y1="6.2651649" - x2="5.9061942" - y2="5.2978506" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6742-8" - id="linearGradient5324" - gradientUnits="userSpaceOnUse" - x1="9.9340439" - y1="4.53125" - x2="10.562407" - y2="22.717516" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6249" - id="linearGradient5326" - gradientUnits="userSpaceOnUse" - x1="14.4375" - y1="13.8125" - x2="8" - y2="7.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17498-6-8" - id="linearGradient5356" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-10,-7.0000003)" - x1="6.6240072" - y1="10.33393" - x2="10.96449" - y2="28.577551" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17780-5-8" - id="linearGradient5358" - gradientUnits="userSpaceOnUse" - x1="0.36980912" - y1="9.6855135" - x2="-3.3759925" - y2="3.3339295" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6762-8" - id="linearGradient5360" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,-3.506058,-0.3596506)" - x1="6.4375" - y1="6.7797499" - x2="8.4537582" - y2="8.7975082" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6837-0" - id="linearGradient5362" - gradientUnits="userSpaceOnUse" - x1="-7.96875" - y1="11.5" - x2="0.96875" - y2="11.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6833-2" - id="linearGradient5364" - gradientUnits="userSpaceOnUse" - x1="8.7232523" - y1="6.2651649" - x2="6.1381931" - y2="6.2651649" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6753-0" - id="linearGradient5366" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,-3.506058,-0.3596506)" - x1="9.2127371" - y1="9.4198446" - x2="17.65192" - y2="17.15192" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17498-6" - id="linearGradient5432" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-10,-7.0000003)" - x1="6.6240072" - y1="10.33393" - x2="10.96449" - y2="28.577551" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17780-5" - id="linearGradient5434" - gradientUnits="userSpaceOnUse" - x1="0.36980912" - y1="9.6855135" - x2="-3.3759925" - y2="3.3339295" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6762" - id="linearGradient5436" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,-3.506058,-0.3596506)" - x1="6.4375" - y1="6.7797499" - x2="8.4537582" - y2="8.7975082" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6837" - id="linearGradient5438" - gradientUnits="userSpaceOnUse" - x1="-7.96875" - y1="11.5" - x2="0.96875" - y2="11.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6833" - id="linearGradient5440" - gradientUnits="userSpaceOnUse" - x1="8.7232523" - y1="6.2651649" - x2="6.1381931" - y2="6.2651649" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6753" - id="linearGradient5442" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,-3.506058,-0.3596506)" - x1="9.2127371" - y1="9.4198446" - x2="17.65192" - y2="17.15192" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6107-8-7" - id="linearGradient5444" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,9.5782761)" - x1="1382.548" - y1="921.10638" - x2="3503.502" - y2="1684.3187" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6156-4" - id="linearGradient5446" - gradientUnits="userSpaceOnUse" - x1="13.593721" - y1="14.923531" - x2="-1.2363037" - y2="11.641434" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6762-2" - id="linearGradient5448" - gradientUnits="userSpaceOnUse" - x1="6.5" - y1="9" - x2="7.5" - y2="5.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6833-5" - id="linearGradient5450" - gradientUnits="userSpaceOnUse" - x1="8.7232523" - y1="6.2651649" - x2="5.9061942" - y2="5.2978506" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6742-8" - id="linearGradient5452" - gradientUnits="userSpaceOnUse" - x1="9.9340439" - y1="4.53125" - x2="10.562407" - y2="22.717516" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6249" - id="linearGradient5454" - gradientUnits="userSpaceOnUse" - x1="14.4375" - y1="13.8125" - x2="8" - y2="7.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17498-6" - id="linearGradient5484" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(-10,-7.0000003)" - x1="6.6240072" - y1="10.33393" - x2="10.96449" - y2="28.577551" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient17780-5" - id="linearGradient5486" - gradientUnits="userSpaceOnUse" - x1="0.36980912" - y1="9.6855135" - x2="-3.3759925" - y2="3.3339295" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6762" - id="linearGradient5488" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,-3.506058,-0.3596506)" - x1="6.4375" - y1="6.7797499" - x2="8.4537582" - y2="8.7975082" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6837" - id="linearGradient5490" - gradientUnits="userSpaceOnUse" - x1="-7.96875" - y1="11.5" - x2="0.96875" - y2="11.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6833" - id="linearGradient5492" - gradientUnits="userSpaceOnUse" - x1="8.7232523" - y1="6.2651649" - x2="6.1381931" - y2="6.2651649" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6753" - id="linearGradient5494" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.7071068,0.7071068,-0.7071068,0.7071068,-3.506058,-0.3596506)" - x1="9.2127371" - y1="9.4198446" - x2="17.65192" - y2="17.15192" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6107-8-7" - id="linearGradient5496" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.03776661,0.0377666,-0.03776661,0.0377666,160.03819,9.5782761)" - x1="1382.548" - y1="921.10638" - x2="3503.502" - y2="1684.3187" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6156-4" - id="linearGradient5498" - gradientUnits="userSpaceOnUse" - x1="13.593721" - y1="14.923531" - x2="-1.2363037" - y2="11.641434" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6762-2" - id="linearGradient5500" - gradientUnits="userSpaceOnUse" - x1="6.5" - y1="9" - x2="7.5" - y2="5.5" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6833-5" - id="linearGradient5502" - gradientUnits="userSpaceOnUse" - x1="8.7232523" - y1="6.2651649" - x2="5.9061942" - y2="5.2978506" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6742-8" - id="linearGradient5504" - gradientUnits="userSpaceOnUse" - x1="9.9340439" - y1="4.53125" - x2="10.562407" - y2="22.717516" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6249" - id="linearGradient5506" - gradientUnits="userSpaceOnUse" - x1="14.4375" - y1="13.8125" - x2="8" - y2="7.5" /> - </defs> - <metadata - id="metadata4"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:creator> - <cc:Agent> - <dc:title>Lapo Calamandrei</dc:title> - </cc:Agent> - </dc:creator> - <dc:source /> - <cc:license - rdf:resource="" /> - <dc:title>Firewall</dc:title> - <dc:subject> - <rdf:Bag /> - </dc:subject> - <dc:date /> - <dc:rights> - <cc:Agent> - <dc:title /> - </cc:Agent> - </dc:rights> - <dc:publisher> - <cc:Agent> - <dc:title /> - </cc:Agent> - </dc:publisher> - <dc:identifier /> - <dc:relation /> - <dc:language /> - <dc:coverage /> - <dc:description /> - <dc:contributor> - <cc:Agent> - <dc:title /> - </cc:Agent> - </dc:contributor> - </cc:Work> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - style="display:inline" - inkscape:groupmode="layer" - inkscape:label="artwork" - id="layer1"> - <g - inkscape:groupmode="layer" - id="layer2" - inkscape:label="baseplate" - style="display:none" - sodipodi:insensitive="true"> - <rect - style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect6284" - width="48" - height="48" - x="296.0625" - y="51.99633" - inkscape:label="48x48" /> - <rect - inkscape:label="32x32" - y="127.99634" - x="303" - height="32" - width="32" - id="rect6592" - style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <rect - inkscape:label="24x24" - y="178" - x="302" - height="24" - width="24" - id="rect5028" - style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <rect - inkscape:label="16x16" - y="221" - x="303" - height="16" - width="16" - id="rect6833" - style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <rect - style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect6749" - width="22" - height="22" - x="303" - y="179.05884" - inkscape:label="22x22" /> - <text - id="context" - inkscape:label="context" - style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans" - x="31.87059" - xml:space="preserve" - y="18.860306"><tspan - id="tspan2716" - sodipodi:role="line" - x="31.87059" - y="18.860306" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans">apps</tspan></text> - <text - id="icon-name" - inkscape:label="icon-name" - sodipodi:linespacing="125%" - style="font-size:18px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans Bold" - x="199.87057" - xml:space="preserve" - y="18.860306"><tspan - id="tspan3023" - sodipodi:role="line" - x="199.87057" - y="18.860306" - style="font-size:18px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans Bold">seahorse</tspan></text> - <rect - inkscape:label="256x256" - y="32" - x="20" - height="256" - width="256" - id="rect6282" - style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" /> - </g> - <g - inkscape:groupmode="layer" - id="layer4" - inkscape:label="smallsizes" - style="display:inline"> - <g - id="g6154" - style="fill:#ffffff" - transform="matrix(1.25,0,0,1.25,-78,-47.25)" /> - <g - transform="matrix(0.01764125,1.4827579,1.4547795,2.9762967e-4,279.22187,67.025361)" - id="g7413"> - <path - style="color:#000000;fill:url(#linearGradient3987);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3989);stroke-width:0.68087411px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - sodipodi:nodetypes="sccccccccccccccccccccccscsssc" - id="path7415" - d="M 13.4375,16.5 C 9.5186406,16.51383 9.104267,20.317626 9.104267,20.317626 L 4.5779358,22.440454 5.5274999,28.161436 10.537742,29.545854 10.34375,31.5 l 1.5,1.5 -1.5,1.5 0,1 2,1 0,1 -2,1 0,1 1.5,1.5 -1.5,1.5 0,1 2.5,2 2.5,0 1,-1.5 0,-14 4.843587,-3.351692 0.285612,-4.53777 -3.879353,-1.635941 C 17.697518,18.950089 16.72173,16.488411 13.4375,16.5 z m -0.09375,2 c 1.104,0 2,0.896 2,2 0,1.104 -0.896,2 -2,2 -1.104,0 -2,-0.896 -2,-2 0,-1.104 0.896,-2 2,-2 z" - inkscape:connector-curvature="0" /> - <rect - y="-14.84375" - x="29" - width="16.311773" - transform="matrix(0,1,-1,0,0,0)" - style="opacity:0.61538463;fill:url(#linearGradient3991);fill-opacity:1;fill-rule:evenodd;stroke:none" - id="rect7423" - height="0.98128641" /> - <path - d="m 13.4375,17.28125 c -1.703381,0.006 -2.476193,0.776336 -2.96875,1.5625 -0.4925567,0.786164 -0.59375,1.5625 -0.59375,1.5625 a 0.79285854,0.79285854 0 0 1 -0.4375,0.625 l -4,1.875 0.78125,4.625 4.53125,1.25 a 0.79285854,0.79285854 0 0 1 0.5625,0.8125 l -0.15625,1.59375 1.25,1.25 a 0.79285854,0.79285854 0 0 1 0,1.125 l -1.28125,1.28125 0,0.15625 1.5625,0.78125 A 0.79285854,0.79285854 0 0 1 13.125,36.5 l 0,1 a 0.79285854,0.79285854 0 0 1 -0.4375,0.71875 L 11.125,39 l 0,0.15625 1.28125,1.28125 a 0.79285854,0.79285854 0 0 1 0,1.125 l -1.28125,1.28125 0,0.25 2.03125,1.625 1.75,0 0.65625,-0.96875 0,-13.75 a 0.79285854,0.79285854 0 0 1 0.34375,-0.65625 l 4.53125,-3.125 0.21875,-3.59375 -3.375,-1.4375 A 0.79285854,0.79285854 0 0 1 16.8125,20.40625 c 0.03854,-0.565438 -0.159384,-1.378013 -0.65625,-2 -0.496866,-0.621987 -1.274512,-1.130096 -2.71875,-1.125 z m -0.09375,0.4375 c 1.532943,0 2.78125,1.248307 2.78125,2.78125 0,1.532943 -1.248307,2.78125 -2.78125,2.78125 -1.532943,0 -2.78125,-1.248307 -2.78125,-2.78125 0,-1.532943 1.248307,-2.78125 2.78125,-2.78125 z" - inkscape:href="#path7415" - id="path17516" - style="color:#000000;fill:none;stroke:url(#linearGradient3993);stroke-width:0.68087411px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - xlink:href="#path7415" - inkscape:original="M 13.4375 16.5 C 9.5186406 16.51383 9.09375 20.3125 9.09375 20.3125 L 4.5625 22.4375 L 5.53125 28.15625 L 10.53125 29.53125 L 10.34375 31.5 L 11.84375 33 L 10.34375 34.5 L 10.34375 35.5 L 12.34375 36.5 L 12.34375 37.5 L 10.34375 38.5 L 10.34375 39.5 L 11.84375 41 L 10.34375 42.5 L 10.34375 43.5 L 12.84375 45.5 L 15.34375 45.5 L 16.34375 44 L 16.34375 30 L 21.1875 26.65625 L 21.46875 22.125 L 17.59375 20.46875 C 17.697672 18.944242 16.72173 16.488411 13.4375 16.5 z M 13.34375 18.5 C 14.44775 18.5 15.34375 19.396 15.34375 20.5 C 15.34375 21.604 14.44775 22.5 13.34375 22.5 C 12.23975 22.5 11.34375 21.604 11.34375 20.5 C 11.34375 19.396 12.23975 18.5 13.34375 18.5 z " - inkscape:radius="-0.79277927" - sodipodi:type="inkscape:offset" /> - </g> - <path - transform="matrix(0.5532396,-0.54421924,0.87679765,0.89133046,297.34092,149.00568)" - style="fill:url(#radialGradient4113);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - sodipodi:type="arc" - sodipodi:ry="0.5625" - sodipodi:rx="0.90625" - sodipodi:cy="2.0625" - sodipodi:cx="11.15625" - id="path177" - d="m 12.0625,2.0625 a 0.90625,0.5625 0 1 1 -1.8125,0 0.90625,0.5625 0 1 1 1.8125,0 z" - inkscape:export-filename="/data/projects/seahorse/32x32.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" /> - <g - transform="matrix(0.00416675,0.99999132,0.99999132,-0.00416675,301.00511,199.0963)" - id="g6769" - inkscape:export-filename="/data/projects/seahorse/24x24.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <path - style="color:#000000;fill:url(#linearGradient4097);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4099);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - sodipodi:nodetypes="csccccccccccccccccssssc" - id="path6081" - d="M -0.5017742,6.4584078 C -0.37175202,4.4522829 -0.8448083,2.5 -3.5060582,2.5 -6.2660581,2.5 -6.6064795,4.8828745 -6.625,6.3689418 l -1.8916614,1.1881832 -0.01828,2.1039435 3.0401445,2.3848735 -0.0052,2.529476 L -4.5,16 l -1,1.5 0,1 2,2 0.9999989,0 L -1.5,19.5 -1.51732,12.045942 1.4161394,9.5495158 1.4878836,7.4939418 z M -2.7989514,5.3726214 c 0.1810001,0.1810001 0.3093592,0.4311066 0.3093592,0.7071068 2e-7,0.5520005 -0.4644656,1.016466 -1.016466,1.016466 -0.552,10e-8 -1.016466,-0.4644656 -1.016466,-1.016466 0,-0.5520004 0.4644656,-1.016466 1.016466,-1.016466 0.2760002,0 0.5261067,0.1283591 0.7071068,0.3093592 z" - inkscape:connector-curvature="0" /> - <path - style="opacity:0.06334845;fill:url(#linearGradient4101);fill-opacity:1;fill-rule:evenodd;stroke:none" - id="path6083" - d="m 0.71269221,8.9174565 -8.43750041,0 c 0.6214183,1.7412405 2.2649102,3.0000005 4.2187502,3.0000005 1.9538399,0 3.5973328,-1.258759 4.21875021,-3.0000005 z" - inkscape:connector-curvature="0" /> - <path - style="opacity:0.52036252;fill:none;stroke:url(#linearGradient4103);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0199475" - inkscape:original="M -3.5 2.5 C -6.2599999 2.5 -8.5 4.7399998 -8.5 7.5 C -8.4999997 9.5446378 -7.2593482 11.256644 -5.5 12.03125 L -5.5 14.5625 L -4.5 16 L -5.5 17.5 L -5.5 18.5 C -5.5 18.5 -3.5 20.5 -3.5 20.5 L -2.5 20.5 L -1.5 19.5 L -1.53125 12.03125 C 0.22809828 11.256644 1.4999997 9.5446378 1.5 7.5 C 1.5000001 6.12 0.93625013 4.8737501 0.03125 3.96875 C -0.87375013 3.0637498 -2.1200001 2.5 -3.5 2.5 z " - id="path6765" - d="m -3.5,3.53125 c -2.2081443,0 -3.96875,1.7606055 -3.96875,3.96875 2e-7,1.6320467 0.9610544,2.971218 2.375,3.59375 a 1.0200495,1.0200495 0 0 1 0.625,0.9375 l 0,2.21875 0.8125,1.15625 a 1.0200495,1.0200495 0 0 1 0,1.15625 l -0.8125,1.21875 0,0.3125 1.375,1.375 0.1875,0 0.375,-0.375 -0.03125,-7.0625 a 1.0200495,1.0200495 0 0 1 0.625,-0.9375 C -0.51947782,10.469423 0.46874976,9.1216542 0.46875,7.5 0.46875008,6.3977756 0.03620106,5.411201 -0.6875,4.6875 -1.411201,3.9637989 -2.3977756,3.53125 -3.5,3.53125 z" /> - <path - transform="matrix(0,1.3333333,-1.3333333,0,4.493942,-3.3285949)" - style="fill:none;stroke:url(#linearGradient4105);stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" - sodipodi:type="arc" - sodipodi:ry="1.5" - sodipodi:rx="1.5" - sodipodi:cy="6" - sodipodi:cx="7" - id="path6085" - d="M 8.5,6 C 8.5,6.8284271 7.8284271,7.5 7,7.5 6.1715729,7.5 5.5,6.8284271 5.5,6 5.5,5.1715729 6.1715729,4.5 7,4.5 7.8284271,4.5 8.5,5.1715729 8.5,6 z" /> - <path - style="fill:none;stroke:url(#linearGradient4107);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" - sodipodi:nodetypes="cc" - id="path6091" - d="m -3.1525046,18.37868 0,-5.656855" - inkscape:connector-curvature="0" /> - </g> - <g - style="display:inline;enable-background:new" - id="g7413-2" - transform="matrix(0.04996045,0.90113171,0.90113171,-0.04996045,286.95195,137.30619)" - inkscape:export-filename="/data/projects/seahorse/32x32.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <path - inkscape:connector-curvature="0" - d="M 13.4375,16.5 C 9.5186406,16.51383 9.104267,20.317626 9.104267,20.317626 L 6.1982808,21.790068 6.2456938,25.750941 10.34375,30 l 0,1.5 1.5,1.5 -1.5,1.5 0,1 2,1 0,1 -2,1 0,1 1.5,1.5 -1.5,1.5 0,1 2.440937,1.274442 3.754218,0.995104 L 17.061728,43.68543 16.34375,30 l 4.843587,-3.351692 0.285612,-4.53777 -3.879353,-1.635941 C 17.697518,18.950089 16.72173,16.488411 13.4375,16.5 z m -0.09375,2 c 1.104,0 2,0.896 2,2 0,1.104 -0.896,2 -2,2 -1.104,0 -2,-0.896 -2,-2 0,-1.104 0.896,-2 2,-2 z" - id="path7415-5" - sodipodi:nodetypes="sccccccccccccccccccccccscsssc" - style="color:#000000;fill:url(#linearGradient17518-1);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient17786-1);stroke-width:1.10801411px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - <rect - height="0.98128641" - id="rect7423-4" - style="opacity:0.61538463;fill:url(#linearGradient17750);fill-opacity:1;fill-rule:evenodd;stroke:none" - transform="matrix(0,1,-1,0,0,0)" - width="16.311773" - x="29" - y="-14.84375" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-0.96211886" - inkscape:original="M 13.4375 16.5 C 9.5186406 16.51383 9.09375 20.3125 9.09375 20.3125 L 6.1875 21.78125 L 6.25 25.75 L 10.34375 30 L 10.34375 31.5 L 11.84375 33 L 10.34375 34.5 L 10.34375 35.5 L 12.34375 36.5 L 12.34375 37.5 L 10.34375 38.5 L 10.34375 39.5 L 11.84375 41 L 10.34375 42.5 L 10.34375 43.5 L 12.78125 44.78125 L 16.53125 45.78125 L 17.0625 43.6875 L 16.34375 30 L 21.1875 26.65625 L 21.46875 22.125 L 17.59375 20.46875 C 17.697672 18.944242 16.72173 16.488411 13.4375 16.5 z M 13.34375 18.5 C 14.44775 18.5 15.34375 19.396 15.34375 20.5 C 15.34375 21.604 14.44775 22.5 13.34375 22.5 C 12.23975 22.5 11.34375 21.604 11.34375 20.5 C 11.34375 19.396 12.23975 18.5 13.34375 18.5 z " - xlink:href="#path7415-5" - style="color:#000000;fill:none;stroke:url(#linearGradient8008-1);stroke-width:1.10801411px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - id="path17516-2" - inkscape:href="#path7415-5" - d="m 13.4375,17.46875 c -1.648688,0.0058 -2.342056,0.71788 -2.8125,1.46875 -0.470444,0.75087 -0.5625,1.46875 -0.5625,1.46875 a 0.96221508,0.96221508 0 0 1 -0.53125,0.75 l -2.375,1.1875 0.0625,3.03125 3.8125,3.96875 A 0.96221508,0.96221508 0 0 1 11.3125,30 l 0,1.09375 1.21875,1.21875 a 0.96221508,0.96221508 0 0 1 0,1.375 l -1.21875,1.1875 0,0.03125 1.46875,0.71875 A 0.96221508,0.96221508 0 0 1 13.3125,36.5 l 0,1 a 0.96221508,0.96221508 0 0 1 -0.53125,0.875 l -1.46875,0.71875 0,0.03125 1.21875,1.1875 a 0.96221508,0.96221508 0 0 1 0,1.375 l -1.21875,1.21875 0,0.03125 1.71875,0.90625 0.03125,0 2.78125,0.75 0.25,-1 L 15.375,30.0625 a 0.96221508,0.96221508 0 0 1 0.4375,-0.84375 l 4.4375,-3.0625 0.21875,-3.4375 -3.25,-1.375 A 0.96221508,0.96221508 0 0 1 16.625,20.40625 C 16.660679,19.882852 16.497217,19.083307 16.03125,18.5 15.565283,17.916693 14.83947,17.463803 13.4375,17.46875 z m -0.09375,0.0625 c 1.624567,0 2.96875,1.344183 2.96875,2.96875 0,1.624567 -1.344183,2.96875 -2.96875,2.96875 -1.624567,0 -2.96875,-1.344183 -2.96875,-2.96875 0,-1.624567 1.344183,-2.96875 2.96875,-2.96875 z" /> - </g> - <g - transform="matrix(-0.03314179,-1.4601652,1.4591995,-1.244622e-4,279.83218,118.08326)" - id="g6765"> - <path - style="color:#000000;fill:url(#linearGradient3907);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3909);stroke-width:0.68507993;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - sodipodi:nodetypes="csccccccccccccccccsccsssc" - id="path6767" - d="m 13.4375,16.5 c -3.9188838,-1e-6 -7.09375,3.157775 -7.09375,7.0625 2e-7,2.818198 1.6046259,5.300595 4,6.4375 l 0,1.5 1.39524,1.39524 -1.5,1.5 0,1 2.10476,1.10476 0,1 -2,1 0,1 1.3254,1.3254 -1.1508,1.1508 0.374619,1.468424 1.846021,1.880776 2.22064,0 1.38412,-1.3254 0,-14 c 2.372429,-1.145434 4,-3.698516 4,-6.5 0,-3.904724 -2.987366,-7 -6.90625,-7 z m -0.09375,2 c 1.104,0 2,0.896 2,2 0,1.104 -0.896,2 -2,2 -1.104,0 -2,-0.896 -2,-2 0,-1.104 0.896,-2 2,-2 z" - inkscape:connector-curvature="0" /> - <path - style="opacity:0.3;fill:url(#linearGradient3911);fill-opacity:1;fill-rule:evenodd;stroke:none" - id="path6769" - d="M 18.846598,24 8.028422,24 c 0,2.76 2.423271,5 5.409088,5 2.985817,0 5.409088,-2.24 5.409088,-5 z" - inkscape:connector-curvature="0" /> - <path - style="opacity:0.6;fill:url(#linearGradient3913);fill-opacity:1;fill-rule:evenodd;stroke:none" - sodipodi:type="inkscape:offset" - inkscape:radius="-0.10364762" - inkscape:original="M 13.40625 17.53125 C 13.179953 17.535742 12.940048 17.565361 12.71875 17.59375 C 11.746507 17.718472 10.844502 18.056009 10.0625 18.5625 C 10.273788 19.382459 10.603512 20.028723 11 20.59375 C 10.998818 20.562191 11 20.531846 11 20.5 C 11 19.119998 12.119999 18 13.5 18 C 14.880001 18 16 19.119998 16 20.5 C 16 21.880003 14.880001 23 13.5 23 C 13.338115 23 13.184591 22.966937 13.03125 22.9375 C 14.159156 24.243071 15.219875 25.922289 15.46875 29.3125 C 17.839227 28.416828 19.53125 26.324417 19.53125 23.5625 C 19.444481 20.923505 17.958879 18.870351 15.46875 17.84375 C 14.777284 17.614671 14.085142 17.517773 13.40625 17.53125 z M 15.46875 31.96875 C 15.356466 34.978468 14.778907 38.970391 13.4375 44.46875 L 14.78125 44.46875 L 15.46875 43.125 L 15.46875 31.96875 z " - id="path6832" - d="m 13.40625,17.625 c -0.218712,0.0043 -0.466555,0.03416 -0.6875,0.0625 -0.93254,0.119629 -1.775868,0.460272 -2.53125,0.9375 0.173643,0.634817 0.42464,1.158079 0.71875,1.625 0.125954,-1.319354 1.241853,-2.34375 2.59375,-2.34375 1.436081,0 2.59375,1.157668 2.59375,2.59375 0,1.436083 -1.157669,2.59375 -2.59375,2.59375 -0.07717,0 -0.14697,-0.02119 -0.21875,-0.03125 1.059311,1.270254 2.021943,2.944267 2.28125,6.09375 2.266237,-0.909044 3.875,-2.925566 3.875,-5.59375 -0.08555,-2.601924 -1.541462,-4.611423 -4,-5.625 -0.680148,-0.225329 -1.363612,-0.325754 -2.03125,-0.3125 z M 15.375,34.6875 c -0.279435,2.585586 -0.854558,5.742004 -1.8125,9.6875 l 1.15625,0 0.65625,-1.3125 0,-8.375 z" /> - <rect - y="-14.84375" - x="29" - width="16.311773" - transform="matrix(0,1,-1,0,0,0)" - style="color:#000000;fill:url(#linearGradient3915);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.79014987px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect6776" - height="0.98128641" /> - <path - d="m 13.4375,17.3125 c -3.4801559,-1e-6 -6.28125,2.787977 -6.28125,6.25 2e-7,2.508186 1.4242699,4.687474 3.53125,5.6875 A 0.81679083,0.81679083 0 0 1 11.15625,30 l 0,1.1875 1.15625,1.15625 a 0.81679083,0.81679083 0 0 1 0,1.125 l -1.25,1.25 0,0.1875 1.65625,0.875 A 0.81679083,0.81679083 0 0 1 13.15625,36.5 l 0,1 a 0.81679083,0.81679083 0 0 1 -0.4375,0.71875 L 11.15625,39 l 0,0.1875 1.0625,1.0625 A 0.81679083,0.81679083 0 0 1 12.25,41.375 L 11.4375,42.21875 11.625,43 l 1.46875,1.5 1.53125,0 0.90625,-0.84375 0,-13.65625 A 0.81679083,0.81679083 0 0 1 16,29.25 c 2.076228,-1.002425 3.53125,-3.264837 3.53125,-5.75 0,-3.488167 -2.60491,-6.1875 -6.09375,-6.1875 z m -0.09375,0.375 c 1.545891,0 2.8125,1.266609 2.8125,2.8125 0,1.545891 -1.266609,2.8125 -2.8125,2.8125 -1.545891,0 -2.8125,-1.266609 -2.8125,-2.8125 0,-1.545891 1.266609,-2.8125 2.8125,-2.8125 z" - inkscape:href="#path6767" - id="path6313" - style="color:#000000;fill:none;stroke:url(#linearGradient3917);stroke-width:0.68507993;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - xlink:href="#path6767" - inkscape:original="M 13.4375 16.5 C 9.5186162 16.499999 6.34375 19.657775 6.34375 23.5625 C 6.3437502 26.380698 7.9483759 28.863095 10.34375 30 L 10.34375 31.5 L 11.75 32.90625 L 10.25 34.40625 L 10.25 35.40625 L 12.34375 36.5 L 12.34375 37.5 L 10.34375 38.5 L 10.34375 39.5 L 11.65625 40.8125 L 10.53125 41.96875 L 10.90625 43.4375 L 12.75 45.3125 L 14.96875 45.3125 L 16.34375 44 L 16.34375 30 C 18.716179 28.854566 20.34375 26.301484 20.34375 23.5 C 20.34375 19.595276 17.356384 16.5 13.4375 16.5 z M 13.34375 18.5 C 14.44775 18.5 15.34375 19.396 15.34375 20.5 C 15.34375 21.604 14.44775 22.5 13.34375 22.5 C 12.23975 22.5 11.34375 21.604 11.34375 20.5 C 11.34375 19.396 12.23975 18.5 13.34375 18.5 z " - inkscape:radius="-0.81670916" - sodipodi:type="inkscape:offset" /> - </g> - <g - transform="matrix(9.4955145e-4,-0.89007416,0.89007416,9.4955145e-4,288.00153,167.01742)" - id="g193" - inkscape:export-filename="/data/projects/seahorse/32x32.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <path - style="color:#000000;fill:url(#linearGradient4907);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4909);stroke-width:1.1235013;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - sodipodi:nodetypes="csccccccccccccccccsccsssc" - id="path195" - d="m 13.4375,16.5 c -3.9188838,-1e-6 -7.09375,3.157775 -7.09375,7.0625 2e-7,2.818198 1.6046259,5.300595 4,6.4375 l 0,1.5 1.5,1.5 -1.5,1.5 0,1 2,1 0,1 -2,1 0,1 1.5,1.5 -1.5,1.5 0,1 2.5,2 2.5,0 1,-1.5 0,-14 c 2.372429,-1.145434 4,-3.698516 4,-6.5 0,-3.904724 -2.987366,-7 -6.90625,-7 z m -0.09375,2 c 1.104,0 2,0.896 2,2 0,1.104 -0.896,2 -2,2 -1.104,0 -2,-0.896 -2,-2 0,-1.104 0.896,-2 2,-2 z" - inkscape:connector-curvature="0" /> - <path - style="opacity:0.3;fill:url(#linearGradient4911);fill-opacity:1;fill-rule:evenodd;stroke:none" - id="path197" - d="M 18.846598,24 8.028422,24 c 0,2.76 2.423271,5 5.409088,5 2.985817,0 5.409088,-2.24 5.409088,-5 z" - inkscape:connector-curvature="0" /> - <path - xlink:href="#path1884" - style="fill:none;stroke:#ffffff;stroke-width:1.12350094;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - sodipodi:type="inkscape:offset" - inkscape:radius="-1.1191492" - inkscape:original="M 13.4375 16.5 C 9.5186162 16.499999 6.34375 19.657775 6.34375 23.5625 C 6.3437502 26.380698 7.9483759 28.863095 10.34375 30 L 10.34375 31.5 L 11.84375 33 L 10.34375 34.5 L 10.34375 35.5 L 12.34375 36.5 L 12.34375 37.5 L 10.34375 38.5 L 10.34375 39.5 L 11.84375 41 L 10.34375 42.5 L 10.34375 43.5 L 12.84375 45.5 L 15.34375 45.5 L 16.34375 44 L 16.34375 30 C 18.716179 28.854566 20.34375 26.301484 20.34375 23.5 C 20.34375 19.595276 17.356384 16.5 13.4375 16.5 z M 13.34375 18.5 C 14.44775 18.5 15.34375 19.396 15.34375 20.5 C 15.34375 21.604 14.44775 22.5 13.34375 22.5 C 12.23975 22.5 11.34375 21.604 11.34375 20.5 C 11.34375 19.396 12.23975 18.5 13.34375 18.5 z " - inkscape:href="#path1884" - id="path199" - d="m 14.3125,17.78125 c 1.186974,0.442749 2.15625,1.386496 2.15625,2.71875 0,1.70953 -1.41547,3.125 -3.125,3.125 -1.70953,0 -3.125,-1.41547 -3.125,-3.125 0,-1.246778 0.868438,-2.127736 1.9375,-2.625 -2.6767585,0.591658 -4.6875,2.839731 -4.6875,5.6875 2e-7,2.393384 1.3435667,4.488163 3.34375,5.4375 a 1.1192611,1.1192611 0 0 1 0.65625,1 l 0,1.0625 1.15625,1.15625 a 1.1192611,1.1192611 0 0 1 0,1.5625 l -1.0625,1.0625 1.28125,0.65625 a 1.1192611,1.1192611 0 0 1 0.625,1 l 0,1 a 1.1192611,1.1192611 0 0 1 -0.625,1 l -1.28125,0.65625 1.0625,1.0625 a 1.1192611,1.1192611 0 0 1 0,1.5625 l -1.15625,1.15625 0,0.03125 1.75,1.40625 1.53125,0 0.46875,-0.71875 0,-13.65625 a 1.1192611,1.1192611 0 0 1 0.625,-1 c 1.966541,-0.949467 3.375,-3.131976 3.375,-5.5 0,-3.019151 -2.052931,-5.297441 -4.90625,-5.71875 z" /> - <path - style="opacity:0.6;fill:url(#linearGradient4913);fill-opacity:1;fill-rule:evenodd;stroke:none" - sodipodi:type="inkscape:offset" - inkscape:radius="-0.10364762" - inkscape:original="M 13.40625 17.53125 C 13.179953 17.535742 12.940048 17.565361 12.71875 17.59375 C 11.746507 17.718472 10.844502 18.056009 10.0625 18.5625 C 10.273788 19.382459 10.603512 20.028723 11 20.59375 C 10.998818 20.562191 11 20.531846 11 20.5 C 11 19.119998 12.119999 18 13.5 18 C 14.880001 18 16 19.119998 16 20.5 C 16 21.880003 14.880001 23 13.5 23 C 13.338115 23 13.184591 22.966937 13.03125 22.9375 C 14.159156 24.243071 15.219875 25.922289 15.46875 29.3125 C 17.839227 28.416828 19.53125 26.324417 19.53125 23.5625 C 19.444481 20.923505 17.958879 18.870351 15.46875 17.84375 C 14.777284 17.614671 14.085142 17.517773 13.40625 17.53125 z M 15.46875 31.96875 C 15.356466 34.978468 14.778907 38.970391 13.4375 44.46875 L 14.78125 44.46875 L 15.46875 43.125 L 15.46875 31.96875 z " - id="path201" - d="m 13.40625,17.625 c -0.218712,0.0043 -0.466555,0.03416 -0.6875,0.0625 -0.93254,0.119629 -1.775868,0.460272 -2.53125,0.9375 0.173643,0.634817 0.42464,1.158079 0.71875,1.625 0.125954,-1.319354 1.241853,-2.34375 2.59375,-2.34375 1.436081,0 2.59375,1.157668 2.59375,2.59375 0,1.436083 -1.157669,2.59375 -2.59375,2.59375 -0.07717,0 -0.14697,-0.02119 -0.21875,-0.03125 1.059311,1.270254 2.021943,2.944267 2.28125,6.09375 2.266237,-0.909044 3.875,-2.925566 3.875,-5.59375 -0.08555,-2.601924 -1.541462,-4.611423 -4,-5.625 -0.680148,-0.225329 -1.363612,-0.325754 -2.03125,-0.3125 z M 15.375,34.6875 c -0.279435,2.585586 -0.854558,5.742004 -1.8125,9.6875 l 1.15625,0 0.65625,-1.3125 0,-8.375 z" /> - <rect - y="-14.84375" - x="29" - width="16.311773" - transform="matrix(0,1,-1,0,0,0)" - style="opacity:0.61538463;color:#000000;fill:none;stroke:url(#linearGradient4915);stroke-width:1.1235013px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect203" - height="0.98128641" /> - </g> - <g - transform="matrix(0.7179987,-0.69604444,0.69604444,0.7179987,300.63641,201.31637)" - id="g6111" - style="display:inline;enable-background:new" - inkscape:export-filename="/data/projects/seahorse/24x24.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <path - style="color:#000000;fill:url(#linearGradient4085);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient4087);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="path7124" - d="m 5.5,0.5 c -1.2798634,3e-8 -2.5554427,0.49294272 -3.53125,1.46875 -1.95161458,1.9516146 -1.95161484,5.1108852 0,7.0625 1.4457774,1.445777 3.5519739,1.790068 5.34375,1.09375 L 8,11 l 1.5,-0.5 0,2 2,0 0,1.5 0.5,0.5 c 0,0 3,0 3,0 l 0.5,-0.5 0,-1.5 -5.375,-5.1875 C 10.821318,5.5207238 10.477027,3.4145274 9.03125,1.96875 8.0554428,0.9929426 6.7798634,0.49999997 5.5,0.5 z m -1,3 c 0.2559728,0 0.5235884,0.086088 0.71875,0.28125 0.3903234,0.3903232 0.3903232,1.0471768 0,1.4375 -0.3903229,0.390323 -1.0471768,0.3903232 -1.4375,0 -0.3903232,-0.3903233 -0.3903232,-1.0471768 0,-1.4375 C 3.9764116,3.5860884 4.2440272,3.5 4.5,3.5 z" - inkscape:connector-curvature="0" /> - <path - style="opacity:0.13574662;fill:url(#linearGradient4089);fill-opacity:1;fill-rule:evenodd;stroke:none" - id="path6142" - d="M 9.543012,3.5767984 3.5767984,9.543012 C 5.2474506,10.334846 7.2996521,10.062799 8.6812256,8.6812256 10.062799,7.2996522 10.334847,5.2474503 9.543012,3.5767984 z" - inkscape:connector-curvature="0" /> - <path - transform="matrix(0.942809,0.942809,-0.942809,0.942809,3.5574935,-7.7562147)" - style="fill:none;stroke:url(#linearGradient4091);stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" - sodipodi:type="arc" - sodipodi:ry="1.5" - sodipodi:rx="1.5" - sodipodi:cy="6" - sodipodi:cx="7" - id="path7134" - d="M 8.5,6 C 8.5,6.8284271 7.8284271,7.5 7,7.5 6.1715729,7.5 5.5,6.8284271 5.5,6 5.5,5.1715729 6.1715729,4.5 7,4.5 7.8284271,4.5 8.5,5.1715729 8.5,6 z" /> - <path - style="opacity:0.42986426;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0313957" - inkscape:original="M 5.5 0.5 C 4.2201366 0.50000003 2.9445573 0.99294272 1.96875 1.96875 C 0.017135421 3.9203646 0.017135161 7.0796352 1.96875 9.03125 C 3.4145274 10.477027 5.5207239 10.821318 7.3125 10.125 L 8 11 L 9.5 10.5 L 9.5 12.5 L 11.5 12.5 L 11.5 14 L 12 14.5 C 12 14.5 15 14.5 15 14.5 L 15.5 14 L 15.5 12.5 L 10.125 7.3125 C 10.821318 5.5207238 10.477027 3.4145274 9.03125 1.96875 C 8.0554428 0.9929426 6.7798634 0.49999997 5.5 0.5 z " - id="path6161" - d="m 5.5,1.53125 c -1.0150336,0 -2.0316705,0.3754205 -2.8125,1.15625 -1.558081,1.558081 -1.5580812,4.0669188 0,5.625 1.1495193,1.149519 2.8195738,1.3996406 4.25,0.84375 A 1.0314988,1.0314988 0 0 1 8.125,9.5 L 8.375,9.8125 9.1875,9.53125 A 1.0314988,1.0314988 0 0 1 10.53125,10.5 l 0,0.96875 0.96875,0 A 1.0314988,1.0314988 0 0 1 12.53125,12.5 l 0,0.96875 1.9375,0 0,-0.53125 -5.0625,-4.875 a 1.0314988,1.0314988 0 0 1 -0.25,-1.125 C 9.7121406,5.5070736 9.462019,3.8370193 8.3125,2.6875 7.5316707,1.9066705 6.5150336,1.53125 5.5,1.53125 z" /> - <path - style="fill:none;stroke:url(#linearGradient4093);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0.69999992" - sodipodi:nodetypes="cccsscsc" - id="path6750" - d="m 14.46875,13.46875 0,-0.53125 -5.0625,-4.875 C 9.1016694,7.7733588 9.0027957,7.3284268 9.15625,6.9375 9.7121406,5.5070736 9.462019,3.8370193 8.3125,2.6875 7.5316707,1.9066705 6.5150336,1.53125 5.5,1.53125 c -1.0150336,0 -2.0316705,0.3754205 -2.8125,1.15625 -1.558081,1.558081 -1.5580812,4.0669188 0,5.625" - inkscape:connector-curvature="0" /> - <path - style="fill:none;stroke:url(#linearGradient4095);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" - sodipodi:nodetypes="cc" - id="path6773" - d="M 13.5,13 9.5,9" - inkscape:connector-curvature="0" /> - </g> - <rect - style="color:#000000;fill:none;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect4939" - width="31.875473" - height="31.876154" - x="300.05255" - y="135.0625" - ry="0" - inkscape:export-filename="/data/projects/seahorse/32x32.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" /> - <rect - style="color:#000000;fill:none;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect4941" - width="23.874947" - height="23.874947" - x="300.05255" - y="186.0625" - inkscape:export-filename="/data/projects/seahorse/24x24.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" /> - <rect - style="color:#000000;fill:none;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect4943" - width="15.876632" - height="15.876632" - x="300.0625" - y="219.0625" - inkscape:export-filename="/data/projects/seahorse/16x16.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" /> - <rect - style="color:#000000;fill:none;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect4939-4" - width="47.81321" - height="47.814232" - x="300.0625" - y="68.0625" - ry="0" /> - <g - id="g5198" - transform="matrix(-0.03314179,-1.4601652,1.4591995,-1.244622e-4,231.83218,113.33326)"> - <path - inkscape:connector-curvature="0" - d="m 13.4375,16.5 c -3.9188838,-1e-6 -7.09375,3.157775 -7.09375,7.0625 2e-7,2.818198 1.6046259,5.300595 4,6.4375 l 0,1.5 1.39524,1.39524 -1.5,1.5 0,1 2.10476,1.10476 0,1 -2,1 0,1 1.3254,1.3254 -1.1508,1.1508 0.374619,1.468424 1.846021,1.880776 2.22064,0 1.38412,-1.3254 0,-14 c 2.372429,-1.145434 4,-3.698516 4,-6.5 0,-3.904724 -2.987366,-7 -6.90625,-7 z m -0.09375,2 c 1.104,0 2,0.896 2,2 0,1.104 -0.896,2 -2,2 -1.104,0 -2,-0.896 -2,-2 0,-1.104 0.896,-2 2,-2 z" - id="path5200" - sodipodi:nodetypes="csccccccccccccccccsccsssc" - style="color:#000000;fill:url(#linearGradient5220);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient5222);stroke-width:0.68507993;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <path - inkscape:connector-curvature="0" - d="M 18.846598,24 8.028422,24 c 0,2.76 2.423271,5 5.409088,5 2.985817,0 5.409088,-2.24 5.409088,-5 z" - id="path5202" - style="opacity:0.3;fill:url(#linearGradient5224);fill-opacity:1;fill-rule:evenodd;stroke:none" /> - <path - d="m 13.40625,17.625 c -0.218712,0.0043 -0.466555,0.03416 -0.6875,0.0625 -0.93254,0.119629 -1.775868,0.460272 -2.53125,0.9375 0.173643,0.634817 0.42464,1.158079 0.71875,1.625 0.125954,-1.319354 1.241853,-2.34375 2.59375,-2.34375 1.436081,0 2.59375,1.157668 2.59375,2.59375 0,1.436083 -1.157669,2.59375 -2.59375,2.59375 -0.07717,0 -0.14697,-0.02119 -0.21875,-0.03125 1.059311,1.270254 2.021943,2.944267 2.28125,6.09375 2.266237,-0.909044 3.875,-2.925566 3.875,-5.59375 -0.08555,-2.601924 -1.541462,-4.611423 -4,-5.625 -0.680148,-0.225329 -1.363612,-0.325754 -2.03125,-0.3125 z M 15.375,34.6875 c -0.279435,2.585586 -0.854558,5.742004 -1.8125,9.6875 l 1.15625,0 0.65625,-1.3125 0,-8.375 z" - id="path5204" - inkscape:original="M 13.40625 17.53125 C 13.179953 17.535742 12.940048 17.565361 12.71875 17.59375 C 11.746507 17.718472 10.844502 18.056009 10.0625 18.5625 C 10.273788 19.382459 10.603512 20.028723 11 20.59375 C 10.998818 20.562191 11 20.531846 11 20.5 C 11 19.119998 12.119999 18 13.5 18 C 14.880001 18 16 19.119998 16 20.5 C 16 21.880003 14.880001 23 13.5 23 C 13.338115 23 13.184591 22.966937 13.03125 22.9375 C 14.159156 24.243071 15.219875 25.922289 15.46875 29.3125 C 17.839227 28.416828 19.53125 26.324417 19.53125 23.5625 C 19.444481 20.923505 17.958879 18.870351 15.46875 17.84375 C 14.777284 17.614671 14.085142 17.517773 13.40625 17.53125 z M 15.46875 31.96875 C 15.356466 34.978468 14.778907 38.970391 13.4375 44.46875 L 14.78125 44.46875 L 15.46875 43.125 L 15.46875 31.96875 z " - inkscape:radius="-0.10364762" - sodipodi:type="inkscape:offset" - style="opacity:0.6;fill:url(#linearGradient5226);fill-opacity:1;fill-rule:evenodd;stroke:none" /> - <rect - height="0.98128641" - id="rect5206" - style="color:#000000;fill:url(#linearGradient5228);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.79014987px;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - transform="matrix(0,1,-1,0,0,0)" - width="16.311773" - x="29" - y="-14.84375" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-0.81670916" - inkscape:original="M 13.4375 16.5 C 9.5186162 16.499999 6.34375 19.657775 6.34375 23.5625 C 6.3437502 26.380698 7.9483759 28.863095 10.34375 30 L 10.34375 31.5 L 11.75 32.90625 L 10.25 34.40625 L 10.25 35.40625 L 12.34375 36.5 L 12.34375 37.5 L 10.34375 38.5 L 10.34375 39.5 L 11.65625 40.8125 L 10.53125 41.96875 L 10.90625 43.4375 L 12.75 45.3125 L 14.96875 45.3125 L 16.34375 44 L 16.34375 30 C 18.716179 28.854566 20.34375 26.301484 20.34375 23.5 C 20.34375 19.595276 17.356384 16.5 13.4375 16.5 z M 13.34375 18.5 C 14.44775 18.5 15.34375 19.396 15.34375 20.5 C 15.34375 21.604 14.44775 22.5 13.34375 22.5 C 12.23975 22.5 11.34375 21.604 11.34375 20.5 C 11.34375 19.396 12.23975 18.5 13.34375 18.5 z " - xlink:href="#path6767" - style="color:#000000;fill:none;stroke:url(#linearGradient5230);stroke-width:0.68507993;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="path5208" - inkscape:href="#path6767" - d="m 13.4375,17.3125 c -3.4801559,-1e-6 -6.28125,2.787977 -6.28125,6.25 2e-7,2.508186 1.4242699,4.687474 3.53125,5.6875 A 0.81679083,0.81679083 0 0 1 11.15625,30 l 0,1.1875 1.15625,1.15625 a 0.81679083,0.81679083 0 0 1 0,1.125 l -1.25,1.25 0,0.1875 1.65625,0.875 A 0.81679083,0.81679083 0 0 1 13.15625,36.5 l 0,1 a 0.81679083,0.81679083 0 0 1 -0.4375,0.71875 L 11.15625,39 l 0,0.1875 1.0625,1.0625 A 0.81679083,0.81679083 0 0 1 12.25,41.375 L 11.4375,42.21875 11.625,43 l 1.46875,1.5 1.53125,0 0.90625,-0.84375 0,-13.65625 A 0.81679083,0.81679083 0 0 1 16,29.25 c 2.076228,-1.002425 3.53125,-3.264837 3.53125,-5.75 0,-3.488167 -2.60491,-6.1875 -6.09375,-6.1875 z m -0.09375,0.375 c 1.545891,0 2.8125,1.266609 2.8125,2.8125 0,1.545891 -1.266609,2.8125 -2.8125,2.8125 -1.545891,0 -2.8125,-1.266609 -2.8125,-2.8125 0,-1.545891 1.266609,-2.8125 2.8125,-2.8125 z" /> - </g> - <rect - ry="0" - y="68.0625" - x="252.0625" - height="47.814232" - width="47.81321" - id="rect5210" - style="color:#000000;fill:none;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <path - inkscape:export-ydpi="90" - inkscape:export-xdpi="90" - inkscape:export-filename="/data/projects/gnome-keyring/gcr/icons/32x32.png" - d="m 12.0625,2.0625 a 0.90625,0.5625 0 1 1 -1.8125,0 0.90625,0.5625 0 1 1 1.8125,0 z" - id="path5232" - sodipodi:cx="11.15625" - sodipodi:cy="2.0625" - sodipodi:rx="0.90625" - sodipodi:ry="0.5625" - sodipodi:type="arc" - style="fill:url(#radialGradient5256);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - transform="matrix(0.5532396,-0.54421924,0.87679765,0.89133046,265.34092,149.00568)" /> - <g - inkscape:export-ydpi="90" - inkscape:export-xdpi="90" - inkscape:export-filename="/data/projects/gnome-keyring/gcr/icons/32x32.png" - id="g5242" - transform="matrix(9.4955145e-4,-0.89007416,0.89007416,9.4955145e-4,256.00153,164.01742)"> - <path - inkscape:connector-curvature="0" - d="m 13.4375,16.5 c -3.9188838,-1e-6 -7.09375,3.157775 -7.09375,7.0625 2e-7,2.818198 1.6046259,5.300595 4,6.4375 l 0,1.5 1.5,1.5 -1.5,1.5 0,1 2,1 0,1 -2,1 0,1 1.5,1.5 -1.5,1.5 0,1 2.5,2 2.5,0 1,-1.5 0,-14 c 2.372429,-1.145434 4,-3.698516 4,-6.5 0,-3.904724 -2.987366,-7 -6.90625,-7 z m -0.09375,2 c 1.104,0 2,0.896 2,2 0,1.104 -0.896,2 -2,2 -1.104,0 -2,-0.896 -2,-2 0,-1.104 0.896,-2 2,-2 z" - id="path5244" - sodipodi:nodetypes="csccccccccccccccccsccsssc" - style="color:#000000;fill:url(#linearGradient5266);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient5268);stroke-width:1.1235013;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <path - inkscape:connector-curvature="0" - d="M 18.846598,24 8.028422,24 c 0,2.76 2.423271,5 5.409088,5 2.985817,0 5.409088,-2.24 5.409088,-5 z" - id="path5246" - style="opacity:0.3;fill:url(#linearGradient5270);fill-opacity:1;fill-rule:evenodd;stroke:none" /> - <path - d="m 14.3125,17.78125 c 1.186974,0.442749 2.15625,1.386496 2.15625,2.71875 0,1.70953 -1.41547,3.125 -3.125,3.125 -1.70953,0 -3.125,-1.41547 -3.125,-3.125 0,-1.246778 0.868438,-2.127736 1.9375,-2.625 -2.6767585,0.591658 -4.6875,2.839731 -4.6875,5.6875 2e-7,2.393384 1.3435667,4.488163 3.34375,5.4375 a 1.1192611,1.1192611 0 0 1 0.65625,1 l 0,1.0625 1.15625,1.15625 a 1.1192611,1.1192611 0 0 1 0,1.5625 l -1.0625,1.0625 1.28125,0.65625 a 1.1192611,1.1192611 0 0 1 0.625,1 l 0,1 a 1.1192611,1.1192611 0 0 1 -0.625,1 l -1.28125,0.65625 1.0625,1.0625 a 1.1192611,1.1192611 0 0 1 0,1.5625 l -1.15625,1.15625 0,0.03125 1.75,1.40625 1.53125,0 0.46875,-0.71875 0,-13.65625 a 1.1192611,1.1192611 0 0 1 0.625,-1 c 1.966541,-0.949467 3.375,-3.131976 3.375,-5.5 0,-3.019151 -2.052931,-5.297441 -4.90625,-5.71875 z" - id="path5248" - inkscape:href="#path1884" - inkscape:original="M 13.4375 16.5 C 9.5186162 16.499999 6.34375 19.657775 6.34375 23.5625 C 6.3437502 26.380698 7.9483759 28.863095 10.34375 30 L 10.34375 31.5 L 11.84375 33 L 10.34375 34.5 L 10.34375 35.5 L 12.34375 36.5 L 12.34375 37.5 L 10.34375 38.5 L 10.34375 39.5 L 11.84375 41 L 10.34375 42.5 L 10.34375 43.5 L 12.84375 45.5 L 15.34375 45.5 L 16.34375 44 L 16.34375 30 C 18.716179 28.854566 20.34375 26.301484 20.34375 23.5 C 20.34375 19.595276 17.356384 16.5 13.4375 16.5 z M 13.34375 18.5 C 14.44775 18.5 15.34375 19.396 15.34375 20.5 C 15.34375 21.604 14.44775 22.5 13.34375 22.5 C 12.23975 22.5 11.34375 21.604 11.34375 20.5 C 11.34375 19.396 12.23975 18.5 13.34375 18.5 z " - inkscape:radius="-1.1191492" - sodipodi:type="inkscape:offset" - style="fill:none;stroke:#ffffff;stroke-width:1.12350094;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" - xlink:href="#path1884" /> - <path - d="m 13.40625,17.625 c -0.218712,0.0043 -0.466555,0.03416 -0.6875,0.0625 -0.93254,0.119629 -1.775868,0.460272 -2.53125,0.9375 0.173643,0.634817 0.42464,1.158079 0.71875,1.625 0.125954,-1.319354 1.241853,-2.34375 2.59375,-2.34375 1.436081,0 2.59375,1.157668 2.59375,2.59375 0,1.436083 -1.157669,2.59375 -2.59375,2.59375 -0.07717,0 -0.14697,-0.02119 -0.21875,-0.03125 1.059311,1.270254 2.021943,2.944267 2.28125,6.09375 2.266237,-0.909044 3.875,-2.925566 3.875,-5.59375 -0.08555,-2.601924 -1.541462,-4.611423 -4,-5.625 -0.680148,-0.225329 -1.363612,-0.325754 -2.03125,-0.3125 z M 15.375,34.6875 c -0.279435,2.585586 -0.854558,5.742004 -1.8125,9.6875 l 1.15625,0 0.65625,-1.3125 0,-8.375 z" - id="path5250" - inkscape:original="M 13.40625 17.53125 C 13.179953 17.535742 12.940048 17.565361 12.71875 17.59375 C 11.746507 17.718472 10.844502 18.056009 10.0625 18.5625 C 10.273788 19.382459 10.603512 20.028723 11 20.59375 C 10.998818 20.562191 11 20.531846 11 20.5 C 11 19.119998 12.119999 18 13.5 18 C 14.880001 18 16 19.119998 16 20.5 C 16 21.880003 14.880001 23 13.5 23 C 13.338115 23 13.184591 22.966937 13.03125 22.9375 C 14.159156 24.243071 15.219875 25.922289 15.46875 29.3125 C 17.839227 28.416828 19.53125 26.324417 19.53125 23.5625 C 19.444481 20.923505 17.958879 18.870351 15.46875 17.84375 C 14.777284 17.614671 14.085142 17.517773 13.40625 17.53125 z M 15.46875 31.96875 C 15.356466 34.978468 14.778907 38.970391 13.4375 44.46875 L 14.78125 44.46875 L 15.46875 43.125 L 15.46875 31.96875 z " - inkscape:radius="-0.10364762" - sodipodi:type="inkscape:offset" - style="opacity:0.6;fill:url(#linearGradient5272);fill-opacity:1;fill-rule:evenodd;stroke:none" /> - <rect - height="0.98128641" - id="rect5252" - style="opacity:0.61538463;color:#000000;fill:none;stroke:url(#linearGradient5274);stroke-width:1.1235013px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - transform="matrix(0,1,-1,0,0,0)" - width="16.311773" - x="29" - y="-14.84375" /> - </g> - <rect - inkscape:export-ydpi="90" - inkscape:export-xdpi="90" - inkscape:export-filename="/data/projects/gnome-keyring/gcr/icons/32x32.png" - ry="0" - y="135.0625" - x="268.05255" - height="31.876154" - width="31.875473" - id="rect5254" - style="color:#000000;fill:none;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <g - inkscape:export-ydpi="90" - inkscape:export-xdpi="90" - inkscape:export-filename="/data/projects/gnome-keyring/gcr/icons/24x24.png" - style="display:inline;enable-background:new" - id="g5288" - transform="matrix(0.7179987,-0.69604444,0.69604444,0.7179987,276.63641,199.31637)"> - <path - inkscape:connector-curvature="0" - d="m 5.5,0.5 c -1.2798634,3e-8 -2.5554427,0.49294272 -3.53125,1.46875 -1.95161458,1.9516146 -1.95161484,5.1108852 0,7.0625 1.4457774,1.445777 3.5519739,1.790068 5.34375,1.09375 L 8,11 l 1.5,-0.5 0,2 2,0 0,1.5 0.5,0.5 c 0,0 3,0 3,0 l 0.5,-0.5 0,-1.5 -5.375,-5.1875 C 10.821318,5.5207238 10.477027,3.4145274 9.03125,1.96875 8.0554428,0.9929426 6.7798634,0.49999997 5.5,0.5 z m -1,3 c 0.2559728,0 0.5235884,0.086088 0.71875,0.28125 0.3903234,0.3903232 0.3903232,1.0471768 0,1.4375 -0.3903229,0.390323 -1.0471768,0.3903232 -1.4375,0 -0.3903232,-0.3903233 -0.3903232,-1.0471768 0,-1.4375 C 3.9764116,3.5860884 4.2440272,3.5 4.5,3.5 z" - id="path5290" - style="color:#000000;fill:url(#linearGradient5316);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient5318);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <path - inkscape:connector-curvature="0" - d="M 9.543012,3.5767984 3.5767984,9.543012 C 5.2474506,10.334846 7.2996521,10.062799 8.6812256,8.6812256 10.062799,7.2996522 10.334847,5.2474503 9.543012,3.5767984 z" - id="path5292" - style="opacity:0.13574662;fill:url(#linearGradient5320);fill-opacity:1;fill-rule:evenodd;stroke:none" /> - <path - d="M 8.5,6 C 8.5,6.8284271 7.8284271,7.5 7,7.5 6.1715729,7.5 5.5,6.8284271 5.5,6 5.5,5.1715729 6.1715729,4.5 7,4.5 7.8284271,4.5 8.5,5.1715729 8.5,6 z" - id="path5294" - sodipodi:cx="7" - sodipodi:cy="6" - sodipodi:rx="1.5" - sodipodi:ry="1.5" - sodipodi:type="arc" - style="fill:none;stroke:url(#linearGradient5322);stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" - transform="matrix(0.942809,0.942809,-0.942809,0.942809,3.5574935,-7.7562147)" /> - <path - d="m 5.5,1.53125 c -1.0150336,0 -2.0316705,0.3754205 -2.8125,1.15625 -1.558081,1.558081 -1.5580812,4.0669188 0,5.625 1.1495193,1.149519 2.8195738,1.3996406 4.25,0.84375 A 1.0314988,1.0314988 0 0 1 8.125,9.5 L 8.375,9.8125 9.1875,9.53125 A 1.0314988,1.0314988 0 0 1 10.53125,10.5 l 0,0.96875 0.96875,0 A 1.0314988,1.0314988 0 0 1 12.53125,12.5 l 0,0.96875 1.9375,0 0,-0.53125 -5.0625,-4.875 a 1.0314988,1.0314988 0 0 1 -0.25,-1.125 C 9.7121406,5.5070736 9.462019,3.8370193 8.3125,2.6875 7.5316707,1.9066705 6.5150336,1.53125 5.5,1.53125 z" - id="path5296" - inkscape:original="M 5.5 0.5 C 4.2201366 0.50000003 2.9445573 0.99294272 1.96875 1.96875 C 0.017135421 3.9203646 0.017135161 7.0796352 1.96875 9.03125 C 3.4145274 10.477027 5.5207239 10.821318 7.3125 10.125 L 8 11 L 9.5 10.5 L 9.5 12.5 L 11.5 12.5 L 11.5 14 L 12 14.5 C 12 14.5 15 14.5 15 14.5 L 15.5 14 L 15.5 12.5 L 10.125 7.3125 C 10.821318 5.5207238 10.477027 3.4145274 9.03125 1.96875 C 8.0554428 0.9929426 6.7798634 0.49999997 5.5 0.5 z " - inkscape:radius="-1.0313957" - sodipodi:type="inkscape:offset" - style="opacity:0.42986426;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" /> - <path - inkscape:connector-curvature="0" - d="m 14.46875,13.46875 0,-0.53125 -5.0625,-4.875 C 9.1016694,7.7733588 9.0027957,7.3284268 9.15625,6.9375 9.7121406,5.5070736 9.462019,3.8370193 8.3125,2.6875 7.5316707,1.9066705 6.5150336,1.53125 5.5,1.53125 c -1.0150336,0 -2.0316705,0.3754205 -2.8125,1.15625 -1.558081,1.558081 -1.5580812,4.0669188 0,5.625" - id="path5298" - sodipodi:nodetypes="cccsscsc" - style="fill:none;stroke:url(#linearGradient5324);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0.69999992" /> - <path - inkscape:connector-curvature="0" - d="M 13.5,13 9.5,9" - id="path5300" - sodipodi:nodetypes="cc" - style="fill:none;stroke:url(#linearGradient5326);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" /> - </g> - <rect - inkscape:export-ydpi="90" - inkscape:export-xdpi="90" - inkscape:export-filename="/data/projects/gnome-keyring/gcr/icons/24x24.png" - y="186.0625" - x="276.05255" - height="23.874947" - width="23.874947" - id="rect5302" - style="color:#000000;fill:none;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <g - inkscape:export-ydpi="90" - inkscape:export-xdpi="90" - inkscape:export-filename="/data/projects/seahorse/16x16.png" - id="g5406" - transform="matrix(0.00307324,0.73755651,0.73755651,-0.00307324,299.50757,227.71465)"> - <path - inkscape:connector-curvature="0" - d="M -0.5017742,6.4584078 C -0.37175202,4.4522829 -0.8448083,2.5 -3.5060582,2.5 -6.2660581,2.5 -6.6064795,4.8828745 -6.625,6.3689418 l -1.8916614,1.1881832 -0.01828,2.1039435 3.0401445,2.3848735 -0.0052,2.529476 L -4.5,16 l -1,1.5 0,1 2,2 0.9999989,0 L -1.5,19.5 -1.51732,12.045942 1.4161394,9.5495158 1.4878836,7.4939418 z M -2.7989514,5.3726214 c 0.1810001,0.1810001 0.3093592,0.4311066 0.3093592,0.7071068 2e-7,0.5520005 -0.4644656,1.016466 -1.016466,1.016466 -0.552,10e-8 -1.016466,-0.4644656 -1.016466,-1.016466 0,-0.5520004 0.4644656,-1.016466 1.016466,-1.016466 0.2760002,0 0.5261067,0.1283591 0.7071068,0.3093592 z" - id="path5408" - sodipodi:nodetypes="csccccccccccccccccssssc" - style="color:#000000;fill:url(#linearGradient5432);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient5434);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - <path - inkscape:connector-curvature="0" - d="m 0.71269221,8.9174565 -8.43750041,0 c 0.6214183,1.7412405 2.2649102,3.0000005 4.2187502,3.0000005 1.9538399,0 3.5973328,-1.258759 4.21875021,-3.0000005 z" - id="path5410" - style="opacity:0.06334845;fill:url(#linearGradient5436);fill-opacity:1;fill-rule:evenodd;stroke:none" /> - <path - d="m -3.5,3.53125 c -2.2081443,0 -3.96875,1.7606055 -3.96875,3.96875 2e-7,1.6320467 0.9610544,2.971218 2.375,3.59375 a 1.0200495,1.0200495 0 0 1 0.625,0.9375 l 0,2.21875 0.8125,1.15625 a 1.0200495,1.0200495 0 0 1 0,1.15625 l -0.8125,1.21875 0,0.3125 1.375,1.375 0.1875,0 0.375,-0.375 -0.03125,-7.0625 a 1.0200495,1.0200495 0 0 1 0.625,-0.9375 C -0.51947782,10.469423 0.46874976,9.1216542 0.46875,7.5 0.46875008,6.3977756 0.03620106,5.411201 -0.6875,4.6875 -1.411201,3.9637989 -2.3977756,3.53125 -3.5,3.53125 z" - id="path5412" - inkscape:original="M -3.5 2.5 C -6.2599999 2.5 -8.5 4.7399998 -8.5 7.5 C -8.4999997 9.5446378 -7.2593482 11.256644 -5.5 12.03125 L -5.5 14.5625 L -4.5 16 L -5.5 17.5 L -5.5 18.5 C -5.5 18.5 -3.5 20.5 -3.5 20.5 L -2.5 20.5 L -1.5 19.5 L -1.53125 12.03125 C 0.22809828 11.256644 1.4999997 9.5446378 1.5 7.5 C 1.5000001 6.12 0.93625013 4.8737501 0.03125 3.96875 C -0.87375013 3.0637498 -2.1200001 2.5 -3.5 2.5 z " - inkscape:radius="-1.0199475" - sodipodi:type="inkscape:offset" - style="opacity:0.52036252;fill:none;stroke:url(#linearGradient5438);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" /> - <path - d="M 8.5,6 C 8.5,6.8284271 7.8284271,7.5 7,7.5 6.1715729,7.5 5.5,6.8284271 5.5,6 5.5,5.1715729 6.1715729,4.5 7,4.5 7.8284271,4.5 8.5,5.1715729 8.5,6 z" - id="path5414" - sodipodi:cx="7" - sodipodi:cy="6" - sodipodi:rx="1.5" - sodipodi:ry="1.5" - sodipodi:type="arc" - style="fill:none;stroke:url(#linearGradient5440);stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" - transform="matrix(0,1.3333333,-1.3333333,0,4.493942,-3.3285949)" /> - <path - inkscape:connector-curvature="0" - d="m -3.1525046,18.37868 0,-5.656855" - id="path5416" - sodipodi:nodetypes="cc" - style="fill:none;stroke:url(#linearGradient5442);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" /> - </g> - <g - inkscape:export-ydpi="90" - inkscape:export-xdpi="90" - inkscape:export-filename="/data/projects/seahorse/16x16.png" - style="display:inline;enable-background:new" - id="g5418" - transform="matrix(0.52956921,-0.51337657,0.51337657,0.52956921,299.23562,229.35209)"> - <path - inkscape:connector-curvature="0" - d="m 5.5,0.5 c -1.2798634,3e-8 -2.5554427,0.49294272 -3.53125,1.46875 -1.95161458,1.9516146 -1.95161484,5.1108852 0,7.0625 1.4457774,1.445777 3.5519739,1.790068 5.34375,1.09375 L 8,11 l 1.5,-0.5 0,2 2,0 0,1.5 0.5,0.5 c 0,0 3,0 3,0 l 0.5,-0.5 0,-1.5 -5.375,-5.1875 C 10.821318,5.5207238 10.477027,3.4145274 9.03125,1.96875 8.0554428,0.9929426 6.7798634,0.49999997 5.5,0.5 z m -1,3 c 0.2559728,0 0.5235884,0.086088 0.71875,0.28125 0.3903234,0.3903232 0.3903232,1.0471768 0,1.4375 -0.3903229,0.390323 -1.0471768,0.3903232 -1.4375,0 -0.3903232,-0.3903233 -0.3903232,-1.0471768 0,-1.4375 C 3.9764116,3.5860884 4.2440272,3.5 4.5,3.5 z" - id="path5420" - style="color:#000000;fill:url(#linearGradient5444);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient5446);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <path - inkscape:connector-curvature="0" - d="M 9.543012,3.5767984 3.5767984,9.543012 C 5.2474506,10.334846 7.2996521,10.062799 8.6812256,8.6812256 10.062799,7.2996522 10.334847,5.2474503 9.543012,3.5767984 z" - id="path5422" - style="opacity:0.13574662;fill:url(#linearGradient5448);fill-opacity:1;fill-rule:evenodd;stroke:none" /> - <path - d="M 8.5,6 C 8.5,6.8284271 7.8284271,7.5 7,7.5 6.1715729,7.5 5.5,6.8284271 5.5,6 5.5,5.1715729 6.1715729,4.5 7,4.5 7.8284271,4.5 8.5,5.1715729 8.5,6 z" - id="path5424" - sodipodi:cx="7" - sodipodi:cy="6" - sodipodi:rx="1.5" - sodipodi:ry="1.5" - sodipodi:type="arc" - style="fill:none;stroke:url(#linearGradient5450);stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" - transform="matrix(0.942809,0.942809,-0.942809,0.942809,3.5574935,-7.7562147)" /> - <path - d="m 5.5,1.53125 c -1.0150336,0 -2.0316705,0.3754205 -2.8125,1.15625 -1.558081,1.558081 -1.5580812,4.0669188 0,5.625 1.1495193,1.149519 2.8195738,1.3996406 4.25,0.84375 A 1.0314988,1.0314988 0 0 1 8.125,9.5 L 8.375,9.8125 9.1875,9.53125 A 1.0314988,1.0314988 0 0 1 10.53125,10.5 l 0,0.96875 0.96875,0 A 1.0314988,1.0314988 0 0 1 12.53125,12.5 l 0,0.96875 1.9375,0 0,-0.53125 -5.0625,-4.875 a 1.0314988,1.0314988 0 0 1 -0.25,-1.125 C 9.7121406,5.5070736 9.462019,3.8370193 8.3125,2.6875 7.5316707,1.9066705 6.5150336,1.53125 5.5,1.53125 z" - id="path5426" - inkscape:original="M 5.5 0.5 C 4.2201366 0.50000003 2.9445573 0.99294272 1.96875 1.96875 C 0.017135421 3.9203646 0.017135161 7.0796352 1.96875 9.03125 C 3.4145274 10.477027 5.5207239 10.821318 7.3125 10.125 L 8 11 L 9.5 10.5 L 9.5 12.5 L 11.5 12.5 L 11.5 14 L 12 14.5 C 12 14.5 15 14.5 15 14.5 L 15.5 14 L 15.5 12.5 L 10.125 7.3125 C 10.821318 5.5207238 10.477027 3.4145274 9.03125 1.96875 C 8.0554428 0.9929426 6.7798634 0.49999997 5.5 0.5 z " - inkscape:radius="-1.0313957" - sodipodi:type="inkscape:offset" - style="opacity:0.42986426;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" /> - <path - inkscape:connector-curvature="0" - d="m 14.46875,13.46875 0,-0.53125 -5.0625,-4.875 C 9.1016694,7.7733588 9.0027957,7.3284268 9.15625,6.9375 9.7121406,5.5070736 9.462019,3.8370193 8.3125,2.6875 7.5316707,1.9066705 6.5150336,1.53125 5.5,1.53125 c -1.0150336,0 -2.0316705,0.3754205 -2.8125,1.15625 -1.558081,1.558081 -1.5580812,4.0669188 0,5.625" - id="path5428" - sodipodi:nodetypes="cccsscsc" - style="fill:none;stroke:url(#linearGradient5452);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0.69999992" /> - <path - inkscape:connector-curvature="0" - d="M 13.5,13 9.5,9" - id="path5430" - sodipodi:nodetypes="cc" - style="fill:none;stroke:url(#linearGradient5454);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" /> - </g> - <rect - inkscape:export-ydpi="90" - inkscape:export-xdpi="90" - inkscape:export-filename="/data/projects/gnome-keyring/gcr/icons/16.png" - y="219.0625" - x="284.0625" - height="15.876632" - width="15.876632" - id="rect5456" - style="color:#000000;fill:none;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <g - transform="matrix(0.52956921,-0.51337657,0.51337657,0.52956921,283.23562,227.35209)" - id="g5470" - style="display:inline;enable-background:new" - inkscape:export-filename="/data/projects/gnome-keyring/gcr/icons/16.png" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90"> - <path - style="color:#000000;fill:url(#linearGradient5496);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient5498);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="path5472" - d="m 5.5,0.5 c -1.2798634,3e-8 -2.5554427,0.49294272 -3.53125,1.46875 -1.95161458,1.9516146 -1.95161484,5.1108852 0,7.0625 1.4457774,1.445777 3.5519739,1.790068 5.34375,1.09375 L 8,11 l 1.5,-0.5 0,2 2,0 0,1.5 0.5,0.5 c 0,0 3,0 3,0 l 0.5,-0.5 0,-1.5 -5.375,-5.1875 C 10.821318,5.5207238 10.477027,3.4145274 9.03125,1.96875 8.0554428,0.9929426 6.7798634,0.49999997 5.5,0.5 z m -1,3 c 0.2559728,0 0.5235884,0.086088 0.71875,0.28125 0.3903234,0.3903232 0.3903232,1.0471768 0,1.4375 -0.3903229,0.390323 -1.0471768,0.3903232 -1.4375,0 -0.3903232,-0.3903233 -0.3903232,-1.0471768 0,-1.4375 C 3.9764116,3.5860884 4.2440272,3.5 4.5,3.5 z" - inkscape:connector-curvature="0" /> - <path - style="opacity:0.13574662;fill:url(#linearGradient5500);fill-opacity:1;fill-rule:evenodd;stroke:none" - id="path5474" - d="M 9.543012,3.5767984 3.5767984,9.543012 C 5.2474506,10.334846 7.2996521,10.062799 8.6812256,8.6812256 10.062799,7.2996522 10.334847,5.2474503 9.543012,3.5767984 z" - inkscape:connector-curvature="0" /> - <path - transform="matrix(0.942809,0.942809,-0.942809,0.942809,3.5574935,-7.7562147)" - style="fill:none;stroke:url(#linearGradient5502);stroke-width:0.75;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" - sodipodi:type="arc" - sodipodi:ry="1.5" - sodipodi:rx="1.5" - sodipodi:cy="6" - sodipodi:cx="7" - id="path5476" - d="M 8.5,6 C 8.5,6.8284271 7.8284271,7.5 7,7.5 6.1715729,7.5 5.5,6.8284271 5.5,6 5.5,5.1715729 6.1715729,4.5 7,4.5 7.8284271,4.5 8.5,5.1715729 8.5,6 z" /> - <path - style="opacity:0.42986426;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.69999992" - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0313957" - inkscape:original="M 5.5 0.5 C 4.2201366 0.50000003 2.9445573 0.99294272 1.96875 1.96875 C 0.017135421 3.9203646 0.017135161 7.0796352 1.96875 9.03125 C 3.4145274 10.477027 5.5207239 10.821318 7.3125 10.125 L 8 11 L 9.5 10.5 L 9.5 12.5 L 11.5 12.5 L 11.5 14 L 12 14.5 C 12 14.5 15 14.5 15 14.5 L 15.5 14 L 15.5 12.5 L 10.125 7.3125 C 10.821318 5.5207238 10.477027 3.4145274 9.03125 1.96875 C 8.0554428 0.9929426 6.7798634 0.49999997 5.5 0.5 z " - id="path5478" - d="m 5.5,1.53125 c -1.0150336,0 -2.0316705,0.3754205 -2.8125,1.15625 -1.558081,1.558081 -1.5580812,4.0669188 0,5.625 1.1495193,1.149519 2.8195738,1.3996406 4.25,0.84375 A 1.0314988,1.0314988 0 0 1 8.125,9.5 L 8.375,9.8125 9.1875,9.53125 A 1.0314988,1.0314988 0 0 1 10.53125,10.5 l 0,0.96875 0.96875,0 A 1.0314988,1.0314988 0 0 1 12.53125,12.5 l 0,0.96875 1.9375,0 0,-0.53125 -5.0625,-4.875 a 1.0314988,1.0314988 0 0 1 -0.25,-1.125 C 9.7121406,5.5070736 9.462019,3.8370193 8.3125,2.6875 7.5316707,1.9066705 6.5150336,1.53125 5.5,1.53125 z" /> - <path - style="fill:none;stroke:url(#linearGradient5504);stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0.69999992" - sodipodi:nodetypes="cccsscsc" - id="path5480" - d="m 14.46875,13.46875 0,-0.53125 -5.0625,-4.875 C 9.1016694,7.7733588 9.0027957,7.3284268 9.15625,6.9375 9.7121406,5.5070736 9.462019,3.8370193 8.3125,2.6875 7.5316707,1.9066705 6.5150336,1.53125 5.5,1.53125 c -1.0150336,0 -2.0316705,0.3754205 -2.8125,1.15625 -1.558081,1.558081 -1.5580812,4.0669188 0,5.625" - inkscape:connector-curvature="0" /> - <path - style="fill:none;stroke:url(#linearGradient5506);stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" - sodipodi:nodetypes="cc" - id="path5482" - d="M 13.5,13 9.5,9" - inkscape:connector-curvature="0" /> - </g> - </g> - <g - inkscape:groupmode="layer" - id="layer5" - inkscape:label="hires" - style="display:inline"> - <g - id="g8198" - transform="matrix(5.0928038,0,0,2.2388776,20.301687,129.4805)" - style="opacity:0.4" /> - <g - id="g8230" - inkscape:label="base" - style="display:inline" - transform="matrix(4.8890868,0,0,4.8890868,322.06038,251.81989)" /> - <path - sodipodi:type="inkscape:offset" - inkscape:radius="-1.0153296" - inkscape:original="M 711.96875 227 C 709.68001 227.00001 707.67461 227.86289 706.5 229.1875 L 706.5 231.625 C 706.5 232.11623 706.8838 232.5 707.375 232.5 L 716.625 232.5 C 717.11622 232.50001 717.5 232.11622 717.5 231.625 L 717.5 229.25 C 716.33242 227.89578 714.28785 227 711.96875 227 z " - style="opacity:0.35;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="path5171-2" - d="m 711.96875,228 c -1.90789,1e-5 -3.49694,0.75848 -4.46875,1.71875 l 0,1.78125 9,0 0,-1.75 c -0.96562,-0.98703 -2.59089,-1.75 -4.53125,-1.75 z" - transform="translate(-7.8685593e-7,2.029528e-6)" /> - </g> - </g> -</svg> diff --git a/gcr/icons/render-icons.py b/gcr/icons/render-icons.py deleted file mode 100755 index d5948569..00000000 --- a/gcr/icons/render-icons.py +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env python - -# Copied from gnome-icon-theme and adjusted lightly. -# -# GNOME icon theme is distributed under the terms of either -# GNU LGPL v.3 or Creative Commons BY-SA 3.0 license. - -import os -import sys -import xml.sax -import subprocess - -INKSCAPE = '/usr/bin/inkscape' -OPTIPNG = '/usr/bin/optipng' -SRC = 'src' -OUT = '.' - -inkscape_process = None - -def optimize_png(png_file): - if os.path.exists(OPTIPNG): - process = subprocess.Popen([OPTIPNG, '-quiet', '-o7', png_file]) - process.wait() - -def wait_for_prompt(process, command=None): - if command is not None: - process.stdin.write(command+'\n') - - # This is kinda ugly ... - # Wait for just a '>', or '\n>' if some other char appearead first - output = process.stdout.read(1) - if output == '>': - return - - output += process.stdout.read(1) - while output != "\n>": - output += process.stdout.read(1) - output = output[1:] - -def start_inkscape(): - process = subprocess.Popen([INKSCAPE, '--shell'], bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE) - wait_for_prompt(process) - return process - -def inkscape_render_rect(icon_file, rect, output_file): - global inkscape_process - if inkscape_process is None: - inkscape_process = start_inkscape() - wait_for_prompt(inkscape_process, '%s -i %s -e %s' % (icon_file, rect, output_file)) - optimize_png(output_file) - -class ContentHandler(xml.sax.ContentHandler): - ROOT = 0 - SVG = 1 - LAYER = 2 - OTHER = 3 - TEXT = 4 - def __init__(self, path, force=False, filter=None): - self.stack = [self.ROOT] - self.inside = [self.ROOT] - self.path = path - self.rects = [] - self.state = self.ROOT - self.chars = "" - self.force = force - self.filter = filter - - def endDocument(self): - pass - - def startElement(self, name, attrs): - if self.inside[-1] == self.ROOT: - if name == "svg": - self.stack.append(self.SVG) - self.inside.append(self.SVG) - return - elif self.inside[-1] == self.SVG: - if (name == "g" and attrs.has_key('inkscape:groupmode') and attrs.has_key('inkscape:label') - and attrs['inkscape:groupmode'] == 'layer' and attrs['inkscape:label'].startswith('baseplate')): - self.stack.append(self.LAYER) - self.inside.append(self.LAYER) - self.context = None - self.icon_name = None - self.rects = [] - return - elif self.inside[-1] == self.LAYER: - if name == "text" and attrs.has_key('inkscape:label') and attrs['inkscape:label'] == 'context': - self.stack.append(self.TEXT) - self.inside.append(self.TEXT) - self.text='context' - self.chars = "" - return - elif name == "text" and attrs.has_key('inkscape:label') and attrs['inkscape:label'] == 'icon-name': - self.stack.append(self.TEXT) - self.inside.append(self.TEXT) - self.text='icon-name' - self.chars = "" - return - elif name == "rect": - self.rects.append(attrs) - - self.stack.append(self.OTHER) - - - def endElement(self, name): - stacked = self.stack.pop() - if self.inside[-1] == stacked: - self.inside.pop() - - if stacked == self.TEXT and self.text is not None: - assert self.text in ['context', 'icon-name'] - if self.text == 'context': - self.context = self.chars - elif self.text == 'icon-name': - self.icon_name = self.chars - self.text = None - elif stacked == self.LAYER: - assert self.icon_name - assert self.context - - if self.filter is not None and not self.icon_name in self.filter: - return - - print '%s %s' % (self.context, self.icon_name) - for rect in self.rects: - width = rect['width'] - height = rect['height'] - id = rect['id'] - - # dir = os.path.join(OUT, "%sx%s" % (width, height), self.context) - dir = os.path.join(OUT, "%sx%s" % (width, height)) - outfile = os.path.join(dir, self.icon_name+'.png') - if not os.path.exists(dir): - os.makedirs(dir) - # Do a time based check! - if self.force or not os.path.exists(outfile): - inkscape_render_rect(self.path, id, outfile) - sys.stdout.write('.') - else: - stat_in = os.stat(self.path) - stat_out = os.stat(outfile) - if stat_in.st_mtime > stat_out.st_mtime: - inkscape_render_rect(self.path, id, outfile) - sys.stdout.write('.') - else: - sys.stdout.write('-') - sys.stdout.flush() - sys.stdout.write('\n') - sys.stdout.flush() - - def characters(self, chars): - self.chars += chars.strip() - -if len(sys.argv) == 1: - if not os.path.exists(OUT): - os.mkdir(OUT) - print 'Rendering from SVGs in %s' % SRC - for file in os.listdir(SRC): - if file[-4:] == '.svg': - file = os.path.join(SRC, file) - handler = ContentHandler(file) - xml.sax.parse(open(file), handler) -else: - file = os.path.join(SRC, sys.argv[1] + '.svg') - if len(sys.argv) > 2: - icons = sys.argv[2:] - else: - icons = None - if os.path.exists(os.path.join(file)): - handler = ContentHandler(file, True, filter=icons) - xml.sax.parse(open(file), handler) - else: - print "Error: No such file %s" % file - sys.exit(1) diff --git a/gcr/icons/src/gcr-smart-card.svg b/gcr/icons/src/gcr-smart-card.svg deleted file mode 100644 index 51a37611..00000000 --- a/gcr/icons/src/gcr-smart-card.svg +++ /dev/null @@ -1,1165 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - -<svg - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:cc="http://creativecommons.org/ns#" - xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" - xmlns:svg="http://www.w3.org/2000/svg" - xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" - xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" - xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - inkscape:export-ydpi="90.000000" - inkscape:export-xdpi="90.000000" - inkscape:export-filename="/home/lapo/firewall.png" - width="400" - height="300" - id="svg11300" - sodipodi:version="0.32" - inkscape:version="0.48.1 r9760" - sodipodi:docname="gcr-smart-card.svg" - inkscape:output_extension="org.inkscape.output.svg.inkscape" - version="1.0" - style="display:inline;enable-background:new"> - <title - id="title4872">Firewall</title> - <sodipodi:namedview - stroke="#ef2929" - fill="#f57900" - id="base" - pagecolor="#474747" - bordercolor="#666666" - borderopacity="0.25490196" - inkscape:pageopacity="0" - inkscape:pageshadow="2" - inkscape:zoom="31.059262" - inkscape:cx="310.4148" - inkscape:cy="75.246655" - inkscape:current-layer="layer4" - showgrid="true" - inkscape:grid-bbox="true" - inkscape:document-units="px" - inkscape:showpageshadow="false" - inkscape:window-width="1278" - inkscape:window-height="866" - inkscape:window-x="1345" - inkscape:window-y="34" - width="400px" - height="300px" - inkscape:snap-nodes="false" - inkscape:snap-bbox="false" - gridtolerance="10000" - inkscape:object-nodes="true" - inkscape:snap-grids="true" - showguides="false" - inkscape:guide-bbox="true" - inkscape:window-maximized="0"> - <inkscape:grid - spacingy="1px" - spacingx="1px" - id="grid5883" - type="xygrid" - enabled="true" - visible="true" - empspacing="4" - snapvisiblegridlinesonly="true" /> - <inkscape:grid - type="xygrid" - id="grid11592" - empspacing="2" - visible="true" - enabled="false" - spacingx="0.5px" - spacingy="0.5px" - color="#ff0000" - opacity="0.1254902" - empcolor="#ff0000" - empopacity="0.25098039" - snapvisiblegridlinesonly="true" /> - <sodipodi:guide - orientation="-0.70710678,0.70710678" - position="309.8125,173.625" - id="guide9630" /> - <sodipodi:guide - orientation="1,0" - position="155.01758,221.5" - id="guide4407" /> - <sodipodi:guide - orientation="1,0" - position="244.125,212.625" - id="guide4409" /> - <sodipodi:guide - orientation="1,0" - position="184.875,211.625" - id="guide4411" /> - <sodipodi:guide - orientation="1,0" - position="213.875,214.25" - id="guide4413" /> - </sodipodi:namedview> - <defs - id="defs3"> - <linearGradient - id="linearGradient6048"> - <stop - style="stop-color:#edd400;stop-opacity:1;" - offset="0" - id="stop6050" /> - <stop - id="stop6052" - offset="0.25" - style="stop-color:#c7b201;stop-opacity:1;" /> - <stop - id="stop6054" - offset="0.5" - style="stop-color:#af9c05;stop-opacity:1;" /> - <stop - style="stop-color:#ffeb3e;stop-opacity:1;" - offset="1" - id="stop6056" /> - </linearGradient> - <linearGradient - id="linearGradient5987"> - <stop - style="stop-color:#c4a000;stop-opacity:1;" - offset="0" - id="stop5989" /> - <stop - style="stop-color:#997e00;stop-opacity:1;" - offset="1" - id="stop5991" /> - </linearGradient> - <linearGradient - id="linearGradient5540"> - <stop - id="stop5542" - offset="0" - style="stop-color:#fc8817;stop-opacity:1;" /> - <stop - id="stop5544" - offset="1" - style="stop-color:#fc8817;stop-opacity:0;" /> - </linearGradient> - <linearGradient - id="linearGradient5532"> - <stop - style="stop-color:#719fcf;stop-opacity:1;" - offset="0" - id="stop5534" /> - <stop - style="stop-color:#3466a4;stop-opacity:1;" - offset="1" - id="stop5536" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath9887"> - <path - d="m 32.1875,0 c -4.917465,0.322114 -6.796581,5.25981 -6.46875,9.125 l 0,211.8125 c 0.365597,5.50865 5.236892,11.01932 12.5,10.46875 l 167.0625,0 c 4.68699,-0.22612 9.31856,-4.12416 9.25,-11.84375 l 0,-193.71875 c 0,-3.758448 -1.21492,-6.263069 -3.96875,-8.96875 L 196.15625,2 C 194.64949,0.576511 193.73508,0 189.5625,0 L 32.1875,0 z" - inkscape:href="#path9521" - id="path9889" - style="fill:none;stroke:#343a3b;stroke-width:0.38129407;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible" - xlink:href="#path9521" - inkscape:original="M 66.4375 95.9375 C 61.520035 96.259614 59.609669 101.19731 59.9375 105.0625 L 59.9375 316.875 C 60.303097 322.38365 65.174392 327.89432 72.4375 327.34375 L 239.53125 327.34375 C 244.21824 327.11763 248.84981 323.21959 248.78125 315.5 L 248.78125 121.78125 C 248.78125 118.0228 247.56633 115.51818 244.8125 112.8125 L 230.375 97.9375 C 228.86824 96.514011 227.95383 95.9375 223.78125 95.9375 L 66.4375 95.9375 z " - inkscape:radius="0" - sodipodi:type="inkscape:offset" /> - </clipPath> - <linearGradient - id="linearGradient9941"> - <stop - id="stop9943" - offset="0" - style="stop-color:#edd400;stop-opacity:1;" /> - <stop - style="stop-color:#bda901;stop-opacity:1;" - offset="0.25" - id="stop9959" /> - <stop - style="stop-color:#a08f05;stop-opacity:1" - offset="0.5" - id="stop9945" /> - <stop - id="stop9947" - offset="1" - style="stop-color:#ffeb3e;stop-opacity:1;" /> - </linearGradient> - <pattern - inkscape:stockid="Sand (bitmap)" - id="sand_bitmap" - height="256" - width="256" - patternUnits="userSpaceOnUse" - patternTransform="matrix(0.1089357,0,0,0.1089357,304.12642,53.923124)"> - <!-- Seamless texture provided by FreeSeamlessTextures.com --> - <!-- License: creative commons attribution --> - <image - xlink:href="data:image/jpeg;base64,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 /p1//9k= " - y="0" - x="0" - id="image9" - height="260" - width="260" /> - </pattern> - <linearGradient - id="linearGradient9326"> - <stop - id="stop9328" - offset="0" - style="stop-color:#555753;stop-opacity:1;" /> - <stop - style="stop-color:#555652;stop-opacity:1" - offset="0.52639353" - id="stop9342" /> - <stop - style="stop-color:#5e605b;stop-opacity:1" - offset="0.62553692" - id="stop9332" /> - <stop - id="stop9330" - offset="1" - style="stop-color:#3e3f3c;stop-opacity:1;" /> - </linearGradient> - <linearGradient - id="linearGradient9326-5"> - <stop - id="stop9328-9" - offset="0" - style="stop-color:#555753;stop-opacity:1;" /> - <stop - style="stop-color:#555652;stop-opacity:1" - offset="0.52639353" - id="stop9342-8" /> - <stop - style="stop-color:#5e605b;stop-opacity:1" - offset="0.62553692" - id="stop9332-4" /> - <stop - id="stop9330-8" - offset="1" - style="stop-color:#3e3f3c;stop-opacity:1;" /> - </linearGradient> - <pattern - inkscape:stockid="Sand (bitmap)" - id="sand_bitmap-1" - height="256" - width="256" - patternUnits="userSpaceOnUse" - patternTransform="matrix(0.1089357,0,0,0.1089357,304.12642,53.923124)"> - <!-- Seamless texture provided by FreeSeamlessTextures.com --> - <!-- License: creative commons attribution --> - <image - xlink:href="data:image/jpeg;base64,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 /p1//9k= " - y="0" - x="0" - id="image9-0" - height="260" - width="260" /> - </pattern> - <linearGradient - id="linearGradient9941-4"> - <stop - id="stop9943-7" - offset="0" - style="stop-color:#edd400;stop-opacity:1;" /> - <stop - style="stop-color:#bda901;stop-opacity:1;" - offset="0.25" - id="stop9959-6" /> - <stop - style="stop-color:#a08f05;stop-opacity:1" - offset="0.5" - id="stop9945-3" /> - <stop - id="stop9947-1" - offset="1" - style="stop-color:#ffeb3e;stop-opacity:1;" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath9887-5"> - <path - d="m 62.15625,35.96875 c -4.917465,0.322114 -6.827831,5.25981 -6.5,9.125 l 0,211.8125 c 0.365597,5.50865 5.236892,11.01932 12.5,10.46875 l 167.09375,0 c 4.68699,-0.22612 9.31856,-4.12416 9.25,-11.84375 l 0,-193.71875 c 0,-3.758448 -1.21492,-6.263069 -3.96875,-8.96875 L 226.125,37.96875 c -1.50676,-1.423489 -2.45242,-2 -6.625,-2 l -157.34375,0 z" - inkscape:href="#path9521-4" - id="path9889-3" - style="fill:none;stroke:#343a3b;stroke-width:0.38129407;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible" - xlink:href="#path9521-4" - inkscape:original="M 62.15625 35.96875 C 57.238785 36.290864 55.328419 41.22856 55.65625 45.09375 L 55.65625 256.90625 C 56.021847 262.4149 60.893142 267.92557 68.15625 267.375 L 235.25 267.375 C 239.93699 267.14888 244.56856 263.25084 244.5 255.53125 L 244.5 61.8125 C 244.5 58.054052 243.28508 55.549431 240.53125 52.84375 L 226.125 37.96875 C 224.61824 36.545261 223.67258 35.96875 219.5 35.96875 L 62.15625 35.96875 z " - inkscape:radius="0" - sodipodi:type="inkscape:offset" /> - </clipPath> - <linearGradient - id="linearGradient9326-2"> - <stop - id="stop9328-5" - offset="0" - style="stop-color:#555753;stop-opacity:1;" /> - <stop - style="stop-color:#555652;stop-opacity:1" - offset="0.52639353" - id="stop9342-4" /> - <stop - style="stop-color:#5e605b;stop-opacity:1" - offset="0.62553692" - id="stop9332-49" /> - <stop - id="stop9330-9" - offset="1" - style="stop-color:#3e3f3c;stop-opacity:1;" /> - </linearGradient> - <pattern - inkscape:stockid="Sand (bitmap)" - id="sand_bitmap-3" - height="256" - width="256" - patternUnits="userSpaceOnUse" - patternTransform="matrix(0.1089357,0,0,0.1089357,304.12642,53.923124)"> - <!-- Seamless texture provided by FreeSeamlessTextures.com --> - <!-- License: creative commons attribution --> - <image - xlink:href="data:image/jpeg;base64,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 /p1//9k= " - y="0" - x="0" - id="image9-6" - height="260" - width="260" /> - </pattern> - <linearGradient - id="linearGradient9903-5"> - <stop - style="stop-color:#bdc5c7;stop-opacity:1" - offset="0" - id="stop9905-0" /> - <stop - style="stop-color:#2e3436;stop-opacity:1" - offset="1" - id="stop9907-2" /> - </linearGradient> - <linearGradient - id="linearGradient9941-43"> - <stop - id="stop9943-5" - offset="0" - style="stop-color:#edd400;stop-opacity:1;" /> - <stop - style="stop-color:#bda901;stop-opacity:1;" - offset="0.25" - id="stop9959-1" /> - <stop - style="stop-color:#a08f05;stop-opacity:1" - offset="0.5" - id="stop9945-7" /> - <stop - id="stop9947-4" - offset="1" - style="stop-color:#ffeb3e;stop-opacity:1;" /> - </linearGradient> - <linearGradient - inkscape:collect="always" - id="linearGradient9677-1"> - <stop - style="stop-color:#ffffff;stop-opacity:1;" - offset="0" - id="stop9679-4" /> - <stop - style="stop-color:#ffffff;stop-opacity:0;" - offset="1" - id="stop9681-69" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath9887-8"> - <path - d="m 62.15625,35.96875 c -4.917465,0.322114 -6.827831,5.25981 -6.5,9.125 l 0,211.8125 c 0.365597,5.50865 5.236892,11.01932 12.5,10.46875 l 167.09375,0 c 4.68699,-0.22612 9.31856,-4.12416 9.25,-11.84375 l 0,-193.71875 c 0,-3.758448 -1.21492,-6.263069 -3.96875,-8.96875 L 226.125,37.96875 c -1.50676,-1.423489 -2.45242,-2 -6.625,-2 l -157.34375,0 z" - inkscape:href="#path9521" - id="path9889-6" - style="fill:none;stroke:#343a3b;stroke-width:0.38129407;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible" - xlink:href="#path9521" - inkscape:original="M 44.84375 57.3125 C 39.3351 57.678097 33.82443 62.549392 34.375 69.8125 L 34.375 236.875 C 34.60112 241.56199 38.49916 246.19356 46.21875 246.125 L 239.9375 246.125 C 243.69595 246.125 246.20057 244.91008 248.90625 242.15625 L 263.78125 227.75 C 265.20474 226.24324 265.78125 225.29758 265.78125 221.125 L 265.78125 63.78125 C 265.45913 58.863785 260.52144 56.984669 256.65625 57.3125 L 44.84375 57.3125 z " - inkscape:radius="0" - sodipodi:type="inkscape:offset" /> - </clipPath> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient9903-5" - id="radialGradient3610" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.02241743,-4.5362601,2.141228,0.00322394,2.865653,1366.4873)" - cx="319.47476" - cy="74.762054" - fx="319.47476" - fy="74.762054" - r="14.737162" /> - <linearGradient - id="linearGradient9326-8"> - <stop - id="stop9328-2" - offset="0" - style="stop-color:#555753;stop-opacity:1;" /> - <stop - style="stop-color:#555652;stop-opacity:1" - offset="0.52639353" - id="stop9342-5" /> - <stop - style="stop-color:#5e605b;stop-opacity:1" - offset="0.62553692" - id="stop9332-3" /> - <stop - id="stop9330-1" - offset="1" - style="stop-color:#3e3f3c;stop-opacity:1;" /> - </linearGradient> - <pattern - inkscape:stockid="Sand (bitmap)" - id="sand_bitmap-2" - height="256" - width="256" - patternUnits="userSpaceOnUse" - patternTransform="matrix(0.1089357,0,0,0.1089357,304.12642,53.923124)"> - <!-- Seamless texture provided by FreeSeamlessTextures.com --> - <!-- License: creative commons attribution --> - <image - xlink:href="data:image/jpeg;base64,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 /p1//9k= " - y="0" - x="0" - id="image9-1" - height="260" - width="260" /> - </pattern> - <linearGradient - id="linearGradient9941-2"> - <stop - id="stop9943-9" - offset="0" - style="stop-color:#edd400;stop-opacity:1;" /> - <stop - style="stop-color:#bda901;stop-opacity:1;" - offset="0.25" - id="stop9959-2" /> - <stop - style="stop-color:#a08f05;stop-opacity:1" - offset="0.5" - id="stop9945-6" /> - <stop - id="stop9947-46" - offset="1" - style="stop-color:#ffeb3e;stop-opacity:1;" /> - </linearGradient> - <clipPath - clipPathUnits="userSpaceOnUse" - id="clipPath9887-4"> - <path - d="m 62.15625,35.96875 c -4.917465,0.322114 -6.827831,5.25981 -6.5,9.125 l 0,211.8125 c 0.365597,5.50865 5.236892,11.01932 12.5,10.46875 l 167.09375,0 c 4.68699,-0.22612 9.31856,-4.12416 9.25,-11.84375 l 0,-193.71875 c 0,-3.758448 -1.21492,-6.263069 -3.96875,-8.96875 L 226.125,37.96875 c -1.50676,-1.423489 -2.45242,-2 -6.625,-2 l -157.34375,0 z" - inkscape:href="#path9521" - id="path9889-0" - style="fill:none;stroke:#343a3b;stroke-width:0.38129407;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible" - xlink:href="#path9521" - inkscape:original="M 62.15625 35.96875 C 57.238785 36.290864 55.328419 41.22856 55.65625 45.09375 L 55.65625 256.90625 C 56.021847 262.4149 60.893142 267.92557 68.15625 267.375 L 235.25 267.375 C 239.93699 267.14888 244.56856 263.25084 244.5 255.53125 L 244.5 61.8125 C 244.5 58.054052 243.28508 55.549431 240.53125 52.84375 L 226.125 37.96875 C 224.61824 36.545261 223.67258 35.96875 219.5 35.96875 L 62.15625 35.96875 z " - inkscape:radius="0" - sodipodi:type="inkscape:offset" /> - </clipPath> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient5532" - id="linearGradient5538" - x1="151.9079" - y1="188.73213" - x2="151.07002" - y2="49.432087" - gradientUnits="userSpaceOnUse" - gradientTransform="translate(3,40)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient9941-43" - id="linearGradient5640" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,-1.9049813,3.5398921,0,97.3544,-37.747404)" - x1="29.374996" - y1="21.741114" - x2="20.004526" - y2="6.7253776" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient9677-1" - id="radialGradient5642" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(1.6935297,-1.6353265,6.1727401,1.8717188,-790.31279,320.79789)" - cx="319.82288" - cy="64.117065" - fx="319.82288" - fy="64.117065" - r="13.808043" /> - <filter - inkscape:collect="always" - id="filter5758"> - <feGaussianBlur - inkscape:collect="always" - stdDeviation="4.6408213" - id="feGaussianBlur5760" /> - </filter> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient5532" - id="linearGradient5840" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.18585006,0,0,0.18717507,293.02852,53.343152)" - x1="151.9079" - y1="188.73213" - x2="151.07002" - y2="49.432087" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient9903-5" - id="radialGradient5842" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.00589609,-1.2059869,0.56317324,8.5710016e-4,35.496775,74.218944)" - cx="319.47476" - cy="74.762054" - fx="319.47476" - fy="74.762054" - r="14.737162" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient9941-43" - id="linearGradient5844" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,-0.50644856,0.93104166,0,60.348652,-299.10369)" - x1="29.374996" - y1="21.741114" - x2="20.004526" - y2="6.7253776" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient9677-1" - id="radialGradient5846" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.4615968,-0.44981091,1.6824726,0.51483267,-182.87988,-200.0395)" - cx="319.82288" - cy="64.117065" - fx="319.82288" - fy="64.117065" - r="13.808043" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient5532" - id="linearGradient5866" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.12671561,0,0,0.12478236,300.6104,129.22895)" - x1="151.9079" - y1="188.73213" - x2="151.07002" - y2="49.432087" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient9903-5" - id="radialGradient5868" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.00461699,-0.8988884,0.44099713,6.3884392e-4,113.24551,-25.407226)" - cx="319.47476" - cy="74.762054" - fx="319.47476" - fy="74.762054" - r="14.737162" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient9941-43" - id="linearGradient5870" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,-0.37748401,0.72905934,0,132.70595,-303.66517)" - x1="29.374996" - y1="21.741114" - x2="20.004526" - y2="6.7253776" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient5532" - id="linearGradient5926" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.09292503,0,0,0.09705373,300.51424,178.5113)" - x1="151.9079" - y1="188.73213" - x2="151.07002" - y2="49.432087" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient5532" - id="linearGradient5965" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.06758181,0,0,0.08318892,301.19216,219.15252)" - x1="151.9079" - y1="188.73213" - x2="151.07002" - y2="49.432087" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient5987" - id="linearGradient5993" - x1="223.94716" - y1="-310.04846" - x2="233.99281" - y2="-310.04846" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.99495343,0,0,0.98976252,1.1855286,-3.1256575)" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient5987" - id="linearGradient5999" - gradientUnits="userSpaceOnUse" - x1="223.94716" - y1="-310.04846" - x2="233.99281" - y2="-310.04846" - gradientTransform="translate(-38.940119,0)" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient9677-1" - id="radialGradient6007" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.42866379,-0.45005125,1.5624352,0.51510774,-164.07876,-199.45791)" - cx="319.82288" - cy="64.117065" - fx="319.82288" - fy="64.117065" - r="13.808043" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient9941-43" - id="linearGradient6009" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,-0.50649125,0.86346939,0,61.811175,-298.60338)" - x1="29.374996" - y1="21.741114" - x2="20.004526" - y2="6.7253776" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient9903-5" - id="radialGradient6011" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.00553762,-1.2219079,0.52893295,8.6841528e-4,38.317881,79.803805)" - cx="319.47476" - cy="74.762054" - fx="319.47476" - fy="74.762054" - r="14.737162" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient9903-5" - id="radialGradient6021" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.00468607,-1.0692464,0.44759605,7.5991801e-4,112.80492,28.04045)" - cx="319.47476" - cy="74.762054" - fx="319.47476" - fy="74.762054" - r="14.737162" /> - <linearGradient - inkscape:collect="always" - xlink:href="#linearGradient6048" - id="linearGradient6023" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0,-0.44321172,0.73068902,0,132.68554,-303.08965)" - x1="29.374996" - y1="21.741114" - x2="20.004526" - y2="6.7253776" /> - <radialGradient - inkscape:collect="always" - xlink:href="#linearGradient9677-1" - id="radialGradient6025" - gradientUnits="userSpaceOnUse" - gradientTransform="matrix(0.36274586,-0.3938231,1.3221712,0.4507516,-58.572255,-216.17961)" - cx="319.82288" - cy="64.117065" - fx="319.82288" - fy="64.117065" - r="13.808043" /> - </defs> - <metadata - id="metadata4"> - <rdf:RDF> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:creator> - <cc:Agent> - <dc:title>Lapo Calamandrei</dc:title> - </cc:Agent> - </dc:creator> - <dc:source /> - <cc:license - rdf:resource="" /> - <dc:title>Firewall</dc:title> - <dc:subject> - <rdf:Bag /> - </dc:subject> - <dc:date /> - <dc:rights> - <cc:Agent> - <dc:title /> - </cc:Agent> - </dc:rights> - <dc:publisher> - <cc:Agent> - <dc:title /> - </cc:Agent> - </dc:publisher> - <dc:identifier /> - <dc:relation /> - <dc:language /> - <dc:coverage /> - <dc:description /> - <dc:contributor> - <cc:Agent> - <dc:title /> - </cc:Agent> - </dc:contributor> - </cc:Work> - <cc:Work - rdf:about=""> - <dc:format>image/svg+xml</dc:format> - <dc:type - rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - </cc:Work> - </rdf:RDF> - </metadata> - <g - style="display:inline" - inkscape:groupmode="layer" - inkscape:label="artwork" - id="layer1"> - <g - inkscape:groupmode="layer" - id="layer2" - inkscape:label="baseplate" - style="display:none"> - <rect - style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect6284" - width="48" - height="48" - x="296.0625" - y="51.99633" - inkscape:label="48x48" /> - <rect - inkscape:label="32x32" - y="127.99634" - x="303" - height="32" - width="32" - id="rect6592" - style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <rect - inkscape:label="24x24" - y="178" - x="302" - height="24" - width="24" - id="rect5028" - style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <rect - inkscape:label="16x16" - y="221" - x="303" - height="16" - width="16" - id="rect6833" - style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <rect - style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect6749" - width="22" - height="22" - x="303" - y="179.05884" - inkscape:label="22x22" /> - <text - id="context" - inkscape:label="context" - style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans" - x="31.87059" - xml:space="preserve" - y="18.860306"><tspan - sodipodi:role="line" - x="31.87059" - y="18.860306" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans" - id="tspan6058">devices</tspan></text> - <text - id="icon-name" - inkscape:label="icon-name" - sodipodi:linespacing="125%" - style="font-size:18px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans Bold" - x="302.87057" - xml:space="preserve" - y="18.860306"><tspan - sodipodi:role="line" - x="302.87057" - y="18.860306" - style="font-size:18px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:DejaVu Sans;-inkscape-font-specification:DejaVu Sans Bold" - id="tspan6062">gcr-smart-card</tspan></text> - <rect - inkscape:label="256x256" - y="32" - x="20" - height="256" - width="256" - id="rect6282" - style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - inkscape:export-xdpi="90" - inkscape:export-ydpi="90" /> - </g> - <g - inkscape:groupmode="layer" - id="layer4" - inkscape:label="smallsizes" - style="display:inline"> - <g - id="g6154" - style="fill:#ffffff" - transform="matrix(1.25,0,0,1.25,-78,-47.25)" /> - <rect - ry="4.75" - rx="5.1779518" - y="94.979431" - x="301.29306" - height="137.04115" - width="234.22455" - id="rect5804" - style="opacity:0.9;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter5758);enable-background:accumulate" - transform="matrix(0.18598708,0,0,0.18713623,242.2418,45.859499)" /> - <rect - ry="1.4764122" - rx="1.4764122" - y="62" - x="298" - height="27" - width="44" - id="rect5806" - style="color:#000000;fill:url(#linearGradient5840);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <path - sodipodi:nodetypes="sscsscsss" - inkscape:connector-curvature="0" - id="path5808" - d="M 298.41236,62 C 298.18248,62 298,62.181715 298,62.410634 l 0,11.815805 c 1.52647,-0.617796 9.57138,-5.313111 20.58744,-4.326436 8.69319,0.778613 9.46199,4.841397 21.61795,6.084632 0.63834,0.06527 1.23556,-0.09702 1.79461,-0.121446 l 0,-13.452555 C 342,62.181715 341.81752,62 341.58765,62 z" - style="color:#000000;fill:#ffffff;fill-opacity:0.1254902;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <rect - transform="matrix(0,1,-1,0,0,0)" - ry="2.1703689" - rx="2.2517214" - y="-319" - x="67.03595" - height="17" - width="13.928329" - id="rect5810" - style="fill:url(#radialGradient6011);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.57194108;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" /> - <rect - transform="matrix(0,1,-1,0,0,0)" - style="fill:url(#linearGradient6009);fill-opacity:1;fill-rule:evenodd;stroke:#c4a000;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - id="rect5812" - width="13" - height="16" - x="67.5" - y="-318.50003" - rx="1.6989782" - ry="1.6375958" /> - <rect - ry="1.3708601" - rx="1.4222498" - y="-318.358" - x="66.713745" - height="15.981206" - width="12.965498" - id="rect5814" - style="opacity:0.44943824;fill:none;stroke:url(#radialGradient6007);stroke-width:1.00000608;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - transform="matrix(0.00182552,0.99999833,-0.99999665,-0.00258966,0,0)" /> - <path - sodipodi:nodetypes="ccccccccccccccc" - inkscape:connector-curvature="0" - d="m 312.98117,76.998772 4.77911,0 m -4.77911,-3.015818 4.81883,0 m -14.6,3.015818 4.7455,0 m -4.69808,-3.015818 4.69808,0 m -4.74235,-2.999064 4.74235,0 m 0,-2.783875 0,11.590736 m 5.03567,0.0093 0,-8.816161 4.77898,0" - style="fill:none;stroke:#534917;stroke-width:0.40000001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;enable-background:new" - id="path5816" /> - <g - transform="scale(0.99692491,1.0030846)" - style="font-size:3.35809374px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - id="text5818"> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 322.99971,84.505959 c -0.32371,0.232981 -1.54949,0.04907 -0.57167,0.557469 1.30174,0.111492 0.90098,-1.166102 0.16184,-1.291557 0.7756,0.107934 0.81615,-0.650871 0.0161,-0.415116 -1.167,0.423486 -0.30987,0.983754 0.39371,1.149204 z" - id="path3148" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 324.52575,83.720165 c 0.58322,0.03859 0.10268,1.927499 0.68071,0.994317 -0.3454,-0.72254 0.65411,-1.459071 0.67298,-0.433284 -0.1754,1.210945 0.81092,0.431071 0.38687,-0.3259 -0.30544,-1.052506 -1.70368,-0.501021 -2.4567,-0.441665 0.0358,0.422654 -0.24246,1.331187 0.16648,1.501906 0.58935,-0.152916 -0.24835,-1.362377 0.54972,-1.295373" - id="path3150" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 327.4337,83.337343 c -0.70375,-0.234044 -0.80517,0.751699 -0.003,0.36018 0.96307,0.47219 -1.53569,0.210894 -0.53946,1.184024 1.15222,0.871793 1.96139,-1.044388 0.78064,-1.523536 -0.0776,-0.02067 -0.15937,-0.0125 -0.23867,-0.02067 z m 0.34254,1.232423 c -1.23331,0.556156 -0.29753,-0.917646 0,0 z" - id="path3152" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 328.92638,83.454876 c -0.71121,-0.25821 -0.25734,2.460253 0.0886,1.181193 -0.23749,-0.835217 0.28101,-0.801149 0.77477,-1.147657 -0.21432,-0.248059 -0.60833,-0.147961 -0.8634,-0.03354 z" - id="path3154" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 331.15846,84.959302 c -0.13091,-0.370672 -1.13688,-0.707435 -0.41974,-1.235716 1.0052,-0.210009 -0.3378,-0.211313 -0.25368,-0.824831 -0.82724,0.270344 -0.32313,1.166161 -0.20457,1.867126 0.16445,0.336794 0.58411,0.319444 0.87799,0.193421 z" - id="path3156" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 332.36092,84.213805 c -0.34598,1.156552 2.30829,0.778865 0.87676,0.398324 -1.11605,-0.394633 0.0921,-1.041939 0.53419,-1.056156 -0.28714,-0.59917 -1.58123,-0.02864 -1.41095,0.657832 z" - id="path3158" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 334.87136,83.337343 c -0.70375,-0.234044 -0.80517,0.7517 -0.003,0.36018 0.96308,0.472187 -1.53573,0.210908 -0.53944,1.184035 1.15222,0.871768 1.96152,-1.044324 0.78072,-1.523548 -0.0776,-0.02067 -0.15935,-0.01249 -0.23866,-0.02067 m 0.34252,1.23242 c -0.79103,0.509837 -0.62218,-0.701893 0.0231,-0.122198 l -0.0231,0.122198 -1e-5,0 z" - id="path3160" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 336.36403,83.454876 c -0.71123,-0.258235 -0.25735,2.460259 0.0886,1.181193 -0.23749,-0.835217 0.28101,-0.801149 0.77477,-1.147658 -0.21432,-0.248055 -0.60832,-0.147962 -0.86339,-0.03354 z" - id="path3162" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 337.43085,84.207089 c -0.19412,0.926634 1.81011,1.235668 1.60519,0.181973 0,-0.575565 0,-1.151129 0,-1.726694 -0.6641,-0.140942 -0.24181,1.169719 -1.07378,0.721555 -0.32992,0.120291 -0.56299,0.471056 -0.53139,0.823167 m 0.90333,0.460059 c -1.26081,-0.05566 0.4577,-1.896907 0.30375,-0.395608 0.045,0.197727 -0.0297,0.498815 -0.30375,0.395608 z" - id="path3164" - inkscape:connector-curvature="0" /> - </g> - <rect - style="color:#000000;fill:url(#linearGradient5866);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect5850" - width="29.999918" - height="17.999855" - x="304.00003" - y="135.00011" - rx="0.98426384" - ry="0.98426384" /> - <path - style="color:#000000;fill:#ffffff;fill-opacity:0.1254902;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - d="m 304.28119,135.00013 c -0.15674,0 -0.28115,0.12252 -0.28115,0.27686 l 0,7.96657 c 1.04078,-0.41652 6.52593,-3.58226 14.03685,-2.91701 5.92717,0.52497 6.45133,3.26422 14.73948,4.10245 0.43522,0.0441 0.84241,-0.0654 1.22358,-0.082 l 0,-9.07012 c 0,-0.15435 -0.12441,-0.27686 -0.28115,-0.27686 z" - id="path5852" - inkscape:connector-curvature="0" - sodipodi:nodetypes="sscsscsss" /> - <rect - ry="1.7391665" - rx="1.7391665" - y="183" - x="303" - height="14" - width="22" - id="rect5912" - style="color:#000000;fill:url(#linearGradient5926);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <path - sodipodi:nodetypes="sscsscsss" - inkscape:connector-curvature="0" - id="path5914" - d="m 303.21305,182.94658 c -0.11472,0 -0.20579,0.0955 -0.20579,0.21585 l 0,6.21093 c 0.76181,-0.32475 4.77672,-2.79283 10.27441,-2.27419 4.33843,0.40929 4.72211,2.54486 10.78869,3.19837 0.31857,0.0342 0.61662,-0.051 0.89562,-0.0639 l 0,-7.07126 c 0,-0.12034 -0.091,-0.21585 -0.20579,-0.21585 z" - style="color:#000000;fill:#ffffff;fill-opacity:0.1254902;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" /> - <rect - style="color:#000000;fill:url(#linearGradient5965);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect5951" - width="15.999992" - height="12" - x="303" - y="223" - rx="1.1520458" - ry="1.1520458" /> - <path - style="color:#000000;fill:#ffffff;fill-opacity:0.1254902;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - d="m 303.13151,222.99567 c -0.0836,0 -0.14994,0.0743 -0.14994,0.16804 l 0,4.83532 c 0.55508,-0.25282 3.4805,-2.17427 7.48634,-1.77049 3.16115,0.31863 3.44071,1.98122 7.86106,2.48999 0.23212,0.0267 0.4493,-0.0398 0.65259,-0.0497 l 0,-5.50511 c 0,-0.0938 -0.0663,-0.16804 -0.14995,-0.16804 z" - id="path5953" - inkscape:connector-curvature="0" - sodipodi:nodetypes="sscsscsss" /> - <g - id="g6001"> - <rect - transform="matrix(0,1,-1,0,0,0)" - style="fill:#edd400;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5993);stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - id="rect5957" - width="9" - height="11" - x="224.5" - y="-315.5" - rx="0.77868956" - ry="0.75055641" /> - <path - sodipodi:nodetypes="ccccccccccc" - inkscape:connector-curvature="0" - d="m 305.4,227.52877 3.11391,0 m -3.11391,2.99452 3.11391,0 m 0,-5.12329 0,7.2 m 3.00306,0 0,-5.07126 3.08303,0 m -3.08303,2.99453 3.08303,0" - style="fill:none;stroke:#997e00;stroke-width:0.80000001;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;enable-background:new" - id="path5959" /> - </g> - <use - x="0" - y="0" - xlink:href="#g6001" - id="use6005" - transform="translate(1,-39)" - width="400" - height="300" /> - <rect - style="fill:url(#radialGradient6021);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.57194108;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - id="rect6013" - width="11.786495" - height="14.87607" - x="137.10687" - y="-320.93796" - rx="2.2517214" - ry="2.1703689" - transform="matrix(0,1,-1,0,0,0)" /> - <rect - ry="1.6375959" - rx="1.6989781" - y="-320.50052" - x="137.49954" - height="14.001008" - width="11.000917" - id="rect6015" - style="fill:url(#linearGradient6023);fill-opacity:1;fill-rule:evenodd;stroke:#c4a000;stroke-width:0.99999958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - transform="matrix(0,1,-1,0,0,0)" /> - <rect - transform="matrix(0.00188775,0.99999822,-0.99999686,-0.00250432,0,0)" - style="opacity:0.44943824;fill:none;stroke:url(#radialGradient6025);stroke-width:1.00000584;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - id="rect6017" - width="10.971724" - height="13.984559" - x="136.73004" - y="-320.22476" - rx="1.4222493" - ry="1.3708594" /> - <path - id="path6019" - style="fill:none;stroke:#534917;stroke-width:0.40000004;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;enable-background:new" - d="m 315.67112,145.03765 4.18202,0 m -12.74115,0 4.15261,0 m -4.14987,-4.08993 4.14987,0 m 0,-2.85579 0,9.80836 m 4.40652,0.008 0,-6.96046 4.18192,0" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccccccccccc" /> - <g - transform="scale(0.99692489,1.0030846)" - style="font-size:3.35809374px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - id="text5818-1"> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 324.73265,150.20183 c -0.1498,0.47294 -1.22187,-0.24989 -0.92803,0.39893 0.44803,0.21962 1.36154,0.19425 1.34952,-0.46486 -0.17549,-0.36152 -1.51481,-0.69478 -0.48028,-0.74481 0.77118,0.0816 0.18308,-0.57638 -0.27856,-0.35109 -0.764,-0.0395 -0.81521,1.01459 -0.0215,0.98616 0.12766,0.0373 0.2619,0.0795 0.35874,0.17574" - id="path3194" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 326.25869,149.41603 c 0.71846,0.0386 -0.14498,1.60083 0.68772,1.20383 0.0179,-0.41554 -0.12296,-1.60217 0.61952,-1.07011 0.0999,0.36387 0.0235,0.75779 0.0461,1.13566 0.71789,0.15007 0.31762,-0.83289 0.37072,-1.2446 -0.21322,-0.68735 -0.99215,-0.22592 -1.47668,-0.33668 -0.39956,-0.045 -1.20695,-0.18263 -0.99616,0.501 0,0.36015 0,0.72031 0,1.08047 0.50746,0.18919 0.39911,-0.29755 0.40297,-0.60366 0.0437,-0.24774 -0.15038,-0.67967 0.25649,-0.65789 l 0.0894,-0.008" - id="path3196" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 329.16664,149.03321 c -0.32716,-0.17538 -0.99565,0.36781 -0.46833,0.39802 0.30912,-0.2484 1.20575,0.25077 0.50658,0.30317 -0.65596,-0.19946 -1.1852,0.74136 -0.40594,0.95373 0.35502,0.006 0.923,0.0745 1.13792,-0.16201 -0.11738,-0.48714 0.21614,-1.29662 -0.46842,-1.46339 -0.0987,-0.0238 -0.20056,-0.0318 -0.30182,-0.0295 m 0.34253,1.23242 c -0.26325,0.40537 -1.05186,-0.22392 -0.32028,-0.23605 0.18832,-0.0694 0.38958,0.007 0.32028,0.23605 z" - id="path3198" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 330.65932,149.15075 c -0.50816,-0.27071 -0.26674,0.61692 -0.31559,0.93657 0.0344,0.27813 -0.15175,0.76409 0.32991,0.60519 0.15485,-0.16454 0.0353,-0.49128 0.0731,-0.72395 -0.11713,-0.47484 0.15253,-0.66492 0.64507,-0.56399 0.51608,-0.4521 -0.53351,-0.42473 -0.73236,-0.25382" - id="path3200" - inkscape:connector-curvature="0" /> - <path - style="line-height:125%;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - d="m 332.8914,150.65517 c 0.15406,-0.45772 -0.90016,-0.23396 -0.57789,-0.85702 -0.0342,-0.26324 -0.023,-0.48106 0.30169,-0.38543 0.5643,0.0893 0.15789,-0.63836 -0.27811,-0.35519 0.15554,-0.33148 -0.27666,-0.72568 -0.4369,-0.31336 0.22561,0.36229 -0.64372,0.41043 -0.0911,0.66216 0.22765,0.45317 -0.1117,1.46905 0.77408,1.30723 0.10405,-0.0111 0.20641,-0.0336 0.30793,-0.0583" - id="path3202" - inkscape:connector-curvature="0" /> - </g> - </g> - <g - inkscape:groupmode="layer" - id="layer5" - inkscape:label="hires" - style="display:inline"> - <g - inkscape:groupmode="layer" - id="layer7" - inkscape:label="card" - style="display:inline"> - <rect - style="opacity:0.9;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter5758);enable-background:accumulate" - id="rect5716" - width="234.22455" - height="137.04115" - x="31.293058" - y="94.979431" - rx="5.1461554" - ry="4.75" /> - <rect - style="color:#000000;fill:url(#linearGradient5538);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - id="rect5530" - width="236.75" - height="144.25" - x="29.75" - y="86.25" - rx="7.8895049" - ry="7.8895049" /> - <path - style="color:#000000;fill:#ffffff;fill-opacity:0.1254902;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" - d="m 31.96875,86.25 c -1.236888,0 -2.21875,0.981862 -2.21875,2.21875 l 0,63.84375 c 8.213435,-3.3381 51.500517,-28.70807 110.77449,-23.37684 46.77528,4.20707 50.91189,26.15933 116.31926,32.87684 3.4347,0.35275 6.64817,-0.52413 9.65625,-0.65625 l 0,-72.6875 c 0,-1.236888 -0.98186,-2.21875 -2.21875,-2.21875 z" - id="rect5546" - inkscape:connector-curvature="0" - sodipodi:nodetypes="sscsscsss" /> - </g> - <g - inkscape:groupmode="layer" - id="layer6" - inkscape:label="chip" - style="display:inline" - sodipodi:insensitive="true"> - <rect - style="fill:url(#radialGradient3610);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.57194108;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - id="rect9523" - width="56.384705" - height="63.111481" - x="119.12219" - y="-114.04798" - rx="8.1474466" - ry="8.1474466" - transform="matrix(0,1,-1,0,0,0)" /> - <rect - ry="6.1474447" - rx="6.1474452" - y="-112.58131" - x="120.67642" - height="60.178139" - width="53.294991" - id="rect9525" - style="fill:url(#linearGradient5640);fill-opacity:1;fill-rule:evenodd;stroke:#c4a000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - transform="matrix(0,1,-1,0,0,0)" /> - <rect - transform="matrix(0.001679,0.99999859,-0.99999604,-0.00281563,0,0)" - style="opacity:0.44943824;fill:none;stroke:url(#radialGradient5642);stroke-width:1.00000632;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.8;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" - id="rect9527" - width="51.223022" - height="58.07003" - x="121.48322" - y="-111.24284" - rx="5.1461554" - ry="5.1461334" /> - <path - id="path4425" - style="fill:none;stroke:#282e2f;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;enable-background:new" - d="m 93.01004,159.80439 19.08411,0 m -19.1169,-12.22749 19.10314,0 m -59.17981,12.22749 18.80887,0 m -18.812733,-12.22749 18.812733,0 m -18.81815,-12.22749 18.90251,0 m -0.0844,-14.18495 0,52.24742 m 21.23733,0.0613 0,-38.10229 19.12426,-0.0214" - inkscape:connector-curvature="0" - sodipodi:nodetypes="ccccccccccccccc" /> - <text - xml:space="preserve" - style="font-size:18px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold" - x="152.5" - y="210.5" - id="text5551" - sodipodi:linespacing="125%"><tspan - sodipodi:role="line" - x="152.5" - y="210.5" - id="tspan5555" - style="font-size:18px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold">smart card</tspan></text> - </g> - </g> - </g> -</svg> diff --git a/gcr/tests/.gitignore b/gcr/tests/.gitignore deleted file mode 100644 index f30fd7b9..00000000 --- a/gcr/tests/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -/ui-test-certificate -/ui-test-details -/ui-test-key -/ui-test-unlock-options -/test-ui-selector diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am deleted file mode 100644 index 5872ff9f..00000000 --- a/gcr/tests/Makefile.am +++ /dev/null @@ -1,68 +0,0 @@ - -INCLUDES = \ - -I$(top_builddir) \ - -I$(top_srcdir) \ - -DSRCDIR="\"@abs_srcdir@\"" \ - -DGCR_API_SUBJECT_TO_CHANGE \ - -DGCK_API_SUBJECT_TO_CHANGE \ - -DGCR_COMPILATION \ - $(GLIB_CFLAGS) \ - $(GTK_CFLAGS) \ - $(LIBGCRYPT_CFLAGS) - -LDADD = \ - $(top_builddir)/gcr/libgcr-testable.la \ - $(top_builddir)/egg/libegg.la \ - $(top_builddir)/egg/libegg-entry-buffer.la \ - $(top_builddir)/gck/libgck-testable.la \ - $(GTK_LIBS) \ - $(GLIB_LIBS) \ - $(LIBGCRYPT_LIBS) - -TEST_PROGS = \ - test-util \ - test-secret-exchange \ - test-simple-certificate \ - test-certificate \ - test-certificate-chain \ - test-fingerprint \ - test-pkcs11-certificate \ - test-openpgp \ - test-openssh \ - test-trust \ - test-parser \ - test-record \ - test-memory-icon \ - test-gnupg-key \ - test-gnupg-collection \ - test-gnupg-process - -check_PROGRAMS = $(TEST_PROGS) - -test: $(TEST_PROGS) - chmod -f 700 $(srcdir)/files/gnupg-homedir - gtester --verbose -m $(TEST_MODE) --g-fatal-warnings $(TEST_PROGS) - -check-local: test - -all-local: $(check_PROGRAMS) - -EXTRA_DIST = \ - files - -# ------------------------------------------------------------------ - -noinst_PROGRAMS = \ - frob-certificate \ - frob-combo-selector \ - frob-gnupg-selector \ - frob-key \ - frob-tree-selector \ - frob-openpgp \ - frob-parser \ - frob-unlock \ - frob-unlock-options - -frob_unlock_SOURCES = \ - frob-unlock.c \ - ../gcr-viewer-window.c diff --git a/gcr/tests/files/RSA_Root_Certificate_1.pem b/gcr/tests/files/RSA_Root_Certificate_1.pem deleted file mode 100644 index f6cdfcd0..00000000 --- a/gcr/tests/files/RSA_Root_Certificate_1.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD -ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu -Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRp -b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv -bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy -NjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x -NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24g -QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x -IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3 -DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2f -NUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM -MFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34 -t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/b -e0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0Wu -PIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A -PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu ------END CERTIFICATE----- diff --git a/gcr/tests/files/RSA_Security_1024_v3.pem b/gcr/tests/files/RSA_Security_1024_v3.pem deleted file mode 100644 index 94e0ad13..00000000 --- a/gcr/tests/files/RSA_Security_1024_v3.pem +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUF -ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg -U2VjdXJpdHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAx -NDlaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT -QSBTZWN1cml0eSAxMDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQDV3f5mCc8kPD6ugU5OisRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dY -rIMKo1W1exeQFYRMiu4mmdxY78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYt -bzZUaMjShFbuklNhCbM/OZuoyZu9zp9+1BlqFikYvtc6adwlWzMaUQIDAQAB -o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME -GDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAdBgNVHQ4EFgQUxMAcpAeU/c1N -AdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEAPy1q4yZDlX2Jl2X7deRy -HUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdNT1+nr6JGFLkM88y9 -am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgDmMrzVcydro7B -qkWY+o8aoI2II/EVQQ2lRj6RP4vr93E= ------END CERTIFICATE----- diff --git a/gcr/tests/files/RSA_Security_2048_v3.pem b/gcr/tests/files/RSA_Security_2048_v3.pem deleted file mode 100644 index 86c907eb..00000000 --- a/gcr/tests/files/RSA_Security_2048_v3.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUF -ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg -U2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5 -MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT -QSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37 -RqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E -0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J -6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMq -s6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzD -uvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2Mw -YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW -gBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6 -/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3V -EhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5g -EydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ -f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJq -aHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk -llgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA -pKnXwiJPZ9d37CAFYd4= ------END CERTIFICATE----- diff --git a/gcr/tests/files/Thawte_Personal_Basic_CA.pem b/gcr/tests/files/Thawte_Personal_Basic_CA.pem deleted file mode 100644 index 22c2a8db..00000000 --- a/gcr/tests/files/Thawte_Personal_Basic_CA.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du -MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl -cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp -Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow -gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV -BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm -BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV -BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ -cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB -jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK -P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ -fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j -kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB -gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7 -c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95 -B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ== ------END CERTIFICATE----- diff --git a/gcr/tests/files/Thawte_Personal_Freemail_CA.pem b/gcr/tests/files/Thawte_Personal_Freemail_CA.pem deleted file mode 100644 index 565a4be1..00000000 --- a/gcr/tests/files/Thawte_Personal_Freemail_CA.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du -MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl -cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m -cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz -NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx -EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp -bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x -JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG -SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq -hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N -j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef -QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY -x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq -hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP -MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC -neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr -5PjRzneigQ== ------END CERTIFICATE----- diff --git a/gcr/tests/files/Thawte_Personal_Premium_CA.pem b/gcr/tests/files/Thawte_Personal_Premium_CA.pem deleted file mode 100644 index 688c3ae1..00000000 --- a/gcr/tests/files/Thawte_Personal_Premium_CA.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du -MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl -cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy -ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5 -NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw -EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n -MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw -IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3 -DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3 -DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7 -7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j -Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq -W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 -DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH -b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx -eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1 -KzGJ ------END CERTIFICATE----- diff --git a/gcr/tests/files/Thawte_Premium_Server_CA.pem b/gcr/tests/files/Thawte_Premium_Server_CA.pem deleted file mode 100644 index aa37cfc9..00000000 --- a/gcr/tests/files/Thawte_Premium_Server_CA.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du -MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy -dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl -IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl -cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1 -OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ -BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg -Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x -ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3 -DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI -NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL -lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN -9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B -AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI -hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ -a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU -Qg== ------END CERTIFICATE----- diff --git a/gcr/tests/files/Thawte_Server_CA.pem b/gcr/tests/files/Thawte_Server_CA.pem deleted file mode 100644 index ac4e25bf..00000000 --- a/gcr/tests/files/Thawte_Server_CA.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du -MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy -dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl -IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 -ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG -A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw -ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE -CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ -VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz -QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I -/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC -6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX -TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD -TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e -QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni -TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= ------END CERTIFICATE----- diff --git a/gcr/tests/files/Thawte_Time_Stamping_CA.pem b/gcr/tests/files/Thawte_Time_Stamping_CA.pem deleted file mode 100644 index fecbd15e..00000000 --- a/gcr/tests/files/Thawte_Time_Stamping_CA.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmls -bGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmlj -YXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcw -MTAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT -BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN -BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x -HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcN -AQEBBQADgY0AMIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8 -WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR -5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7 -X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN -AQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC9RAIDb/LogWK -0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQpgCed/r8 -zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZCayJ -SdM= ------END CERTIFICATE----- diff --git a/gcr/tests/files/ca-certificates.crt b/gcr/tests/files/ca-certificates.crt deleted file mode 100644 index c30335f8..00000000 --- a/gcr/tests/files/ca-certificates.crt +++ /dev/null @@ -1,2560 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx -EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h -bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy -YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp -Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAy -MzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG -A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt -YWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYD -VQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVA -isamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyj -Qo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50 -QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYt -bRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbUR -yEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwID -AQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0 -cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0f -BDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFj -cmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1 -U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGl -YjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75Fos -SzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/ -t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u -mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb -K+9A46sd33oqK8n8 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 -IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB -IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA -Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO -BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi -MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ -ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ -8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 -zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y -fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 -w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc -G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k -epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q -laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ -QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU -fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 -YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w -ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY -gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe -MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 -IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy -dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw -czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 -dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl -aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC -AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg -b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB -ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc -nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg -18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c -gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl -Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY -sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T -SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF -CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum -GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk -zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW -omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIRANAeQJAAAEZSAAAAAQAAAAQwDQYJKoZIhvcNAQEF -BQAwgYkxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJEQzETMBEGA1UEBxMKV2Fz -aGluZ3RvbjEXMBUGA1UEChMOQUJBLkVDT00sIElOQy4xGTAXBgNVBAMTEEFC -QS5FQ09NIFJvb3QgQ0ExJDAiBgkqhkiG9w0BCQEWFWFkbWluQGRpZ3NpZ3Ry -dXN0LmNvbTAeFw05OTA3MTIxNzMzNTNaFw0wOTA3MDkxNzMzNTNaMIGJMQsw -CQYDVQQGEwJVUzELMAkGA1UECBMCREMxEzARBgNVBAcTCldhc2hpbmd0b24x -FzAVBgNVBAoTDkFCQS5FQ09NLCBJTkMuMRkwFwYDVQQDExBBQkEuRUNPTSBS -b290IENBMSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBkaWdzaWd0cnVzdC5jb20w -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx0xHgeVVDBwhMywVC -AOINg0Y95JO6tgbTDVm9PsHOQ2cBiiGo77zM0KLMsFWWU4RmBQDaREmA2FQK -pSWGlO1jVv9wbKOhGdJ4vmgqRF4vz8wYXke8OrFGPR7wuSw0X4x8TAgpnUBV -6zx9g9618PeKgw6hTLQ6pbNfWiKX7BmbwQVo/ea3qZGULOR4SCQaJRk665Wc -OQqKz0Ky8BzVX/tr7WhWezkscjiw7pOp03t3POtxA6k4ShZsiSrK2jMTecJV -jO2cu/LLWxD4LmE1xilMKtAqY9FlWbT4zfn0AIS2V0KFnTKo+SpU+/94Qby9 -cSj0u5C8/5Y0BONFnqFGKECBAgMBAAGjFjAUMBIGA1UdEwEB/wQIMAYBAf8C -AQgwDQYJKoZIhvcNAQEFBQADggEBAARvJYbk5pYntNlCwNDJALF/VD6Hsm0k -qS8Kfv2kRLD4VAe9G52dyntQJHsRW0mjpr8SdNWJt7cvmGQlFLdh6X9ggGvT -ZOirvRrWUfrAtF13Gn9kCF55xgVM8XrdTX3O5kh7VNJhkoHWG9YA8A6eKHeg -TYjHInYZw8eeG6Z3ePhfm1bR8PIXrI6dWeYf/le22V7hXZ9F7GFoGUHhsiAm -/lowdiT/QHI8eZ98IkirRs3bs4Ysj78FQdPB4xTjQRcm0HyncUwZ6EoPclgx -fexgeqMiKL0ZJGA/O4dzwGvky663qyVDslUte6sGDnVdNOVdc22esnVApVnJ -TzFxiNmIf1Q= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC -VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB -bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg -Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyOTA2MDAw -MFoXDTM3MTEyMDE1MDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB -T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg -SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAJnej8Mlo2k06AX3dLm/WpcZuS+U0pPlLYnKhHw/EEMbjIt8hFj4JHxI -zyr9wBXZGH6EGhfT257XyuTZ16pYUYfw8ItITuLCxFlpMGK2MKKMCxGZYTVt -fu/FsRkGIBKOQuHfD5YQUqjPnF+VFNivO3ULMSAfRC+iYkGzuxgh28pxPIzs -trkNn+9R7017EvILDOGsQI93f7DKeHEMXRZxcKLXwjqFzQ6axOAAsNUl6twr -5JQtOJyJQVdkKGUZHLZEtMgxa44Be3ZZJX8VHIQIfHNlIAqhBC4aMqiaILGc -LCFZ5/vP7nAtCMpjPiybkxlqpMKX/7eGV4iFbJ4VFitNLLMCAwEAAaNjMGEw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUoTYwFsuGkABFgFOxj8jYPXy+ -XxIwHwYDVR0jBBgwFoAUoTYwFsuGkABFgFOxj8jYPXy+XxIwDgYDVR0PAQH/ -BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4IBAQCKIBilvrMvtKaEAEAwKfq0FHNM -eUWn9nDg6H5kHgqVfGphwu9OH77/yZkfB2FK4V1Mza3u0FIy2VkyvNp5ctZ7 -CegCgTXTCt8RHcl5oIBN/lrXVtbtDyqvpxh1MwzqwWEFT2qaifKNuZ8u77Bf -WgDrvq2g+EQFZ7zLBO+eZMXpyD8Fv8YvBxzDNnGGyjhmSs3WuEvGbKeXO/oT -LW4jYYehY0KswsuXn2Fozy1MBJ3XJU8KDk2QixhWqJNIV9xvrr2eZ1d3iVCz -vhGbRWeDhhmH05i9CBoWH1iCC+GWaQVLjuyDUTEH1dSf/1l7qG6Fz9NLqUmw -X7A5KGgOc90lmt4S ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF5jCCA86gAwIBAgIBATANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC -VVMxHTAbBgNVBAoTFEFPTCBUaW1lIFdhcm5lciBJbmMuMRwwGgYDVQQLExNB -bWVyaWNhIE9ubGluZSBJbmMuMTcwNQYDVQQDEy5BT0wgVGltZSBXYXJuZXIg -Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyOTA2MDAw -MFoXDTM3MDkyODIzNDMwMFowgYMxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRB -T0wgVGltZSBXYXJuZXIgSW5jLjEcMBoGA1UECxMTQW1lcmljYSBPbmxpbmUg -SW5jLjE3MDUGA1UEAxMuQU9MIFRpbWUgV2FybmVyIFJvb3QgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC -ggIBALQ3WggWmRToVbEbJGv8x4vmh6mJ7ouZzU9AhqS2TcnZsdw8TQ2FTBVs -RotSeJ/4I/1n9SQ6aF3Q92RhQVSji6UI0ilbm2BPJoPRYxJWSXakFsKlnUWs -i4SVqBax7J/qJBrvuVdcmiQhLE0OcR+mrF1FdAOYxFSMFkpBd4aVdQxHAWZg -/BXxD+r1FHjHDtdugRxev17nOirYlxcwfACtCJ0zr7iZYYCLqJV+FNwSbKTQ -2O9ASQI2+W6p1h2WVgSysy0WVoaP2SBXgM1nEG2wTPDaRrbqJS5Gr42whTg0 -ixQmgiusrpkLjhTXUr2eacOGAgvqdnUxCc4zGSGFQ+aJLZ8lN2fxI2rSAG2X -+Z/nKcrdH9cG6rjJuQkhn8g/BsXS6RJGAE57COtCPStIbp1n3UsC5ETzkxml -J85per5n0/xQpCyrw2u544BMzwVhSyvcG7mm0tCq9Stz+86QNZ8MUhy/XCFh -EVsVS6kkUfykXPcXnbDS+gfpj1bkGoxoigTTfFrjnqKhynFbotSg5ymFXQNo -Kk/SBtc9+cMDLz9l+WceR0DTYw/j1Y75hauXTLPXJuuWCpTehTacyH+BCQJJ -Kg71ZDIMgtG6aoIbs0t0EfOMd9afv9w3pKdVBC/UMejTRrkDfNoSTllkt1Ex -MVCgyhwn2RAurda9EGYrw7AiShJbAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMB -Af8wHQYDVR0OBBYEFE9pbQN+nZ8HGEO8txBO1b+pxCAoMB8GA1UdIwQYMBaA -FE9pbQN+nZ8HGEO8txBO1b+pxCAoMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG -9w0BAQUFAAOCAgEAO/Ouyuguh4X7ZVnnrREUpVe8WJ8kEle7+z802u6teio0 -cnAxa8cZmIDJgt43d15Ui47y6mdPyXSEkVYJ1eV6moG2gcKtNuTxVBFT8zRF -ASbI5Rq8NEQh3q0l/HYWdyGQgJhXnU7q7C+qPBR7V8F+GBRn7iTGvboVsNIY -vbdVgaxTwOjdaRITQrcCtQVBynlQboIOcXKTRuidDV29rs4prWPVVRaAMCf/ -drr3uNZK49m1+VLQTkCpx+XCMseqdiThawVQ68W/ClTluUI8JPu3B5wwn3la -5uBAUhX0/Kr0VvlEl4ftDmVyXr4m+02kLQgH3thcoNyBM5kYJRF3p+v9WAks -mWsbivNSPxpNSGDxoPYzAlOL7SUJuA0t7Zdz7NeWH45gDtoQmy8YJPamTQr5 -O8t1wswvziRpyQoijlmn94IM19drNZxDAGrElWe6nEXLuA4399xOAU++CrYD -062KRffaJ00psUjf5BHklka9bAI+1lHIlRcBFanyqqryvy9lG2/QuRqT9Y41 -xICHPpQvZuTpqP9BnHAqTyo5GJUefvthATxRCC4oGKQWDzH9OmwjkyB24f0H -hdFbP9IcczLd+rn4jM8Ch3qaluTtT4mNU0OrDhPAARW0eTjb/G49nlG2uBOL -Z8/5fNkiHfZdxRwBL5joeiQYvITX+txyW/fBOmg= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJT -RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4 -dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5h -bCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzEL -MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1B -ZGRUcnVzdCBFeHRlcm5hbCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1 -c3QgRXh0ZXJuYWwgQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBALf3GjPm8gAELTngTlvtH7xsD821+iO2zt6bETOXpClMfZOfvUq8 -k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9uMq/NzgtHj6RQa1wVsfwTz/oMp50 -ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzXmk6vBbOmcZSccbNQYArHE504 -B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LXa0Tkx63ubUFfclpxCDez -eWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzNE0S3ySvdQwAl+mG5 -aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0WicCAwEAAaOB -3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYDVR0PBAQD -AgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0Jvf6 -xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU -cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdv -cmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJ -KoZIhvcNAQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZl -j7DYd7usQWxHYINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5R -xNKWt9x+Tu5w/Rw56wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjT -K3rMUUKhemPR5ruhxSvCNr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1 -n6diIWgVIEM8med8vSTYqZEXc4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHx -REzGBHNJdmAPx/i9F4BrLunMTA5amnkPIAou1Z5jJh5VkpTYghdae9C8x49O -hgQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJT -RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU -UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw -HhcNMDAwNTMwMTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJT -RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU -UCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3Qw -ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwze -xODcEyPNwTXH+9ZOEQpnXvUGW2ulCDtbKRY654eyNAbFvAWlA3yCyykQruGI -gb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6ntGO0/7Gcrjyvd7ZWxbWroulpOj0O -M3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyldI+Yrsj5wAYi56xz36Uu+1Lc -sRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJchPXQhI2U0K7t4WaPW4XY5 -mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC+Mcdoq0Dlyz4zyXG -9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0OBBYEFJWxtPCU -tr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ -MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBlMQsw -CQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk -ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAx -IENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0 -MkhHma6X7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0Ph -iVYrqW9yTkkz43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9 -tTEv2dB8Xfjea4MYeDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL -/bscVjby/rK25Xa71SJlpz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlV -g3sslgf/WSxEo8bl6ancoWOAWiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6 -tkD9xOQ14R0WHNC8K47Wcdk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJT -RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU -UCBOZXR3b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAe -Fw0wMDA1MzAxMDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNF -MRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQ -IE5ldHdvcmsxIDAeBgNVBAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+ -A3S72mnTRqX4jsIMEZBRpS9mVEBV6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c -+OLspoH4IcUkzBEMP9smcnrHAZcHF/nXGCwwfQ56HmIexkvA/X1id9NEHif2 -P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnPdzRGULD4EfL+OHn3Bzn+UZKX -C1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH1lWfl2royBFkuucZKT8R -s3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF62WUaUC6wNW0uLp9 -BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQWBBSBPjfYkrAf -d59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zCB -jgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDELMAkG -A1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU -cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENB -IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmu -G7jD8WS6IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL -+YPoRNWyQSW/iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbj -PGsye/Kf8Lb93/AoGEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bY -GozH7ZxOmuASu7VqTITh4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6 -NVDFSMwGR+gn2HCNX2TmoUQmXiLsks3/QppEIW1cxeMiHV9HEufOX1362Kqx -My3ZdvJOOjMMK7MtkAY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJT -RTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRU -UCBOZXR3b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9v -dDAeFw0wMDA1MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYT -AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3Qg -VFRQIE5ldHdvcmsxIzAhBgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBS -b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoek -n0e+EV+vhDTbYjx5eLfpMLXsDBwqxBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKk -IhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G87B4pfYOQnrjfxvM0PC3KP0q6p6z -sLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i2O+tCBGaKZnhqkRFmhJePp1t -UvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8UWfyEk9mHfExUE+uf0S0R -+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c10cIDMzZbdSZtQvES -a0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0GA1UdDgQWBBQ5 -lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw -AwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6FrpGkw -ZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL -ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVh -bGlmaWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2Vh -lRO6aQTvhsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxG -GuoYQ992zPlmhpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx9 -5dr6h+sNNVJn0J6XdgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKF -Yqa0p9m9N5xotS1WfbC3P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVA -wRv1cEWw3F369nJad9Jjzc9YiQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQw -dOUeqN48Jzd/g66ed8/wMLH/S5noxqE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV -UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l -cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4X -DTAyMDUyODA2MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMx -HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp -Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCa -xlCyfqXfaE0bfA+2l2h9LaaLl+lkhsmj76CGv2BlnEtUiMJIxUo5vxTjWVXl -GbR0yLQFOVwWpeKVBeASrlmLojNoWBym1BW32J/X3HGrfpq/m44zDyL9Hy7n -BzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsWOqMFf6Dch9Wc/HKpoH145Lcx -VR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb2xzTa5qGUwew76wGePiE -mf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQkoO3rHl+Ee5fSfwMCu -JKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAUAK3Zo/Z5 -9m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUA -A4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF -Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOM -IOAbLjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTI -dGcL+oiroQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43g -Kd8hdIaC2y+CMMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j -8uB9Gr784N/Xx6dssPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJV -UzEcMBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1l -cmljYSBPbmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4X -DTAyMDUyODA2MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMx -HDAaBgNVBAoTE0FtZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJp -Y2EgT25saW5lIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIw -DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssN -t79Hc9PwVU3dxgz6sWYFas14tNwC206B89enfHG8dWOgXeMHDEjsJcQDIPT/ -DjsS/5uN4cbVG7RtIuOx238hZK+GvFciKtZHgVdEglZTvYYUAQv8f3SkWq7x -uhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2JxhP7JsowtS013wMPgwr38oE -18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9BoInLRBYBbV4Bbkv2wxr -kJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7eXz8d3eOyG6ChKiMD -bi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8BPeraunzgWGcX -uVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67Xnfn6KVu -Y8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEqZ8A9 -W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ -o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48 -ArO3+L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124Hhn -AgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3Op -aaEg5+31IqEjFNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNee -MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypL -M7PmG2tZTiLMubekJcmnxPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qf -tIe3RUavg6WXSIylvfEWK5t2LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjR -Ywu5W1LtGLBDQiKmsXeu3mnFzcccobGlHBD7GL4acN3Bkku+KVqdPzW+5X1R -+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8CNyRnqjQ1xU3c6U1uPx+xURABsPr -+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMeIjzCpjbdGe+n/BLzJsBZMYVM -nNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMADjMSW7yV5TKQqLPGbIOt -d+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2FAjgQ5ANh1NolNscI -WC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUXOm/9riW99XJZ -ZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPbAZO1XB4Y -3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQlZvqz -2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw -RY8mkaKO/qk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG -EwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0 -MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUx -MjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNV -BAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZ -QmFsdGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAKMEuyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+h -Xe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gR -QKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/CG9VwcPCP -wBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1 -pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNT -Px8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkC -AwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1BE3wMBIGA1Ud -EwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUA -A4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkT -I7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/ -oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67 -G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H -RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYT -AlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNl -cnR1bSBDQTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJ -BgNVBAYTAlBMMRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNV -BAMTCUNlcnR1bSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AM6xwS7TT3zNJc4YPk/EjG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYV -M42sLQnFdvkrOYCJ5JdLkKWoePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/Ox -LjBos8Q82KxujZlakE403Daaj4GIULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE -7SZfECYPCE/wpFcozo+47UX2bu4lXapuOb7kky/ZR6By6/qmW6/KUz/iDsaW -VhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUgAKpoC6EahQGcxEZjgoi2IrHu -/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7HVkCAwEAAaMTMBEwDwYD -VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAuI3O7+cUus/usESS -bLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQaTOs9qmdvLdTN -/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTgxSvgGrZg -FCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1qCjqT -E5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x -O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYV -IZQs6GAqm4VKQPNriiTsBhYscw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJH -QjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxm -b3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFB -IENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIz -MTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFu -Y2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENB -IExpbWl0ZWQxITAfBgNVBAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5AnfRu4ep2hxxNRUSO -vkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhGC1Pqy0wk -wLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfH -dr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf04 -9vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULi -mAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cmez6KJcfA3Z3m -NWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEKIz6W -8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB -Af8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v -QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwu -Y29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG -9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm -7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHC -v8S5dIa2LX1rzNLzRt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdV -CYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAV -GI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C12yxow+ev+to -51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJH -QjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxm -b3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2Vj -dXJlIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4 -MTIzMTIzNTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIg -TWFuY2hlc3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2Rv -IENBIExpbWl0ZWQxJDAiBgNVBAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2 -aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBxM4KK0HDr -c4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPMcm3ye5drswfxdySRXyWP9nQ95IDC -+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3SHpR7LZQdqnXXs5jLrLxkU0C8 -j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996CF23uPJAGysnnlDOXmWC -iIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk3wN42ubqwUcaCwtG -Cd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz6YiO/O1R65Nx -Tq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNVHQ4EFgQU -PNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB -/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv -Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNo -dHRwOi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNl -cy5jcmwwDQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm -4J4oqF7Tt/Q05qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiF -Gv45jN5bBAS0VPmjZ55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXG -De+X3EyrEeFryzHRbPtIgKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsF -Vy2T96oTy9IT4rcuO81rUBcJaD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfU -a7/lXORlAnZUtOM3ZiTTGWHIUhDlizeauan5Hb/qmZJhlv8BzaFfDbxxvA6s -Cx1HRR3B7Hzs/Sk= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJH -QjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxm -b3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1 -c3RlZCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0y -ODEyMzEyMzU5NTlaMH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVy -IE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9k -byBDQSBMaW1pdGVkMSUwIwYDVQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNl -cnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhT -WvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWWfnJSoBVC21ndZHoa0Lh73TkVvFVI -xO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMtTGo87IvDktJTdyR0nAducPy9 -C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7ILfhdyFgymBwwbOM/JYrc/ -oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW1O24zG71++IsWL1/ -T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7kUlcsutT6vif -R4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0GA1UdDgQW -BBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v -ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2 -hjRodHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2Vy -dmljZXMuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8Ntw -uleGFTQQuS9/HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdT -mw7pSqBYaWcOrp32pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+C -l5EfKNsYEYwq5GWDVxISjBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/g -hhmBeC8owH7TzEIK9a5QoNE+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVF -wL4Ucd56/Y57fU0IlqUSc/AtyjcndBInTMu2l+nZrghtWjlA3QVHdWpaIbOj -GM9O9y5Xt5hwXsjEeLBi ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG -EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw -DwYDVQQLEwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQw -MjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy -ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEB -AQUAA4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlR -EmlvMVW5SXIACH7TpWJENySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+Lth -zfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2io74CTADKAqjuAQIxZA9SLRN0 -dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E -YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg -U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNV -BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIx -MDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5fpFpRhgTCgJ3 -pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAMBgNV -HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3 -DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN -QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomA -sH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6 -w4pl ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGp -MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM -YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv -LjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx -ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDEx -ODE4NTVaFw0wODExMjgxODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE -CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp -Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDEx -FjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0BCQEWEmNhQGRp -Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -ANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdfWvnTLnUv2Chi0ZMv/E3U -q4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uKxBmd9LIO/BZsubEF -koPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBEzUNKcI5YhZXh -TizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F5X5yP4Wd -lGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMvOnNn -7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG -9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+ -LegzZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvV -WlHG4VMElo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX -8ngvYzZAOONGDx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn8 -6Oawde3uPclwx12qgUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsT -F7ANUkz+/m9c4pFuHf2kYtdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQG -EwJVUzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREw -DwYDVQQLEwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3 -MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVy -ZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEB -AQUAA4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fB -w18DW9Fvrn5C6mYjuGODVvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87e -ZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd -55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBoBgNVHR8E -YTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwg -U2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNV -BAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIw -OTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6CTShlgDzJQW6s -NS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAMBgNV -HRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3 -DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR -xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLb -dHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlih -w6ID ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGp -MQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBM -YWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENv -LjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx -ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAy -MjQ2MTZaFw0wODExMjcyMjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UE -CBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0Rp -Z2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgWDIx -FjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0BCQEWEmNhQGRp -Z3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -ANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbVp9oaBBg5kkp4o4HC9Xd6 -ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWwBZoPFflrWXJW8vo5 -/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl5WJp3OXuAFK9 -MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi3sOP17ih -YqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+QVCv -bK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG -9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWog -WxyQ2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6 -HE3K1GjNI3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV -6YyDfFk/xPEL553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8 -PzGn0EdzMzkbzE5q10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30 -sPDst2yC7S8xmUJMqbINuBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEgzCCA+ygAwIBAgIEOJ725DANBgkqhkiG9w0BAQQFADCBtDEUMBIGA1UE -ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9HQ0NB -X0NQUyBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT -HChjKSAyMDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1 -c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMDAy -MDcxNjE2NDBaFw0yMDAyMDcxNjQ2NDBaMIG0MRQwEgYDVQQKEwtFbnRydXN0 -Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0dDQ0FfQ1BTIGluY29y -cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDIwMDAg -RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xp -ZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCTdLS25MVL1qFof2LV7PdRV7NySpj10InJrWPNTTVRaoTU -rcloeW+46xHbh65cJFET8VQlhK8pK5/jgOLZy93GRUk0iJBeAZfv6lOm3fzB -3ksqJeTpNfpVBQbliXrqpBFXO/x8PTbNZzVtpKklWb1m9fkn5JVn1j+SgF7y -NH0rhQIDAQABo4IBnjCCAZowEQYJYIZIAYb4QgEBBAQDAgAHMIHdBgNVHR8E -gdUwgdIwgc+ggcyggcmkgcYwgcMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUAw -PgYDVQQLFDd3d3cuZW50cnVzdC5uZXQvR0NDQV9DUFMgaW5jb3JwLiBieSBy -ZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMjAwMCBFbnRydXN0 -Lm5ldCBMaW1pdGVkMTMwMQYDVQQDEypFbnRydXN0Lm5ldCBDbGllbnQgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw -IoAPMjAwMDAyMDcxNjE2NDBagQ8yMDIwMDIwNzE2NDY0MFowCwYDVR0PBAQD -AgEGMB8GA1UdIwQYMBaAFISLdP3FjcD/J20gN0V8/i3OutN9MB0GA1UdDgQW -BBSEi3T9xY3A/ydtIDdFfP4tzrrTfTAMBgNVHRMEBTADAQH/MB0GCSqGSIb2 -fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQQFAAOBgQBObzWA -O9GK9Q6nIMstZVXQkvTnhLUGJoMShAusO7JE7r3PQNsgDrpuFOow4DtifH+L -a3xKp9U1PL6oXOpLu5OOgGarDyn9TS2/GpsKkMWr2tGzhtQvJFJcem3G8v7l -TRowjJDyutdKPkN+1MhQGof4T4HHdguEOnKdzmVml64mXg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIElTCCA/6gAwIBAgIEOJsRPDANBgkqhkiG9w0BAQQFADCBujEUMBIGA1UE -ChMLRW50cnVzdC5uZXQxPzA9BgNVBAsUNnd3dy5lbnRydXN0Lm5ldC9TU0xf -Q1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc -KGMpIDIwMDAgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVz -dC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wMDAyMDQxNzIwMDBaFw0yMDAyMDQxNzUwMDBaMIG6MRQwEgYDVQQKEwtF -bnRydXN0Lm5ldDE/MD0GA1UECxQ2d3d3LmVudHJ1c3QubmV0L1NTTF9DUFMg -aW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykg -MjAwMCBFbnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5l -dCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0G -CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHwV9OcfHO8GCGD9JYf9Mzly0XonUw -tZZkJi9ow0SrqHXmAGc0V55lxyKbc+bT3QgON1WqJUaBbL3+qPZ1V1eMkGxK -wz6LS0MKyRFWmponIpnPVZ5h2QLifLZ8OAfc439PmrkDQYC2dWcTC5/oVzbI -XQA23mYU2m52H083jIITiQIDAQABo4IBpDCCAaAwEQYJYIZIAYb4QgEBBAQD -AgAHMIHjBgNVHR8EgdswgdgwgdWggdKggc+kgcwwgckxFDASBgNVBAoTC0Vu -dHJ1c3QubmV0MT8wPQYDVQQLFDZ3d3cuZW50cnVzdC5uZXQvU1NMX0NQUyBp -bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAy -MDAwIEVudHJ1c3QubmV0IExpbWl0ZWQxOjA4BgNVBAMTMUVudHJ1c3QubmV0 -IFNlY3VyZSBTZXJ2ZXIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxDTALBgNV -BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMDAyMDQxNzIwMDBagQ8yMDIwMDIw -NDE3NTAwMFowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFMtswGvjuz7L/CKc -/vuLkpyw8m4iMB0GA1UdDgQWBBTLbMBr47s+y/winP77i5KcsPJuIjAMBgNV -HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkq -hkiG9w0BAQQFAAOBgQBi24GRzsiad0Iv7L0no1MPUBvqTpLwqa+poLpIYcvv -yQbvH9X07t9WLebKahlzqlO+krNQAraFJnJj2HVQYnUUt7NQGj/KEQALhUVp -bbalrlHhStyCP2yMNLJ3a9kC9n8O6mUE8c1UyrrJzOCE98g+EZfTYAkYvAX/ -bIkz8OwVDw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UE -ChMLRW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNf -MjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsT -HChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1 -c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEy -MjQxNzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0 -Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29y -cC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkg -RW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4 -QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/EC -DNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuXMlBvPci6Zgzj -/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzWnLLP -KQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZd -enoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH -4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB -0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJ -FrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B -AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFh -fGPjK50xA3B20qMooPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVU -KcgF7bISKo30Axv/55IQh7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaoho -wXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2 -+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof888 -6ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE -BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50 -cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs -aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp -bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa -MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV -BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw -LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50 -cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50 -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL -ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv -x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV -iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173 -iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw -ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50 -cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff -SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE -CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50 -cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD -VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D -bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx -MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW -/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG -A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI -hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ -OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU -ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE -PHayXOw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UE -BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50 -cnVzdC5uZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl -MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UE -AxMxRW50cnVzdC5uZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eTAeFw05OTA1MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQsw -CQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3 -dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1pdHMgbGlh -Yi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVkMTow -OAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp -b24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDNKIM0 -VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/I0dNxScZgSYMVHIN -iC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3wkrYKZImZNHk -mGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OCAdcwggHT -MBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHboIHY -pIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5 -BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChs -aW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBM -aW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNo -dHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAi -gA8xOTk5MDUyNTE2MDk0MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMC -AQYwHwYDVR0jBBgwFoAU8BdiE1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYE -FPAXYhNVPbP/CgBr+1CEl/PtYtAaMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9 -B0EABAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEFBQADgYEAkNwwAvpkdMKn -CqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN95K+8cPV1ZVqBLssziY2Zcgx -xufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd2cNgQ4xYDiKWL2KjLB+6 -rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG -EwJVUzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1 -cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4 -MDgyMjE2NDE1MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgx -LTArBgNVBAsTJEVxdWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0 -eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2R -FGiYCh7+2gRvE4RiIcPRfM6fBeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO -/t0BCezhABRP/PvwDN1Dulsr4R+AcJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuv -K9buY0V7xdlfUNLjUA86iOe/FP3gx7kCAwEAAaOCAQkwggEFMHAGA1UdHwRp -MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXF1aWZheDEt -MCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 -MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgwODIyMTY0MTUxWjAL -BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gjIBBPM5iQn9Qw -HQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQFMAMBAf8w -GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB -AFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y -7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2u -FHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJV -UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1 -aWZheCBTZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0 -MDAwMFoXDTIwMDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoT -E0VxdWlmYXggU2VjdXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJl -IEdsb2JhbCBlQnVzaW5lc3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEAuucXkAJlsTRVPEnCUdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQy -td4zjTov2/KaelpzmKNc6fuKcxtc58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORR -OhI8bIpaVIRw28HFkM9yRcuoWcDNM50/o5brhTMhHD4ePmBudpxnhcXIw2EC -AwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAHMA8GA1UdEwEB/wQFMAMBAf8w -HwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1draGwwHQYDVR0OBBYEFL6o -oHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUAA4GBADDiAVGqx+pf -2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkAZ70Br83gcfxa -z2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv8qIYNMR1 -pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJV -UzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1 -aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcN -MjAwNjIxMDQwMDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZh -eCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2lu -ZXNzIENBLTEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fe -k6lfWg0XTzQaDJj0ItlZ1MRoRvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5 -/VGcqiTZ9J2DKocKIdMSODRsjQBuWqDZQu4aIZX5UkxVWsUPOE9G+m34LjXW -HXzr4vCwdYDIqROsvojvOm6rXyo4YgKwEnv+j6YDAgMBAAGjZjBkMBEGCWCG -SAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEp4 -MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRKeDJSEdtZFjZe38EUNkBq -R3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZMzfmpTMANmvPMZWnm -JXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+WB5Hh1Q+WKG1 -tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+KpYr -tWKmpj29f5JZzVoqgrI3eQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQG -EwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlm -YXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5 -MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXgg -U2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0Et -MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF -7Y6yEb3+6+e0dMKP/wXn2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKD -pkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HM -HMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAGA1UdHwRp -MGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBT -ZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y -MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjAL -BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBqy/3YIHqngnYw -HQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMBAf8w -GgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GB -AAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy -0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkt -y3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgw -FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRy -dXN0IFNvbHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3Qg -R2xvYmFsIFJvb3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1 -MQswCQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYD -VQQLEx5HVEUgQ3liZXJUcnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMT -GkdURSBDeWJlclRydXN0IEdsb2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQCVD6C28FCc6HrHiM3dFw4usJTQGz0O9pTAipTHBsiQl8i4 -ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTSr41tiGeA5u2ylc9yMcqlHHK6XALn -ZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X404Wqk2kmhXBIgD8SFcd5tB8F -LztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3rGwnpXtlR22ciYaQqPEh3 -46B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l93PR2VX2bY1QY6fDq -81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0PlZPvy5TYnh+d -XIVtx6quTx8itc2VrbqnzPmrC3p/ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIB+jCCAWMCAgGjMA0GCSqGSIb3DQEBBAUAMEUxCzAJBgNVBAYTAlVTMRgw -FgYDVQQKEw9HVEUgQ29ycG9yYXRpb24xHDAaBgNVBAMTE0dURSBDeWJlclRy -dXN0IFJvb3QwHhcNOTYwMjIzMjMwMTAwWhcNMDYwMjIzMjM1OTAwWjBFMQsw -CQYDVQQGEwJVUzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMRwwGgYDVQQD -ExNHVEUgQ3liZXJUcnVzdCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQC45k+625h8cXyvRLfTD0bZZOWTwUKOx7pJjTUteueLveUFMVnGsS8K -DPufpz+iCWaEVh43KRuH6X4MypqfpX/1FZSj1aJGgthoTNE3FQZor734sLPw -KfWVWgkWYXcKIiXUT0Wqx73llt/51KiOQswkwB6RJ0q1bQaAYznEol44AwID -AQABMA0GCSqGSIb3DQEBBAUAA4GBABKzdcZfHeFhVYAA1IFLezEPI2PnPfMD -+fQ2qLvZ46WXTeorKeDWanOB5sCJo9Px4KWlIjeaY8JIILTbcuPI9tl8vrGv -U9oUtCG41tWW4/5ODFlitppK+ULdjG+BqXH/9ApybW1EDp3zdHSo1TRJ6V6e -6bR64eVaH4QwnNOfpSXY ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYT -AlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVz -dCBHbG9iYWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBC -MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UE -AxMSR2VvVHJ1c3QgR2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEA2swYYzD99BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEH -CIjaWC9mOSm9BXiLnTjoBbdqfnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlC -GDUUna2YRpIuT8rxh0PBFpVXLVDviS2Aelet8u5fa9IAjbkU+BQVNdnARqN7 -csiRv8lVK83Qlz6cJmTM386DGXHKTubU1XupGc1V3sjs0l44U+VcT4wt/lAj -Nvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+bw8HHa8sHo9gOeL6NlMTOdRe -JivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoWMPRfwCvocWvk+QIDAQAB -o1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTAephojYn7qwVkDBF9 -qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1luMrMTjANBgkq -hkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKInZ57Qzxpe -R+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfStQWV -Yrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF -PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot -2/Unhw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeX -xx12E6nV5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvm -Mw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzEL -MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNV -BAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05 -ODA5MDExMjAwMDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkw -FwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRsw -GQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQDaDuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR -4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc -71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4 -bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgK -OOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMW -ea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DP -AgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQUYHtmGkUNl8qJ -UC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOC -AQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq75bCd -PTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q -gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT -2iHRrH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlD -NPYPhyk7ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBg -Hcl5JLL2bP2oZg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYT -AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu -MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s -LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 -MjEuMCwGA1UECxMlSVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eTEuMCwGA1UEAxMlSVBTIENBIENMQVNFMSBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAx -MTIyOTAwNTkzOFoXDTI1MTIyNzAwNTkzOFowggESMQswCQYDVQQGEwJFUzES -MBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNV -BAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzAp -BgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxLjAs -BgNVBAsTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx -LjAsBgNVBAMTJUlQUyBDQSBDTEFTRTEgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEA4FEnpwvdr9G5Q1uCN0VWcu+atsIS7ywSzHb5 -BlmvXSHU0lq4oNTzav3KaY1mSPd05u42veiWkXWmcSjK5yISMmmwPh5r9FBS -YmL9Yzt9fuzuOOpi9GyocY3h6YvJP8a1zZRCb92CRTzo3wno7wpVqVZHYUxJ -ZHMQKD/Kvwn/xi8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBTrsxl588GlHKzc -uh9morKbadB4CDCCAUQGA1UdIwSCATswggE3gBTrsxl588GlHKzcuh9morKb -adB4CKGCARqkggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl -bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJu -ZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFp -bC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0Eg -Q0xBU0UxIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMg -Q0EgQ0xBU0UxIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcN -AQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E -BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUH -AwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB -FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcw -GgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0Bt -YWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UxIENBIENlcnRpZmlj -YXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC -BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQt -FitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTEuY3Js -MD8GCWCGSAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jl -dm9jYXRpb25DTEFTRTEuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93 -d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFMS5odG1sPzA6BglghkgB -hvhCAQgELRYraHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFT -RTEuaHRtbDBzBgNVHR8EbDBqMDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9p -cHMyMDAyL2lwczIwMDJDTEFTRTEuY3JsMDWgM6Axhi9odHRwOi8vd3d3YmFj -ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0UxLmNybDAvBggrBgEFBQcB -AQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZI -hvcNAQEFBQADgYEAK9Dr/drIyllq2tPMMi7JVBuKYn4VLenZMdMu9Ccj/1ur -xUq2ckCuU3T0vAW0xtnIyXf7t/k0f3gA+Nak5FI/LEpjV4F1Wo7ojPsCwJTG -Kbqz3Bzosq/SLmJbGqmODszFV0VRFOlOHIilkfSj945RyKm+hjM+5i9Ibq9U -kE6tsSU= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH6jCCB1OgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARIxCzAJBgNVBAYT -AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu -MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s -LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 -MjEuMCwGA1UECxMlSVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eTEuMCwGA1UEAxMlSVBTIENBIENMQVNFMyBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMB4XDTAx -MTIyOTAxMDE0NFoXDTI1MTIyNzAxMDE0NFowggESMQswCQYDVQQGEwJFUzES -MBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmExLjAsBgNV -BAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMubC4xKzAp -BgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0NTIxLjAs -BgNVBAsTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx -LjAsBgNVBAMTJUlQUyBDQSBDTEFTRTMgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlwcy5lczCBnzANBgkqhkiG -9w0BAQEFAAOBjQAwgYkCgYEAqxf+DrDGaBtT8FK+n/ra+osTBLsBjzLZH49N -zjaY2uQARIwo2BNEKqRrThckQpzTiKRBgtYj+4vJhuW5qYIF3PHeH+AMmVWY -8jjsbJ0gA8DvqqPGZARRLXgNo9KoOtYkTOmWehisEyMiG3zoMRGzXwmqMHBx -RiVrSXGAK5UBsh8CAwEAAaOCBEowggRGMB0GA1UdDgQWBBS4k/8uy9wsjqLn -ev42USGjmFsMNDCCAUQGA1UdIwSCATswggE3gBS4k/8uy9wsjqLnev42USGj -mFsMNKGCARqkggEWMIIBEjELMAkGA1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNl -bG9uYTESMBAGA1UEBxMJQmFyY2Vsb25hMS4wLAYDVQQKEyVJUFMgSW50ZXJu -ZXQgcHVibGlzaGluZyBTZXJ2aWNlcyBzLmwuMSswKQYDVQQKFCJpcHNAbWFp -bC5pcHMuZXMgQy5JLkYuICBCLTYwOTI5NDUyMS4wLAYDVQQLEyVJUFMgQ0Eg -Q0xBU0UzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVJUFMg -Q0EgQ0xBU0UzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcN -AQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8E -BQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUH -AwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIB -FgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcw -GgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0Bt -YWlsLmlwcy5lczBBBglghkgBhvhCAQ0ENBYyQ0xBU0UzIENBIENlcnRpZmlj -YXRlIGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgEC -BBwWGmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMDoGCWCGSAGG+EIBBAQt -FitodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJDTEFTRTMuY3Js -MD8GCWCGSAGG+EIBAwQyFjBodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jl -dm9jYXRpb25DTEFTRTMuaHRtbD8wPAYJYIZIAYb4QgEHBC8WLWh0dHA6Ly93 -d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFMy5odG1sPzA6BglghkgB -hvhCAQgELRYraHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9wb2xpY3lDTEFT -RTMuaHRtbDBzBgNVHR8EbDBqMDGgL6AthitodHRwOi8vd3d3Lmlwcy5lcy9p -cHMyMDAyL2lwczIwMDJDTEFTRTMuY3JsMDWgM6Axhi9odHRwOi8vd3d3YmFj -ay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0UzLmNybDAvBggrBgEFBQcB -AQQjMCEwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZI -hvcNAQEFBQADgYEAF2VcmZVDAyevJuXr0LMXI/dDqsfwfewPxqmurpYPdikc -4gYtfibFPPqhwYHOU7BC0ZdXGhd+pFFhxu7pXu8Fuuu9D6eSb9ijBmgpjnn1 -/7/5p6/ksc7C0YBCJwUENPjDfxZ4IwwHJPJGR607VNCv1TGyr33I6unUVtkO -E7LFRVA= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYT -AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu -MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s -LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 -MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcN -MDExMjI5MDEwNTMyWhcNMjUxMjI3MDEwNTMyWjCCARQxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwG -A1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjEr -MCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEv -MC0GA1UECxMmSVBTIENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwgZ8wDQYJ -KoZIhvcNAQEBBQADgY0AMIGJAoGBALsw19zQVL01Tp/FTILq0VA8R5j8m2md -d81u4D/u6zJfX5/S0HnllXNEITLgCtud186Nq1KLK3jgm1t99P1tCeWu4Wwd -ByOgF9H5fahGRpEiqLJpxq339fWUoTCUvQDMRH/uxJ7JweaPCjbB/SQ9AaD1 -e+J8eGZDi09Z8pvZ+kmzAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUZyaW56G/ -2LUDnf473P7yiuYV3TAwggFGBgNVHSMEggE9MIIBOYAUZyaW56G/2LUDnf47 -3P7yiuYV3TChggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlC -YXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIElu -dGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBz -QG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBT -IENBIENMQVNFQTEgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT -JklQUyBDQSBDTEFTRUExIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJ -KoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM -BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYI -KwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYB -BAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEE -BAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB -D2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMSBDQSBD -ZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG -SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgB -hvhCAQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xB -U0VBMS5jcmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lw -czIwMDIvcmV2b2NhdGlvbkNMQVNFQTEuaHRtbD8wPQYJYIZIAYb4QgEHBDAW -Lmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTEuaHRt -bD8wOwYJYIZIAYb4QgEIBC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIv -cG9saWN5Q0xBU0VBMS5odG1sMHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93 -d3cuaXBzLmVzL2lwczIwMDIvaXBzMjAwMkNMQVNFQTEuY3JsMDagNKAyhjBo -dHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMS5j -cmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5p -cHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAH66iqyAAIQVCtWYUQxkxZwCWINm -yq0eB81+atqAB98DNEock8RLWCA1NnHtogo1EqWmZaeFaQoO42Hu6r4okzPV -7Oi+xNtff6j5YzHIa5biKcJboOeXNp13XjFr/tOn2yrb25aLH2betgPAK7N4 -1lUH5Y85UN4HI3LmvSAUS7SG ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARQxCzAJBgNVBAYT -AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu -MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s -LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 -MjEvMC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwHhcN -MDExMjI5MDEwNzUwWhcNMjUxMjI3MDEwNzUwWjCCARQxCzAJBgNVBAYTAkVT -MRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwG -A1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjEr -MCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEv -MC0GA1UECxMmSVBTIENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkxLzAtBgNVBAMTJklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXMwgZ8wDQYJ -KoZIhvcNAQEBBQADgY0AMIGJAoGBAO6AAPYaZC6tasiDsYun7o/ZttvNG7uG -BiJ2MwwSbUhWYdLcgiViL5/SaTBlA0IjWLxH3GvWdV0XPOH/8lhneaDBgbHU -VqLyjRGZ/fZ98cfEXgIqmuJKtROKAP2Md4bm15T1IHUuDky/dMQ/gT6DtKM4 -Ninn6Cr1jIhBqoCm42zvAgMBAAGjggRTMIIETzAdBgNVHQ4EFgQUHp9XUEe2 -YZM50yz82l09BXW3mQIwggFGBgNVHSMEggE9MIIBOYAUHp9XUEe2YZM50yz8 -2l09BXW3mQKhggEcpIIBGDCCARQxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlC -YXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEuMCwGA1UEChMlSVBTIElu -dGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5sLjErMCkGA1UEChQiaXBz -QG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1MjEvMC0GA1UECxMmSVBT -IENBIENMQVNFQTMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxLzAtBgNVBAMT -JklQUyBDQSBDTEFTRUEzIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJ -KoZIhvcNAQkBFg9pcHNAbWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAM -BgNVHQ8EBQMDB/+AMGsGA1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYI -KwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYB -BAGCNwIBFgYKKwYBBAGCNwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEE -BAMCAAcwGgYDVR0RBBMwEYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGB -D2lwc0BtYWlsLmlwcy5lczBCBglghkgBhvhCAQ0ENRYzQ0xBU0VBMyBDQSBD -ZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkgaHR0cDovL3d3dy5pcHMuZXMvMCkGCWCG -SAGG+EIBAgQcFhpodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyLzA7BglghkgB -hvhCAQQELhYsaHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xB -U0VBMy5jcmwwQAYJYIZIAYb4QgEDBDMWMWh0dHA6Ly93d3cuaXBzLmVzL2lw -czIwMDIvcmV2b2NhdGlvbkNMQVNFQTMuaHRtbD8wPQYJYIZIAYb4QgEHBDAW -Lmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbENMQVNFQTMuaHRt -bD8wOwYJYIZIAYb4QgEIBC4WLGh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIv -cG9saWN5Q0xBU0VBMy5odG1sMHUGA1UdHwRuMGwwMqAwoC6GLGh0dHA6Ly93 -d3cuaXBzLmVzL2lwczIwMDIvaXBzMjAwMkNMQVNFQTMuY3JsMDagNKAyhjBo -dHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0xBU0VBMy5j -cmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5p -cHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAEo9IEca2on0eisxeewBwMwB9dbB -/MjD81ACUZBYKp/nNQlbMAqBACVHr9QPDp5gJqiVp4MI3y2s6Q73nMify5NF -8bpqxmdRSmlPa/59Cy9SKcJQrSRE7SOzSMtEQMEDlQwKeAYSAfWRMS1Jjbs/ -RU4s4OjNtckUFQzjB4ObJnXv ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIH9zCCB2CgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCARwxCzAJBgNVBAYT -AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu -MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s -LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 -MjEzMDEGA1UECxMqSVBTIENBIENoYWluZWQgQ0FzIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MTMwMQYDVQQDEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lwc0BtYWlsLmlw -cy5lczAeFw0wMTEyMjkwMDUzNThaFw0yNTEyMjcwMDUzNThaMIIBHDELMAkG -A1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vs -b25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNl -cyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYw -OTI5NDUyMTMwMQYDVQQLEypJUFMgQ0EgQ2hhaW5lZCBDQXMgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkxMzAxBgNVBAMTKklQUyBDQSBDaGFpbmVkIENBcyBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1h -aWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcVpJJspQg -vJhPUOtopKdJC7/SMejHT8KGC/po/UNaivNgkjWZOLtNA1IhW/A3mTXhQSCB -hYEFcYGdtJUZqV92NC5jNzVXjrQfQj8VXOF6wV8TGDIxya2+o8eDZh65nAQT -y2nBBt4wBrszo7Uf8I9vzv+W6FS+ZoCua9tBhDaiPQIDAQABo4IEQzCCBD8w -HQYDVR0OBBYEFKGtMbH5PuEXpsirNPxShwkeYlJBMIIBTgYDVR0jBIIBRTCC -AUGAFKGtMbH5PuEXpsirNPxShwkeYlJBoYIBJKSCASAwggEcMQswCQYDVQQG -EwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJjZWxvbmEx -LjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZpY2VzIHMu -bC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEItNjA5Mjk0 -NTIxMzAxBgNVBAsTKklQUyBDQSBDaGFpbmVkIENBcyBDZXJ0aWZpY2F0aW9u -IEF1dGhvcml0eTEzMDEGA1UEAxMqSVBTIENBIENoYWluZWQgQ0FzIENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNAbWFpbC5p -cHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsGA1UdJQRk -MGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggr -BgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGCNwoDAQYK -KwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMwEYEPaXBz -QG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5lczBCBglg -hkgBhvhCAQ0ENRYzQ2hhaW5lZCBDQSBDZXJ0aWZpY2F0ZSBpc3N1ZWQgYnkg -aHR0cDovL3d3dy5pcHMuZXMvMCkGCWCGSAGG+EIBAgQcFhpodHRwOi8vd3d3 -Lmlwcy5lcy9pcHMyMDAyLzA3BglghkgBhvhCAQQEKhYoaHR0cDovL3d3dy5p -cHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0FDLmNybDA8BglghkgBhvhCAQMELxYt -aHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9yZXZvY2F0aW9uQ0FDLmh0bWw/ -MDkGCWCGSAGG+EIBBwQsFipodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL3Jl -bmV3YWxDQUMuaHRtbD8wNwYJYIZIAYb4QgEIBCoWKGh0dHA6Ly93d3cuaXBz -LmVzL2lwczIwMDIvcG9saWN5Q0FDLmh0bWwwbQYDVR0fBGYwZDAuoCygKoYo -aHR0cDovL3d3dy5pcHMuZXMvaXBzMjAwMi9pcHMyMDAyQ0FDLmNybDAyoDCg -LoYsaHR0cDovL3d3d2JhY2suaXBzLmVzL2lwczIwMDIvaXBzMjAwMkNBQy5j -cmwwLwYIKwYBBQUHAQEEIzAhMB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5p -cHMuZXMvMA0GCSqGSIb3DQEBBQUAA4GBAERyMJ1WWKJBGyi3leGmGpVfp3hA -K+/blkr8THFj2XOVvQLiogbHvpcqk4A0hgP63Ng9HgfNHnNDJGD1HWHc3Jag -vPsd4+cSACczAsDAK1M92GsDgaPb1pOVIO/Tln4mkImcJpvNb2ar7QMiRDjM -Wb2f2/YHogF/JsRj9SVCXmK9 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICtzCCAiACAQAwDQYJKoZIhvcNAQEEBQAwgaMxCzAJBgNVBAYTAkVTMRIw -EAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcTCUJBUkNFTE9OQTEZMBcGA1UE -ChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UECxMPQ2VydGlmaWNhY2lvbmVz -MRcwFQYDVQQDEw5JUFMgU0VSVklET1JFUzEeMBwGCSqGSIb3DQEJARYPaXBz -QG1haWwuaXBzLmVzMB4XDTk4MDEwMTIzMjEwN1oXDTA5MTIyOTIzMjEwN1ow -gaMxCzAJBgNVBAYTAkVTMRIwEAYDVQQIEwlCQVJDRUxPTkExEjAQBgNVBAcT -CUJBUkNFTE9OQTEZMBcGA1UEChMQSVBTIFNlZ3VyaWRhZCBDQTEYMBYGA1UE -CxMPQ2VydGlmaWNhY2lvbmVzMRcwFQYDVQQDEw5JUFMgU0VSVklET1JFUzEe -MBwGCSqGSIb3DQEJARYPaXBzQG1haWwuaXBzLmVzMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQCsT1J0nznqjtwlxLyYXZhkJAk8IbPMGbWOlI6H0fg3 -PqHILVikgDVboXVsHUUMH2Fjal5vmwpMwci4YSM1gf/+rHhwLWjhOgeYlQJU -3c0jt4BT18g3RXIGJBK6E2Ehim51KODFDzT9NthFf+G4Nu+z4cYgjui0OLzh -PvYR3oydAQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACzzw3lYJN7GO9HgQmm4 -7mSzPWIBubOE3yN93ZjPEKn+ANgilgUTB1RXxafey9m4iEL2mdsUdx+2/iU9 -4aI+A6mB0i1sR/WWRowiq8jMDQ6XXotBtDvECgZAHd1G9AHduoIuPD14cJ58 -GNCr+Lh3B0Zx8coLY1xq+XKU1QFPoNtC ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIIODCCB6GgAwIBAgIBADANBgkqhkiG9w0BAQUFADCCAR4xCzAJBgNVBAYT -AkVTMRIwEAYDVQQIEwlCYXJjZWxvbmExEjAQBgNVBAcTCUJhcmNlbG9uYTEu -MCwGA1UEChMlSVBTIEludGVybmV0IHB1Ymxpc2hpbmcgU2VydmljZXMgcy5s -LjErMCkGA1UEChQiaXBzQG1haWwuaXBzLmVzIEMuSS5GLiAgQi02MDkyOTQ1 -MjE0MDIGA1UECxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0aWZpY2F0aW9u -IEF1dGhvcml0eTE0MDIGA1UEAxMrSVBTIENBIFRpbWVzdGFtcGluZyBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eTEeMBwGCSqGSIb3DQEJARYPaXBzQG1haWwu -aXBzLmVzMB4XDTAxMTIyOTAxMTAxOFoXDTI1MTIyNzAxMTAxOFowggEeMQsw -CQYDVQQGEwJFUzESMBAGA1UECBMJQmFyY2Vsb25hMRIwEAYDVQQHEwlCYXJj -ZWxvbmExLjAsBgNVBAoTJUlQUyBJbnRlcm5ldCBwdWJsaXNoaW5nIFNlcnZp -Y2VzIHMubC4xKzApBgNVBAoUImlwc0BtYWlsLmlwcy5lcyBDLkkuRi4gIEIt -NjA5Mjk0NTIxNDAyBgNVBAsTK0lQUyBDQSBUaW1lc3RhbXBpbmcgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkxNDAyBgNVBAMTK0lQUyBDQSBUaW1lc3RhbXBp -bmcgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHjAcBgkqhkiG9w0BCQEWD2lw -c0BtYWlsLmlwcy5lczCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLju -VqWajOY2ycJioGaBjRrVetJznw6EZLqVtJCneK/K/lRhW86yIFcBrkSSQxA4 -Efdo/BdApWgnMjvEp+ZCccWZ73b/K5Uk9UmSGGjKALWkWi9uy9YbLA1UZ2t6 -KaFYq6JaANZbuxjC3/YeE1Z2m6Vo4pjOxgOKNNtMg0GmqaMCAwEAAaOCBIAw -ggR8MB0GA1UdDgQWBBSL0BBQCYHynQnVDmB4AyKiP8jKZjCCAVAGA1UdIwSC -AUcwggFDgBSL0BBQCYHynQnVDmB4AyKiP8jKZqGCASakggEiMIIBHjELMAkG -A1UEBhMCRVMxEjAQBgNVBAgTCUJhcmNlbG9uYTESMBAGA1UEBxMJQmFyY2Vs -b25hMS4wLAYDVQQKEyVJUFMgSW50ZXJuZXQgcHVibGlzaGluZyBTZXJ2aWNl -cyBzLmwuMSswKQYDVQQKFCJpcHNAbWFpbC5pcHMuZXMgQy5JLkYuICBCLTYw -OTI5NDUyMTQwMgYDVQQLEytJUFMgQ0EgVGltZXN0YW1waW5nIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5MTQwMgYDVQQDEytJUFMgQ0EgVGltZXN0YW1waW5n -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MR4wHAYJKoZIhvcNAQkBFg9pcHNA -bWFpbC5pcHMuZXOCAQAwDAYDVR0TBAUwAwEB/zAMBgNVHQ8EBQMDB/+AMGsG -A1UdJQRkMGIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUF -BwMEBggrBgEFBQcDCAYKKwYBBAGCNwIBFQYKKwYBBAGCNwIBFgYKKwYBBAGC -NwoDAQYKKwYBBAGCNwoDBDARBglghkgBhvhCAQEEBAMCAAcwGgYDVR0RBBMw -EYEPaXBzQG1haWwuaXBzLmVzMBoGA1UdEgQTMBGBD2lwc0BtYWlsLmlwcy5l -czBHBglghkgBhvhCAQ0EOhY4VGltZXN0YW1waW5nIENBIENlcnRpZmljYXRl -IGlzc3VlZCBieSBodHRwOi8vd3d3Lmlwcy5lcy8wKQYJYIZIAYb4QgECBBwW -Gmh0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvMEAGCWCGSAGG+EIBBAQzFjFo -dHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBpbmcu -Y3JsMEUGCWCGSAGG+EIBAwQ4FjZodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAy -L3Jldm9jYXRpb25UaW1lc3RhbXBpbmcuaHRtbD8wQgYJYIZIAYb4QgEHBDUW -M2h0dHA6Ly93d3cuaXBzLmVzL2lwczIwMDIvcmVuZXdhbFRpbWVzdGFtcGlu -Zy5odG1sPzBABglghkgBhvhCAQgEMxYxaHR0cDovL3d3dy5pcHMuZXMvaXBz -MjAwMi9wb2xpY3lUaW1lc3RhbXBpbmcuaHRtbDB/BgNVHR8EeDB2MDegNaAz -hjFodHRwOi8vd3d3Lmlwcy5lcy9pcHMyMDAyL2lwczIwMDJUaW1lc3RhbXBp -bmcuY3JsMDugOaA3hjVodHRwOi8vd3d3YmFjay5pcHMuZXMvaXBzMjAwMi9p -cHMyMDAyVGltZXN0YW1waW5nLmNybDAvBggrBgEFBQcBAQQjMCEwHwYIKwYB -BQUHMAGGE2h0dHA6Ly9vY3NwLmlwcy5lcy8wDQYJKoZIhvcNAQEFBQADgYEA -ZbrBzAAalZHK6Ww6vzoeFAh8+4Pua2JR0zORtWB5fgTYXXk36MNbsMRnLWha -sl8OCvrNPzpFoeo2zyYepxEoxZSPhExTCMWTs/zif/WN87GphV+I3pGW7hdb -rqXqcGV4LCFkAZXOzkw+UPS2Wctjjba9GNSHSl/c7+lW8AoM6HU= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQG -EwJCTTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9v -dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMg -Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNa -Fw0yMTAzMTcxODMzMzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9W -YWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1 -lVO6V/z68mcLOhrfEYBklbTRvM16z/Ypli4kVEAkOPcahdxYTMukJ0KX0J+D -isPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2DrOpm2RgbaIr1VxqYuvXtdj18 -2d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJWCCYfqtffp/p1k3sg3Sp -x2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cugF+FxZc4dZjH3dgEZ -yH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospUxbF6lR1xHkop -igPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCCAk4wPQYI -KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVvdmFk -aXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw -ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlh -bmNlIG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBw -YXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJs -ZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRp -ZmljYXRpb24gcHJhY3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmlj -YXRlIFBvbGljeS4wIgYIKwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMu -Ym0wHQYDVR0OBBYEFItLbe3TKbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYw -gaOAFItLbe3TKbkGGew5Oanwl4Rqy+/foYGEpIGBMH8xCzAJBgNVBAYTAkJN -MRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290 -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCLMA4GA1UdDwEB/wQEAwIB -BjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSkfnIYj9lofFIk3Wdv -OXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf87C9TqnN7Az10 -buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1RcHhXHTMe -/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0ymQM6 -isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW -xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQ -NiOKSnQ2+Q== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD -ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu -Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRp -b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv -bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy -NjAwMjIzM1oXDTE5MDYyNjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x -NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24g -QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x -IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3 -DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfDcnWTq8+epvzzFlLWLU2f -NUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs2Ejcv8ECIMYkpChM -MFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqYJJgpp0lZpd34 -t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliEZwgs3x/b -e0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJn0Wu -PIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A -PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICXDCCAcWgAwIBAgIQCgEBAQAAAnwAAAALAAAAAjANBgkqhkiG9w0BAQUF -ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg -U2VjdXJpdHkgMTAyNCBWMzAeFw0wMTAyMjIyMTAxNDlaFw0yNjAyMjIyMDAx -NDlaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT -QSBTZWN1cml0eSAxMDI0IFYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQDV3f5mCc8kPD6ugU5OisRpgFtZO9+5TUzKtS3DJy08rwBCbbwoppbPf9dY -rIMKo1W1exeQFYRMiu4mmdxY78c4pqqv0I5CyGLXq6yp+0p9v+r+Ek3d/yYt -bzZUaMjShFbuklNhCbM/OZuoyZu9zp9+1BlqFikYvtc6adwlWzMaUQIDAQAB -o2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSME -GDAWgBTEwBykB5T9zU0B1FTapQxf3q4FWjAdBgNVHQ4EFgQUxMAcpAeU/c1N -AdRU2qUMX96uBVowDQYJKoZIhvcNAQEFBQADgYEAPy1q4yZDlX2Jl2X7deRy -HUZXxGFraZ8SmyzVWujAovBDleMf6XbN3Ou8k6BlCsdNT1+nr6JGFLkM88y9 -am63nd4lQtBU/55oc2PcJOsiv6hy8l4A4Q1OOkNumU4/iXgDmMrzVcydro7B -qkWY+o8aoI2II/EVQQ2lRj6RP4vr93E= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUF -ADA6MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0Eg -U2VjdXJpdHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5 -MjNaMDoxGTAXBgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJT -QSBTZWN1cml0eSAyMDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAt49VcdKA3XtpeafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37 -RqtBaB4Y6lXIL5F4iSj7Jylg/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E -0S1PRsNO3Ng3OTsor8udGuorryGlwSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J -6elhc5SYcSa8LWrg903w8bYqODGBDSnhAMFRD0xS+ARaqn1y07iHKrtjEAMq -s6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2PcYJk5qjEoAAVZkZR73QpXzD -uvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpuAWgXIszACwIDAQABo2Mw -YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAW -gBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NRMKSq6UWuNST6 -/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYcHnmYv/3V -EhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/Zb5g -EydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ -f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJq -aHVOrSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEk -llgVsRch6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kA -pKnXwiJPZ9d37CAFYd4= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJK -UDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0 -eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMw -OTMwMDQyMDQ5WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1 -c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RD -QTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8 -V6UMbXaKL0u/ZPtM7orw8yl89f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpx -xpp9Hp3dfGzGjGdnSj74cbAZJ6kJDKaVv0uMDPpVmDvY6CKhS3E4eayXkmmz -iX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9Ms+k2Y7CI9eNqPPYJayX5HA49LY6 -tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/NQV3Is00qVUarH9oe4kA92819 -uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJxrHty8OVYNEP8Ktw+N/L -TX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0GA1UdDgQWBBSgc0mZ -aNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vGkl3g0dNq -/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfrUj94 -nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 -Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNn -PaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfci -oU+tHXotRSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAi -FL39vmwLAw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJG -STEPMA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENB -MB4XDTAxMDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMC -RkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBD -QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue -+H887dF+2rDNbS82rDTG29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mX -y47vPxVnqIJyY1MPQYx9EJUkoVqlBvqSV536pQHydekfvFYmUk54GWVYVQNY -wBSujHxVX3BbdyMGNpfzJLWaRpXk3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JF -hfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBLqdReLjVQCfOAl/QMF6452F/NM8Ec -yonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIINnvmLVz5MxxftLItyM19yejhW -1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB -/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEB -BQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuXZfsSZ9gqXLar -5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0HDjxVyhbM -p6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VOTzF2 -nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv -kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2y -Ix4wzMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJG -STEPMA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENB -MB4XDTAxMDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMC -RkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBD -QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE -+hY3/Ei9vX+ALTU74W+oZ6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gX -GM2RX/uJ4+q/Tl18GybTdXnt5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQ -TiMofRhj8VQ7Jp12W5dCsv+u8E7s3TmVToMGf+dJQMjFAbJUWmYdPfz56TwK -noG4cPABi+QjVHzIrviQHgCWctRUz2EjvOr7nQKV0ba5cTppCD8PtOFCx4j1 -P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu8nYybieDwnPz3BjotJPqdURr -BGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB -/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEB -BQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zilzqsWuasvfDXL -rNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/3DEIcbCd -jdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvDFNr4 -50kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 -Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkeja -nZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQG -EwJOTDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQD -Ex1TdGFhdCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIz -NDlaFw0xNTEyMTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVT -dGFhdCBkZXIgTmVkZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRl -cmxhbmRlbiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAmNK1URF6gaYUmHFtvsznExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rF -DBKeNVU+LCeIQGv33N0iYfXCxw719tV2U02PjLwYdjeFnejKScfST5gTCaI+ -Ioicf9byEGW07l8Y1Rfj+MX94p2i71MOhXeiD+EwR+4A5zN9RGcaC1Hoi6Ce -UJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+UtFE5A3+y3qcym7RHjm+0Sq7l -r7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3oBmrC1SoLbHuEvVYFy4Zl -kuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAhSQIDAQABo4GRMIGO -MAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDwwOgYIKwYBBQUH -AgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMvcm9vdC1w -b2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA7Jbg -0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k -/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVF -IGzmeafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0 -C5GUR5z6u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3y -nGQI0DvDKcWy7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBp -IzlWYGeQiy52OfsRiJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYV -wSR8MnwDHTuhWEUykw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT -AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD -VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3 -b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENB -MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe -Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE -RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE -ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y -a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTEp -MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w -DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0yAClxgwENv4wB3NrGrTmk -qYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDwTFXlay3HhQswHJJO -gtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8/vhYnvgpjbB7 -zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w -DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy -dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G -CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+W -LDO/jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xR -T3h2oNmsGb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/Ac -ASZ4smZHcFFk ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYT -AkRFMRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYD -VQQKEzFUQyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3 -b3JrcyBHbWJIMSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENB -MSkwJwYJKoZIhvcNAQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAe -Fw05ODAzMDkxMTU5NTlaFw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJE -RTEQMA4GA1UECBMHSGFtYnVyZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UE -ChMxVEMgVHJ1c3RDZW50ZXIgZm9yIFNlY3VyaXR5IGluIERhdGEgTmV0d29y -a3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTEp -MCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVAdHJ1c3RjZW50ZXIuZGUwgZ8w -DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUFLg2N7KBAahwOJ6ZQkmtQ -GwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGwDtf7pBc9r6tpepYn -v68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDWw1Krj10nnGvA -o+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQFMAMBAf8w -DgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3LnRy -dXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G -CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4 -iJIETb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yC -GdHHsbHD2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQS -CdS7kjXvD9s0 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQG -EwJESzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50 -ZXJuZXQgUm9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTda -MEMxCzAJBgNVBAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNV -BAsTFFREQyBJbnRlcm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAxLhAvJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4Nr -XceO+YQwzho7+vvOi20jxsNuZp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaq -HF1j4QeGDmUApy6mcca8uYGoOn0a0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5 -Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc14izbSysseLlJ28TQx5yc5IogCSEW -Vmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGNeGlVRGn1ypYcNIUXJXfi9i8n -mHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcDR0G2l8ktCkEiu7vmpwID -AQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUGA1UdHwReMFwwWqBY -oFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIEludGVybmV0MR0w -GwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTAr -BgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3WjAL -BgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw -HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8w -HQYJKoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUA -A4IBAQBOQ8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540m -gwV5dOy0uaOXwTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKs -LtB9KOy282A4aW8+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7T -mHnaCB4Mb7j4Fifvwm899qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE -64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQ -V0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQG -EwJESzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0w -MzAyMTEwODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQww -CgYDVQQKEwNUREMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSj -hFuHnEz9pPPEXyG9VhDr2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8 -z3sM8W9Hpg1DTeLpHTk0zY0s2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJH -hNlktxmW/OwZ5LKXJk5KTMuPJItUGBxIYXvViGjaXbXqzRowwYCDdlCqT9HU -3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKjdGqPqcNiKXEx5TukYBdedObaE+3p -Hx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+rTpPGWOmlgtt3xDqZsXKVSQTw -tyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B -Af8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkBAQEwgdEwLwYIKwYB -BQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBvc2l0b3J5MIGd -BggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRlciBmcmEg -ZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4x -LiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg -T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEG -A1UdHwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERD -MRQwEgYDVQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYm -aHR0cDovL2NybC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0Q -BCQwIoAPMjAwMzAyMTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0j -BBgwFoAUYLWF7FZkfhIZJ2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4S -GSdnHVAVS3OuO/kSMB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDAN -BgkqhkiG9w0BAQUFAAOCAQEACromJkbTc6gJ82sLMJn9iuFXehHTuJTXCRBu -o7E4A9G28kNBKWKnctj7fAXmMXAnVBhOinxO5dHKjHiIzxvTkIvmI/gLDjND -fZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2YcaaYb7Z8vTd/vuGTJW1v8Aqt -FxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoBmbgGglGBTvH1tJFUuSN6 -AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQYqbsFbS1AoLbrIyi -gfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9BKNDLdr8C2Lq -L19iUw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du -MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBl -cnNvbmFsIEJhc2ljIENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNp -Y0B0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVow -gcsxCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNV -BAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAm -BgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24xITAfBgNV -BAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBDQTEoMCYGCSqGSIb3DQEJARYZ -cGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB -jQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53dXLdjUmbllegeNTK -P1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdKwPQIcOk8RHtQ -fmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7G1sY0b8j -kyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQFAAOB -gQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7 -c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95 -B21P9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du -MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBl -cnNvbmFsIEZyZWVtYWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1m -cmVlbWFpbEB0aGF3dGUuY29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIz -NTk1OVowgdExCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUx -EjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UEChMRVGhhd3RlIENvbnN1bHRp -bmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x -JDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBGcmVlbWFpbCBDQTErMCkGCSqG -SIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhhd3RlLmNvbTCBnzANBgkq -hkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfYDFG26nKRsIRefS0N -j3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5ErHzmj+hND3Ef -QDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVquzgkCGqY -x7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkq -hkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP -MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgC -neSa/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr -5PjRzneigQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du -MRowGAYDVQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBl -cnNvbmFsIFByZW1pdW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXBy -ZW1pdW1AdGhhd3RlLmNvbTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5 -NTlaMIHPMQswCQYDVQQGEwJaQTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIw -EAYDVQQHEwlDYXBlIFRvd24xGjAYBgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5n -MSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9uMSMw -IQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJlbWl1bSBDQTEqMCgGCSqGSIb3 -DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUuY29tMIGfMA0GCSqGSIb3 -DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0VsBd/eJxZRNkERbGw7 -7f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWIEt12TfIa/G8j -Hnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYDZicRFTuq -W/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 -DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH -b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVx -eTBhKXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1 -KzGJ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du -MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy -dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3Rl -IFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl -cnZlckB0aGF3dGUuY29tMB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1 -OVowgc4xCzAJBgNVBAYTAlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQ -BgNVBAcTCUNhcGUgVG93bjEdMBsGA1UEChMUVGhhd3RlIENvbnN1bHRpbmcg -Y2MxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2VydmljZXMgRGl2aXNpb24x -ITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNlcnZlciBDQTEoMCYGCSqGSIb3 -DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNvbTCBnzANBgkqhkiG9w0B -AQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkEVdbQ7xwblRZH7xhI -NTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQug2SBhRz1JPL -lyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMRuHM/qgeN -9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B -AQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI -hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZ -a4JMpAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcU -Qg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3du -MR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2Vy -dGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3Rl -IFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0 -ZS5jb20wHhcNOTYwODAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkG -A1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2Fw -ZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE -CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQ -VGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRz -QHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOkUG7I -/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91yekIYfUGbTBuFRkC -6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCXL+eQbcAoQpnX -TEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGjEzARMA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG7oWD -TSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e -QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdni -TCxZqdq5snUb9kLy78fyGPmJvKP/iiMucEc= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICoTCCAgqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBizELMAkGA1UEBhMC -WkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmls -bGUxDzANBgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmlj -YXRpb24xHzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwHhcNOTcw -MTAxMDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBizELMAkGA1UEBhMCWkExFTAT -BgNVBAgTDFdlc3Rlcm4gQ2FwZTEUMBIGA1UEBxMLRHVyYmFudmlsbGUxDzAN -BgNVBAoTBlRoYXd0ZTEdMBsGA1UECxMUVGhhd3RlIENlcnRpZmljYXRpb24x -HzAdBgNVBAMTFlRoYXd0ZSBUaW1lc3RhbXBpbmcgQ0EwgZ8wDQYJKoZIhvcN -AQEBBQADgY0AMIGJAoGBANYrWHhhRYZT6jR7UZztsOYuGA7+4F+oJ9O0yeB8 -WU4WDnNUYMF/9p8u6TqFJBU820cEY8OexJQaWt9MevPZQx08EHp5JduQ/vBR -5zDWQQD9nyjfeb6Uu522FOMjhdepQeBMpHmwKxqL8vg7ij5FrHGSALSQQZj7 -X+36ty6K+Ig3AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN -AQEEBQADgYEAZ9viwuaHPUCDhjc1fR/OmsMMZiCouqoEiYbC9RAIDb/LogWK -0E02PvTX72nGXuSwlG9KuefeW4i2e9vjJ+V2w/A1wcu1J5szedyQpgCed/r8 -zSeUQhac0xxo7L9c3eWpexAKMnRUEzGLhQOEkbdYATAUOK8oyvyxUBkZCayJ -SdM= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUF -ADCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 -IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw -HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVU -Ti1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0 -ODM5WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgT -AlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVT -RVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVz -dC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNh -dGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZV -hawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAb -GHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZ -NaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hAReYFmnjDRy7rh4 -xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwiP8vv -/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7i -gEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD -AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf -8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0 -LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G -CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXh -i6r/fWRRzwr/vH3YIWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUq -f9FuVSTiuwL7MT++6LzsQCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAf -hZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvP -NximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+ -FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjis -H8SE ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUF -ADCBkzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 -IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw -HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVU -TiAtIERBVEFDb3JwIFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2 -MzBaMIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNh -bHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx -ITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEbMBkGA1UEAxMS -VVROIC0gREFUQUNvcnAgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6E5Qbvfa2gI5lBZMAHryv4g+O -GQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZD0/Ww5y0vpQZY/KmEQrr -U0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK4ESGoE1O1kduSUrL -Z9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykqlXvY8qdOD1R8 -oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulWbfXv33i+ -Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQABo4Gr -MIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT -MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8v -Y3JsLnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUE -IzAhBggrBgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3 -DQEBBQUAA4IBAQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHc -rpY6CiM+iVnJowftGzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuM -FrMOoAyYUJuTqXAJyCyjj98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1 -+XtgHI3zzVAmbQQnmt/VDUVHKWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdO -jtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jF -VkwPDPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUF -ADCBrjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 -IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw -HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVU -Ti1VU0VSRmlyc3QtQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAe -Fw05OTA3MDkxNzI4NTBaFw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJV -UzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD -VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93 -d3cudXNlcnRydXN0LmNvbTE2MDQGA1UEAxMtVVROLVVTRVJGaXJzdC1DbGll -bnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWlsMIIBIjANBgkqhkiG9w0BAQEF -AAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3BYHW8OWX5ShpHornMSMxq -mNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9hVE1eaROaJB7HHqk -kqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6lL8/K2m2qL+us -obNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLmSGHGTPNp -saguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM1tZU -Ot4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws -6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0G -A1UdDgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJ -hkdodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGll -bnRBdXRoZW50aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEF -BQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rk -MPxTbyUkxsrt4jFcKw7u7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK -2lYcYJeA3IKirUq9iiv/Cwm0xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/ -bDCVNy8zEqx/3cfREYxRmLLQo5HQrfafnoOTHh1CuEava2bwm3/q4wMC5QJR -warVNZ1yQAOJujEdxRBoUp7fooXFXAimeOZTT7Hot9MUnpOmw2TjrH5xzbyf -6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gkUSeh1YdV8nuPmD0Wnu51tvjQ -jvLzxq4oW6fw8zYX/MMF08oDSlQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUF -ADCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 -IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw -HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVU -Ti1VU0VSRmlyc3QtSGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5 -MTgxOTIyWjCBlzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQH -Ew5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3 -b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNV -BAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdhcmUwggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn0G2f0v9Y8+efK+wNiVSZuTiZ -FvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJM6Rsl7HoxuzBdXmcRl6N -q9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4aMXcMmgF6sTLjKwEH -OG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNdoI6yqqr2jmmI -BsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqIDsjfPe58 -BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9KsyoUhb -AgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD -VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWG -M2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3 -YXJlLmNybDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUF -BwMGBggrBgEFBQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0o -XnWO6y1n7k57K9cM//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjA -bPLPSbtNk28GpgoiskliCE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59 -Ojg6FEgSxvunOxqNDYJAB+gECJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4f -Fm517zP4029bHpbj4HR3dHuKom4t3XbWOTCC8KucUvIqx69JXn7HaOWCgchq -J/kniCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0q -UZ6B+dQ7XnASfxAynB67nfhmqA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUF -ADCBlTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 -IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEw -HwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVU -Ti1VU0VSRmlyc3QtT2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4 -NDAzNlowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMO -U2FsdCBMYWtlIENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29y -azEhMB8GA1UECxMYaHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR0wGwYDVQQD -ExRVVE4tVVNFUkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r55 -96Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc -/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2 -yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+pKvEHDHd17bR -5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehbkkj7RwvC -bNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUCAwEA -AaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E -FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0 -cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNy -bDApBgNVHSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQw -DQYJKoZIhvcNAQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXF -wfNfLEzIR1pp6ujwNTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T -7/yxSPlrJSUtUbYsbUXBmMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85 -dRNacrACgZ++8A+EVCBibGnU4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U -+CRVX/A0FklmPlBGyWNxODFiuGK581OtbLUrohKqGU8J2l7nk8aOFAj+8DCA -GKCGhU3IfdeLA/5u1fedFqySLKAj5ZyRUh+U3xeUc8OzwcFxBSAAeL0TUh2o -Ps0AH8g= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD -ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu -Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRp -b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv -bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy -NTIyMjM0OFoXDTE5MDYyNTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x -NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24g -QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x -IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3 -DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9YLqdUHAZu9OqNSLwxlBfw -8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+TunRf50sQB1ZaG6m -+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8YTfwggtFzVXSN -dnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0LBwGlN+V -YH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLWI8so -gTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw -nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlD -ZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu -Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRp -b24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNv -bS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYy -NjAwMTk1NFoXDTE5MDYyNjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0 -IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4x -NTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g -QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8x -IDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMIGfMA0GCSqGSIb3 -DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vYdA757tn2VUdZZUcOBVXc -65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9WlmpZdRJEy0kTRxQ -b7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QSv4dk+NoS/zcn -wbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9vUJSZSWI4 -OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTuIYEZ -oDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC -W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8x -CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UE -CxMuQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eTAeFw05NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNV -BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh -c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCB -nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3 -noaACpEO+jglr0aIguVzqKCbJF0NH8xlbgyw0FaEGIeaBpsQoXPftFg5a27B -9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR4k5FVmkfeAKA2txHkSm7NsljXMXg -1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATANBgkqhkiG9w0BAQIFAAOBgQBM -P7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZoEWx8QszznC7EBz8UsA9P -/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5FvjqBUuUfx3CHMjj -t/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89FxlA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcEx -CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE -CxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt -IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU -cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow -gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG -A1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j -LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln -biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq -0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9 -Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSmFc/IReumXY6c -PvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQABMA0G -CSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9Zr -bWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul -uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4i -P/68DzFc6PLZ ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHK -MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV -BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5 -IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD -BgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3 -MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s -IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV -BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg -dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFBy -aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRR -ZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO8ESlV8dAWB6j -Rx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJrKsh -JlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7P -oBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2 -6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHh -v2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQ -BfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N -y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUf -xJM8/XmPBNQ+T+r3ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFM -DSZl4kSAHsef493oCtrspSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5 -SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXV -OBRgmaNL3gaWcSzy27YfpO8/7g== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDnjCCAwegAwIBAgIQK2jUo0aexTsoCas4XX8nIDANBgkqhkiG9w0BAQUF -ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1 -BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX -MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy -dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov -L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAx -IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQC57V56Ondfzl86UvzNZPdxtW9qlsZZklWUXS9bLsER -6iaKy6eBPPZaRN56Ey/9WlHZezcmSsAnPwQDalbBgyzhb1upVFAkSsYuekyh -WzdUJCExH6F4GHansXDaItBq/gdiQMb39pt9DAa4S8co5GYjhFHvRreT2IEz -y+U2rMboBQIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT -CE9DU1AgMS0xMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp -Z24uY29tL3BjYTEuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF -BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j -b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG -CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud -EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAHCQ3bjkvlMX -fH8C6dX3i5mTMWCNfuZgayTvYKzSzpHegG0JpNO4OOVEynJeDS3Bd5y9LAN4 -KY2kpXeH9fErJq3MB2w6VFoo4AnzTQoEytRYaQuns/XdAaXn3PAfusFdkI2z -6k/BEVmXarIrE7HarZehs7GgIFvKMquNzxPwHynD ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL -Ey5DbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y -aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE -BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf -MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZM -JaLtVRKXxaeAufqDwSCg+i8VDXyhYGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvE -erf4Zh+AVPy3wo5ZShRXRtGak75BkQO7FYCTXOvnzAhsPz6zSvz/S2wj1VCC -JkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBAIob -K/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxgJ8pFUs4W7z8GZOeUaHxg -MxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Ncr6Pc5iaAIzy4RHT3 -Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHB -MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNV -BAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4g -LSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24g -VHJ1c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTla -MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6 -BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIElu -Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNp -Z24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA -p4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkf -rbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjwDqL7MWzJ5m+Z -Jwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEAATAN -BgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/ -7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX -rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6x -RnInjBJ7xUS0rg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcox -CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UE -CxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkg -VmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMG -A1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcx -NjIzNTk1OVowgcoxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwg -SW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UE -CxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1 -c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJp -bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY8 -1nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDOJxOeBUebMXoT -2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7C9UT -AJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQ -HgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN -qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVC -YQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekh -ktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf -0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydE -p85EXdQbkJgNHkKUsQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377B -MnMiIYtYgXsVkXq642RIsH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab -5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//jGHyJizNdrDPX -p/naOlXJWBD5qu9ats9LS98q ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDnjCCAwegAwIBAgIQCUYX5h3Y1BygDKBi6HmKpzANBgkqhkiG9w0BAQUF -ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1 -BgNVBAsTLkNsYXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwHhcNMDAwODAxMDAwMDAwWhcNMDQwNzMxMjM1OTU5WjCBpzEX -MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy -dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov -L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAy -IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQDQymMxYX9ENHwFfQs9apDLeUt3Cj9LxyPlwGItfpx+ -PoiHkdCs6E1Jh6KWkIrdBKUCP4yb6Yn+YqDiWr3I3bR45qVCkwhnAcAgTddc -9F3as+M3plIaLExlTYqH2aij8UlUuzxcgFFoxvtJ/wtVqxXd+5rBuR10DbKM -RF2J/J/5gwIDAQABo4IBEDCCAQwwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT -CE9DU1AgMS0yMDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwudmVyaXNp -Z24uY29tL3BjYTIuY3JsMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEIGCCsGAQUF -BwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJpc2lnbi5j -b20vb2NzcC9zdGF0dXMwRAYDVR0gBD0wOzA5BgtghkgBhvhFAQcBATAqMCgG -CCsGAQUFBwIBFhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vUlBBMAkGA1Ud -EwQCMAAwCwYDVR0PBAQDAgeAMA0GCSqGSIb3DQEBBQUAA4GBAB99CW4kRnUE -nPMmm+M5bhfvvL2iG9IChIar0ECXLMRDiDcZayKoA3FQnSDcNmAgmnMtc1Vs -WJsswrQ0LHozQsqR2elDr88e4PXEeqs/cmMeqTfhWzuIsxOGgpBXy1f/9Fa+ -It3jl6jhvCJDwt1N2/aBnpIUnjkPE1TegtjAXjSN ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzEL -MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQL -Ey5DbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y -aXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UE -BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz -cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGf -MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69q -RUCPhAwL0TPZ2RHP7gJYHyX3KqhEBarsAx94f56TuZoAqiN91qyFomNFx3In -zPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/isI19wKTakyYbnsZogy1Olhec9vn2a -/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0GCSqGSIb3DQEBAgUAA4GBALtM -EivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Dolbwdj2wsqFHMc9ikwFPw -TtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzk -uxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcEx -CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE -CxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt -IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU -cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow -gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG -A1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j -LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln -biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM -XtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXX -wc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GV -j0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0G -CSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01U -bSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i -F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo -1KpYoJ2daZH9 ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHK -MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV -BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5 -IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD -BgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3 -MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s -IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV -BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg -dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFBy -aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8bN3O9+MlrlBIwT/A2 -R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2tKmFZpGcmTNDo -vFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGukxUccLwg -TS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBmCC+V -k7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ -Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJ -OxWuimi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my -/uRan2Te2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5f -j267Cz3qWhMeDGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoA -Wii/gt/4uhMdUIaC/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8S -GhJouPtmmRQURVyu565pF4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbb -o27q/a2ywtrvAkcTisDxszGtTxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh -/sVFuq1ruQp6Tk9LhO5L8X3dEQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDojCCAwugAwIBAgIQLpaev7ZibOx76XPM42zBhDANBgkqhkiG9w0BAQUF -ADBfMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1 -BgNVBAsTLkNsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwHhcNMDAwODA0MDAwMDAwWhcNMDQwODAzMjM1OTU5WjCBpzEX -MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy -dXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczov -L3d3dy52ZXJpc2lnbi5jb20vUlBBIChjKTAwMS4wLAYDVQQDEyVDbGFzcyAz -IFB1YmxpYyBQcmltYXJ5IE9DU1AgUmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEB -AQUAA4GNADCBiQKBgQDx5AgOg7t140jluNum8Lmr6Txix141W9ACVBHYydFW -uXZLuat65s269gwE1n7WsAplrE454/H3LaMlOe+wi8++2wxdbnD0B81w9zrA -PjUW7XiMQ8/CJi5H1oZ9nPG+1mcMIiWkymXmH3p4KC8/BdsEIb/hRWb+PLeC -7Vq4FhW5VQIDAQABo4IBFDCCARAwIAYDVR0RBBkwF6QVMBMxETAPBgNVBAMT -CE9DU1AgMS0zMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly9jcmwudmVyaXNp -Z24uY29tL3BjYTMuMS4xLmNybDATBgNVHSUEDDAKBggrBgEFBQcDCTBCBggr -BgEFBQcBAQQ2MDQwMgYIKwYBBQUHMAGmJhYkaHR0cDovL29jc3AudmVyaXNp -Z24uY29tL29jc3Avc3RhdHVzMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQEw -KjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL1JQQTAJ -BgNVHRMEAjAAMAsGA1UdDwQEAwIHgDANBgkqhkiG9w0BAQUFAAOBgQAC9lNj -wKke8tCLMzCPSJtMsFa0g3FKvtxQ2PW24AvbvXhP6c8JNNopSZ0Bc1qRkYJU -LBMK03cjzzf8Y96n4/a3tWlFKEnDkdyqRxypiJksBSqNjYr6YuJatwAgXTnE -KMLL/J6oia5bPY4S6jKy/OsU1wkVGsDNG9W1FU5B1ZbjTg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcEx -CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UE -CxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAt -IEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBU -cnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVow -gcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoG -A1UECxMzQ2xhc3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5j -LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2ln -biBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6 -8OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDMHO0oW369atyzkSTK -QWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtKqsGgtG7rL+VX -xbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwIDAQABMA0G -CSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwjcSGI -L4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y -cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckzt -ImRPT8qAkbYp ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHK -MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNV -BAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5 -IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBD -BgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3 -MTYyMzU5NTlaMIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24s -IEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNV -BAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQg -dXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDQgUHVibGljIFBy -aW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1GQ9Wzsy1HyDkniYl -S+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ+mGuqPKljYXC -KtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0GbdU6LM8BDc -VHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLmNxdL -MEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY -ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDD -Zq3/ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1Wr -IhVZPMq1CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXtt -mhwwjIDLk5Mqg6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csK -vE+MW8VLADsfKoKmfjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluP -QSjA1egtTaRezarZ7c7c2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kP -mF6Z6PDQpLv1U70qzlmwr25/bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr -9Xgn2uf3ZkPznoM+IKrDNWCRzg== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzEL -MAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMu -MS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9y -aXR5MB4XDTk0MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UE -BhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD -VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGb -MA0GCSqGSIb3DQEBAQUAA4GJADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6O -LDfO6zV4ZFQD5YRAUcm/jwjiioII0haGN1XpsSECrXZogZoFokvJSyVmIlZs -iAeP94FZbYQHZXATcXY+m3dM41CJVphIuR2nKRoTLkoRWZweFdVJVCxzOmmC -sZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZIhvcNAQECBQADfgBl3X7hsuyw -4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3YQO2WxZpO8ZECAyIUwxr -l0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc1/p3yjkWWW8O6tO1 -g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDnzCCAwygAwIBAgIRAP9F1SddJPuzwjkkU1fhT94wDQYJKoZIhvcNAQEF -BQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5 -LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5MB4XDTAwMDgwNDAwMDAwMFoXDTA0MDgwMzIzNTk1OVowgZ4x -FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBU -cnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6 -Ly93d3cudmVyaXNpZ24uY29tL1JQQSAoYykwMDElMCMGA1UEAxMcU2VjdXJl -IFNlcnZlciBPQ1NQIFJlc3BvbmRlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEAuFGZZIUO7rMKaPC/Y3YdU/X8oXiMM+6f9L452psPTUepjyDoS0S9 -zs17kNEw6JDEJXuJKN699pMd/7n/krWpjeSuzOLDB4Nqo3IQASdiIqY1Jjkt -ns9gDPxHpNfQQninHWzQy08VpykKtJVFxLHnWgnXOZXYHTWewr2zXcEMSx8C -AwEAAaOCAR0wggEZMCAGA1UdEQQZMBekFTATMREwDwYDVQQDEwhPQ1NQIDEt -NDA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLnZlcmlzaWduLmNvbS9S -U0FTZWN1cmVTZXJ2ZXItcC5jcmwwEwYDVR0lBAwwCgYIKwYBBQUHAwkwQgYI -KwYBBQUHAQEENjA0MDIGCCsGAQUFBzABpiYWJGh0dHA6Ly9vY3NwLnZlcmlz -aWduLmNvbS9vY3NwL3N0YXR1czBEBgNVHSAEPTA7MDkGC2CGSAGG+EUBBwEB -MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LnZlcmlzaWduLmNvbS9SUEEw -CQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwDQYJKoZIhvcNAQEFBQADfgAAsxBT -ZpxJky4xoAJC0lhXfmah/huKYRhQQCweK0Gl1tv/rAgcWgVtAlwqtpZPR9u+ -TtvOzLqGuBjOsRKRX2P380g+zPFNE+RtCZR4AJLLoyCdBgtqoEMHztEZbI8Y -dZqfFzP9qSa44+LewqjEWop/mNYHBmvMVp6GcM7U7w== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDzTCCAzagAwIBAgIQU2GyYK7bcY6nlLMTM/QHCTANBgkqhkiG9w0BAQUF -ADCBwTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTww -OgYDVQQLEzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24g -QXV0aG9yaXR5IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJ -bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlT -aWduIFRydXN0IE5ldHdvcmswHhcNMDAwOTI2MDAwMDAwWhcNMTAwOTI1MjM1 -OTU5WjCBpTEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl -cmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBh -dCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTAwMSwwKgYDVQQD -EyNWZXJpU2lnbiBUaW1lIFN0YW1waW5nIEF1dGhvcml0eSBDQTCBnzANBgkq -hkiG9w0BAQEFAAOBjQAwgYkCgYEA0hmdZ8IAIVlizrQJIkRpivglWtvtDbc2 -fk7gu5Q+kCWHwmFHKdm9VLhjzCx9abQzNvQ3B5rB3UBU/OB4naCTuQk9I1F/ -RMIUdNsKvsvJMDRAmD7Q1yUQgZS9B0+c1lQn3y6ov8uQjI11S7zi6ESHzeZB -CiVu6PQkAsVSD27smHUCAwEAAaOB3zCB3DAPBgNVHRMECDAGAQH/AgEAMEUG -A1UdIAQ+MDwwOgYMYIZIAYb4RQEHFwEDMCowKAYIKwYBBQUHAgEWHGh0dHBz -Oi8vd3d3LnZlcmlzaWduLmNvbS9ycGEwMQYDVR0fBCowKDAmoCSgIoYgaHR0 -cDovL2NybC52ZXJpc2lnbi5jb20vcGNhMy5jcmwwCwYDVR0PBAQDAgEGMEIG -CCsGAQUFBwEBBDYwNDAyBggrBgEFBQcwAaYmFiRodHRwOi8vb2NzcC52ZXJp -c2lnbi5jb20vb2NzcC9zdGF0dXMwDQYJKoZIhvcNAQEFBQADgYEAgnBold+2 -DcIBcBlK0lRWHqzyRUyHuPU163hLBanInTsZIS5wNEqi9YngFXVF5yg3ADQn -Keg3S/LvRJdrF1Eaw1adPBqK9kpGRjeM+sv1ZFo4aC4cw+9wzrhGBha/937n -tag+RaypJXUie28/sJyU58dzq6wf7iWbwBbtt8pb8BQ= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDgDCCAmigAwIBAgICAx4wDQYJKoZIhvcNAQEFBQAwYTELMAkGA1UEBhMC -VVMxDTALBgNVBAoTBFZJU0ExLzAtBgNVBAsTJlZpc2EgSW50ZXJuYXRpb25h -bCBTZXJ2aWNlIEFzc29jaWF0aW9uMRIwEAYDVQQDEwlHUCBSb290IDIwHhcN -MDAwODE2MjI1MTAwWhcNMjAwODE1MjM1OTAwWjBhMQswCQYDVQQGEwJVUzEN -MAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNl -cnZpY2UgQXNzb2NpYXRpb24xEjAQBgNVBAMTCUdQIFJvb3QgMjCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkBcLWqxEDwq2omYXkZAPy/mzdZ -DK9vZBv42pWUJGkzEXDK41Z0ohdXZFwgBuHW73G3O/erwWnQSaSxBNf0V2KJ -XLB1LRckaeNCYOTudNargFbYiCjh+20i/SN8RnNPflRzHqgsVVh1t0zzWkWl -Ahr62p3DRcMiXvOL8WAp0sdftAw6UYPvMPjU58fy+pmjIlC++QU3o63tmsPm -7IgbthknGziLgE3sucfFicv8GjLtI/C1AVj59o/ghalMCXI5Etuz9c9OYmTa -xhkVOmMd6RdVoUwiPDQyRvhlV7or7zaMavrZ2UT0qt2E1w0cslSsMoW0ZA3e -QbuxNMYBhjJk1Z8CAwEAAaNCMEAwHQYDVR0OBBYEFJ59SzS/ca3CBfYDdYDO -qU8axCRMMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqG -SIb3DQEBBQUAA4IBAQAhpXYUVfmtJ3CPPPTVbMjMCqujmAuKBiPFyWHbmQdp -NSYx/scuhMKZYdQN6X0uEyt8joW2hcdLzzW2LEc9zikv2G+fiRxkk78IvXbQ -kIqUs38oW26sTTMs7WXcFsziza6kPWKSBpUmv9+55CCmc2rBvveURNZNbyoL -axhNdBA2aGpawWqn3TYpjLgwi08hPwAuVDAHOrqK5MOeyti12HvOdUVmB/Rt -Ldh6yumJivIj2C/LbgA2T/vwLwHMD8AiZfSr4k5hLQOCfZEWtTDVFN5ex5D8 -ofyrEK9ca3CnB+8phuiyJccg/ybdd+95RBTEvd07xQObdyPsoOy7Wjm1zK0G ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUF -ADBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlz -YSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMT -E1Zpc2EgZUNvbW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0 -MDAxNjEyWjBrMQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UE -CxMmVmlzYSBJbnRlcm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAa -BgNVBAMTE1Zpc2EgZUNvbW1lcmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA -A4IBDwAwggEKAoIBAQCvV95WHm6h2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh -28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4ElpF7sDPwsRROEW+1QK8bRaVK7362 -rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdVZqW1LS7YgFmypw23RuwhY/81 -q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq299yOIzzlr3xF7zSujtF -Wsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0tvz8KPFUgOSwsAGl0 -lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaLdXe6YJ2E5/4t -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUFAAOC -AQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR -zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKht -cbP3LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGI -xHYdkFsd7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBu -YQa7FkKMcPcw++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/ -hC3euiInlhBx6yLt398znM/jra6O1I7mT1GvFpLgXPYHDw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFajCCBFKgAwIBAgIEPLU9RjANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK -EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG -A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EtQmFsdGltb3JlIEltcGxlbWVudGF0 -aW9uMB4XDTAyMDQxMTA3Mzg1MVoXDTIyMDQxMTA3Mzg1MVowZjESMBAGA1UE -ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx -BgNVBAMTKmJlVFJVU1RlZCBSb290IENBLUJhbHRpbW9yZSBJbXBsZW1lbnRh -dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALx+xDmcjOPW -HIb/ymKt4H8wRXqOGrO4x/nRNv8i805qX4QQ+2aBw5R5MdKR4XeOGCrDFN5R -9U+jK7wYFuK13XneIviCfsuBH/0nLI/6l2Qijvj/YaOcGx6Sj8CoCd8JEey3 -fTGaGuqDIQY8n7pc/5TqarjDa1U0Tz0yH92BFODEPM2dMPgwqZfT7syj0B9f -HBOB1BirlNFjw55/NZKeX0Tq7PQiXLfoPX2k+YmpkbIq2eszh+6l/ePazIjm -iSZuxyuC0F6dWdsU7JGDBcNeDsYq0ATdcT0gTlgn/FP7eHgZFLL8kFKJOGJg -B7Sg7KxrUNb9uShr71ItOrL/8QFArDcCAwEAAaOCAh4wggIaMA8GA1UdEwEB -/wQFMAMBAf8wggG1BgNVHSAEggGsMIIBqDCCAaQGDysGAQQBsT4AAAEJKIOR -MTCCAY8wggFIBggrBgEFBQcCAjCCAToaggE2UmVsaWFuY2Ugb24gb3IgdXNl -IG9mIHRoaXMgQ2VydGlmaWNhdGUgY3JlYXRlcyBhbiBhY2tub3dsZWRnbWVu -dCBhbmQgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5k -YXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgdGhlIENlcnRpZmlj -YXRpb24gUHJhY3RpY2UgU3RhdGVtZW50IGFuZCB0aGUgUmVseWluZyBQYXJ0 -eSBBZ3JlZW1lbnQsIHdoaWNoIGNhbiBiZSBmb3VuZCBhdCB0aGUgYmVUUlVT -VGVkIHdlYiBzaXRlLCBodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20vcHJvZHVj -dHNfc2VydmljZXMvaW5kZXguaHRtbDBBBggrBgEFBQcCARY1aHR0cDovL3d3 -dy5iZXRydXN0ZWQuY29tL3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWww -HQYDVR0OBBYEFEU9w6nR3D8kVpgccxiIav+DR+22MB8GA1UdIwQYMBaAFEU9 -w6nR3D8kVpgccxiIav+DR+22MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B -AQUFAAOCAQEASZK8o+6svfoNyYt5hhwjdrCAWXf82n+0S9/DZEtqTg6t8n1Z -dwWtColzsPq8y9yNAIiPpqCy6qxSJ7+hSHyXEHu67RMdmgduyzFiEuhjA6p9 -beP4G3YheBufS0OM00mG9htc9i5gFdPp43t1P9ACg9AYgkHNZTfqjjJ+vWuZ -XTARyNtIVBw74acT02pIk/c9jH8F6M7ziCpjBLjqflh8AXtb4cV97yHgjQ5d -UX2xZ/2jvTg2xvI4hocalmhgRvsoFEdV4aeADGvi6t9NfJBIoDa9CReJf8Py -05yc493EG931t3GzUwWJBtDLSoDByFOQtTwxiBdQn8nEDovYqAJjDQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFLDCCBBSgAwIBAgIEOU99hzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQG -EwJXVzESMBAGA1UEChMJYmVUUlVTVGVkMRswGQYDVQQDExJiZVRSVVNUZWQg -Um9vdCBDQXMxGjAYBgNVBAMTEWJlVFJVU1RlZCBSb290IENBMB4XDTAwMDYy -MDE0MjEwNFoXDTEwMDYyMDEzMjEwNFowWjELMAkGA1UEBhMCV1cxEjAQBgNV -BAoTCWJlVFJVU1RlZDEbMBkGA1UEAxMSYmVUUlVTVGVkIFJvb3QgQ0FzMRow -GAYDVQQDExFiZVRSVVNUZWQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBANS0c3oTCjhVAb6JVuGUntS+WutKNHUbYSnE4a0IYCF4 -SP+00PpeQY1hRIfo7clY+vyTmt9P6j41ffgzeubx181vSUs9Ty1uDoM6GHh3 -o8/n9E1z2Jo7Gh2+lVPPIJfCzz4kUmwMjmVZxXH/YgmPqsWPzGCgc0rXOD8V -cr+il7dw6K/ifhYGTPWqZCZyByWtNfwYsSbX2P8ZDoMbjNx4RWc0PfSvHI3k -bWvtILNnmrRhyxdviTX/507AMhLn7uzf/5cwdO2NR47rtMNE5qdMf1ZD6Li8 -tr76g5fmu/vEtpO+GRg+jIG5c4gW9JZDnGdzF5DYCW5jrEq2I8QBoa2k5MUC -AwEAAaOCAfgwggH0MA8GA1UdEwEB/wQFMAMBAf8wggFZBgNVHSAEggFQMIIB -TDCCAUgGCisGAQQBsT4BAAAwggE4MIIBAQYIKwYBBQUHAgIwgfQagfFSZWxp -YW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVz -IGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0 -ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGFuZCBjZXJ0aWZpY2F0aW9u -IHByYWN0aWNlIHN0YXRlbWVudCwgd2hpY2ggY2FuIGJlIGZvdW5kIGF0IGJl -VFJVU1RlZCdzIHdlYiBzaXRlLCBodHRwczovL3d3dy5iZVRSVVNUZWQuY29t -L3ZhdWx0L3Rlcm1zMDEGCCsGAQUFBwIBFiVodHRwczovL3d3dy5iZVRSVVNU -ZWQuY29tL3ZhdWx0L3Rlcm1zMDQGA1UdHwQtMCswKaAnoCWkIzAhMRIwEAYD -VQQKEwliZVRSVVNUZWQxCzAJBgNVBAYTAldXMB0GA1UdDgQWBBQquZtpLjub -2M3eKjEENGvKBxirZzAfBgNVHSMEGDAWgBQquZtpLjub2M3eKjEENGvKBxir -ZzAOBgNVHQ8BAf8EBAMCAf4wDQYJKoZIhvcNAQEFBQADggEBAHlh26Nebhax -6nZR+csVm8tpvuaBa58oH2U+3RGFktToQb9+M70j5/Egv6S0phkBxoyNNXxl -pE8JpNbYIxUFE6dDea/bow6be3ga8wSGWsb2jCBHOElQBp1yZzrwmAOtlmdE -/D8QDYZN5AA7KXvOOzuZhmElQITcE2K3+spZ1gMe1lMBzW1MaFVA4e5rxyoA -AEiCswoBw2AqDPeCNe5IhpbkdNQ96gFxugR1QKepfzk5mlWXKWWuGVUlBXJH -0+gY3Ljpr0NzARJ0o+FcXxVdJPP55PS2Z2cS52QiivalQaYctmBjRYoQtLpG -EK5BV2VsPyMQPyEQWbfkQN0mDCP2qq4= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGUTCCBTmgAwIBAgIEPLVPQDANBgkqhkiG9w0BAQUFADBmMRIwEAYDVQQK -EwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290IENBczEzMDEG -A1UEAxMqYmVUUlVTVGVkIFJvb3QgQ0EgLSBFbnRydXN0IEltcGxlbWVudGF0 -aW9uMB4XDTAyMDQxMTA4MjQyN1oXDTIyMDQxMTA4NTQyN1owZjESMBAGA1UE -ChMJYmVUUlVTVGVkMRswGQYDVQQLExJiZVRSVVNUZWQgUm9vdCBDQXMxMzAx -BgNVBAMTKmJlVFJVU1RlZCBSb290IENBIC0gRW50cnVzdCBJbXBsZW1lbnRh -dGlvbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALr0RAOqEmq1 -Q+xVkrYwfTVXDNvzDSduTPdQqJtOK2/b9a0cS12zqcH+e0TrW6MFDR/FNCsw -ACnxeECypP869AGIF37m1CbTukzqMvtDd5eHI8XbQ6P1KqNRXuE70mVpflUV -m3rnafdE4Fe1FehmYA8NA/uCjqPoEXtsvsdjDheT389Lrm5zdeDzqrmkwAkb -hepxKYhBMvnwKg5sCfJ0a2ZsUhMfGLzUPvfYbiCeyv78IZTuEyhL11xeDGbu -6bsPwTSxfwh28z0mcMmLJR1iJAzqHHVOwBLkuhMdMCktVjMFu5dZfsZJT4nX -LySotohAtWSSU1Yk5KKghbNekLQSM80CAwEAAaOCAwUwggMBMIIBtwYDVR0g -BIIBrjCCAaowggGmBg8rBgEEAbE+AAACCSiDkTEwggGRMIIBSQYIKwYBBQUH -AgIwggE7GoIBN1JlbGlhbmNlIG9uIG9yIHVzZSBvZiB0aGlzIENlcnRpZmlj -YXRlIGNyZWF0ZXMgYW4gYWNrbm93bGVkZ21lbnQgYW5kIGFjY2VwdGFuY2Ug -b2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29u -ZGl0aW9ucyBvZiB1c2UsIHRoZSBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0 -YXRlbWVudCBhbmQgdGhlIFJlbHlpbmcgUGFydHkgQWdyZWVtZW50LCB3aGlj -aCBjYW4gYmUgZm91bmQgYXQgdGhlIGJlVFJVU1RlZCB3ZWIgc2l0ZSwgaHR0 -cHM6Ly93d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRl -eC5odG1sMEIGCCsGAQUFBwIBFjZodHRwczovL3d3dy5iZXRydXN0ZWQuY29t -L3Byb2R1Y3RzX3NlcnZpY2VzL2luZGV4Lmh0bWwwEQYJYIZIAYb4QgEBBAQD -AgAHMIGJBgNVHR8EgYEwfzB9oHugeaR3MHUxEjAQBgNVBAoTCWJlVFJVU1Rl -ZDEbMBkGA1UECxMSYmVUUlVTVGVkIFJvb3QgQ0FzMTMwMQYDVQQDEypiZVRS -VVNUZWQgUm9vdCBDQSAtIEVudHJ1c3QgSW1wbGVtZW50YXRpb24xDTALBgNV -BAMTBENSTDEwKwYDVR0QBCQwIoAPMjAwMjA0MTEwODI0MjdagQ8yMDIyMDQx -MTA4NTQyN1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFH1w5a44iwY/qhwa -j/nPJDCqhIQWMB0GA1UdDgQWBBR9cOWuOIsGP6ocGo/5zyQwqoSEFjAMBgNV -HRMEBTADAQH/MB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkq -hkiG9w0BAQUFAAOCAQEAKrgXzh8QlOu4mre5X+za95IkrNySO8cgjfKZ5V04 -ocI07cUTWVwFtStPYZuR+0H8/NU8TZh2BvWBfevdkObRVlTa4y0MnxEylCIB -evZsLHRnBMylj44ss0O1lKLQfelifwa+JwGDnjr9iu6YQ0pr17WXOzq/T220 -Y/ozADQuLW2WyXvKmWO6vvT2MKAtmJbpVkQFqUSjYRDrgqFnXbxdJ3Wqiig2 -KjiS2d2kXgClzMx8KSreKJCrt+G2/30lC0DYqjSjLd4H61/OCt3Kfjp9JsFi -aDrmLzfzgYYhxKlkqu9FNtEaZnz46TfW1mG+oq1I59/mdP7TbX3SJdysYlep -9w== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFaDCCBFCgAwIBAgIQO1nHe81bV569N1KsdrSqGjANBgkqhkiG9w0BAQUF -ADBiMRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBS -b290IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1w -bGVtZW50YXRpb24wHhcNMDIwNDExMTExODEzWhcNMjIwNDEyMTEwNzI1WjBi -MRIwEAYDVQQKEwliZVRSVVNUZWQxGzAZBgNVBAsTEmJlVFJVU1RlZCBSb290 -IENBczEvMC0GA1UEAxMmYmVUUlVTVGVkIFJvb3QgQ0EgLSBSU0EgSW1wbGVt -ZW50YXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkujQw -CY5X0LkGLG9uJIAiv11DpvpPrILnHGhwhRujbrWqeNluB0s/6d/16uhUoWGK -Di9pdRi3DOUUjXFumLhV/AyV0Jtu4S2I1DpAa5LxmZZk3tv/ePTulh1HiXzU -vrmIdyM6CeYEnm2qXtLIvZpOGd+J6lsOfsPktPDgaTuID0GQ+NRxQyTBjyZL -O1bp/4xsN+lFrYWMU8NghpBKlsmzVLC7F/AcRdnUGxlkVgoZ98zh/4avflhe -rHqQH8koOUV7orbHnB/ahdQhhlkwk75TMzf270HPM8ercmsl9fNTGwxMLvF1 -S++gh/f+ihXQbNXL+WhTuXAVE8L1LvtDNXUtAgMBAAGjggIYMIICFDAMBgNV -HRMEBTADAQH/MIIBtQYDVR0gBIIBrDCCAagwggGkBg8rBgEEAbE+AAADCSiD -kTEwggGPMEEGCCsGAQUFBwIBFjVodHRwOi8vd3d3LmJldHJ1c3RlZC5jb20v -cHJvZHVjdHNfc2VydmljZXMvaW5kZXguaHRtbDCCAUgGCCsGAQUFBwICMIIB -OhqCATZSZWxpYW5jZSBvbiBvciB1c2Ugb2YgdGhpcyBDZXJ0aWZpY2F0ZSBj -cmVhdGVzIGFuIGFja25vd2xlZGdtZW50IGFuZCBhY2NlcHRhbmNlIG9mIHRo -ZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5kIGNvbmRpdGlv -bnMgb2YgdXNlLCB0aGUgQ2VydGlmaWNhdGlvbiBQcmFjdGljZSBTdGF0ZW1l -bnQgYW5kIHRoZSBSZWx5aW5nIFBhcnR5IEFncmVlbWVudCwgd2hpY2ggY2Fu -IGJlIGZvdW5kIGF0IHRoZSBiZVRSVVNUZWQgd2ViIHNpdGUsIGh0dHA6Ly93 -d3cuYmV0cnVzdGVkLmNvbS9wcm9kdWN0c19zZXJ2aWNlcy9pbmRleC5odG1s -MAsGA1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSp7BR++dlDzFMrFK3P9/BZiUHN -GTAdBgNVHQ4EFgQUqewUfvnZQ8xTKxStz/fwWYlBzRkwDQYJKoZIhvcNAQEF -BQADggEBANuXsHXqDMTBmMpWBcCorSZIry0g6IHHtt9DwSwddUvUQo3neqh0 -3GZCWYez9Wlt2ames30cMcH1VOJZJEnl7r05pmuKmET7m9cqg5c0Lcd9NUwt -NLg+DcTsiCevnpL9UGGCqGAHFFPMZRPB9kdEadIxyKbdLrML3kqNWz2rDcI1 -UqJWN8wyiyiFQpyRQHpwKzg21eFzGh/l+n5f3NacOzDq28BbJ1zTcwfBwvNM -m2+fG8oeqqg4MwlYsq78B+g23FW6L09A/nq9BqaBwZMifIYRCgZ3SK41ty8y -mmFei74pnykkiFY5LKjSq5YDWtRIn7lAhAuYaPsBQ9Yb4gmxlxw= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz -MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw -IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR -dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp -li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D -rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ -WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug -F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU -xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC -Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv -dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw -ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl -IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh -c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy -ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh -Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI -KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T -KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq -y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p -dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD -VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL -MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk -fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 -7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R -cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y -mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW -xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK -SnQ2+Q== ------END CERTIFICATE----- - ------BEGIN CERTIFICATE----- -MIIETzCCAzegAwIBAgIEO63vKTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIzMTQxODE3WhcNMTEw -OTIzMTMxODE3WjB1MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v -LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWdu -ZXQgLSBDQSBLbGFzYSAxMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4SRW9Q58g5DY1Hw7h -gCRKBEdPdGn0MFHsfw7rlu/oQm7IChI/uWd9q5wwo77YojtTDjRnpgZsjqBeynX8T90vFILqsY2K -5CF1OESalwvVr3sZiQX79lisuFKat92u6hBFikFIVxfHHB67Af+g7u0dEHdDW7lwy81MwFYxBTRy -9wIDAQABo4IBbTCCAWkwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwggEEBgNVHSAE -gfwwgfkwgfYGDSsGAQQBvj8CAQoBAQAwgeQwgZoGCCsGAQUFBwICMIGNGoGKQ2VydHlmaWthdCB3 -eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtOiAiUG9saXR5a2EgQ2VydHlmaWthY2ppIGRs -YSBSb290Q0EiLiBDZXJ0eWZpa2F0IHd5c3Rhd2lvbnkgcHJ6ZXogUm9vdENBIHcgaGllcmFyY2hp -aSBDQyBTaWduZXQuMEUGCCsGAQUFBwIBFjlodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0b3Jp -dW0vZG9rdW1lbnR5L3BjX3Jvb3RjYS50eHQwHwYDVR0jBBgwFoAUwJvFIw0C4aZOSGsfAOnjmhQb -sa8wHQYDVR0OBBYEFMODHtVZd1T7TftXR/nEI1zR54njMA0GCSqGSIb3DQEBBQUAA4IBAQBRIHQB -FIGh8Jpxt87AgSLwIEEk4+oGy769u3NtoaR0R3WNMdmt7fXTi0tyTQ9V4AIszxVjhnUPaKnF1KYy -f8Tl+YTzk9ZfFkZ3kCdSaILZAOIrmqWNLPmjUQ5/JiMGho0e1YmWUcMci84+pIisTsytFzVP32/W -+sz2H4FQAvOIMmxB7EJX9AdbnXn9EXZ+4nCqi0ft5z96ZqOJJiCB3vSaoYg+wdkcvb6souMJzuc2 -uptXtR1Xf3ihlHaGW+hmnpcwFA6AoNrom6Vgzk6U1ienx0Cw28BhRSKqzKkyXkuK8gRflZUx84uf -tXncwKJrMiE3lvgOOBITRzcahirLer4c ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIE9zCCA9+gAwIBAgIEPL/xoTANBgkqhkiG9w0BAQUFADB2MQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MSAwHgYDVQQDExdDQyBTaWduZXQgLSBQQ0EgS2xhc2EgMjAeFw0wMjA0MTkxMDI5NTNa -Fw0xNzA0MTgxMjUzMDdaMHUxCzAJBgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4g -eiBvLm8uMSQwIgYDVQQLExtDZW50cnVtIENlcnR5ZmlrYWNqaSBTaWduZXQxHzAdBgNVBAMTFkND -IFNpZ25ldCAtIENBIEtsYXNhIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqgLJu -QqY4yavbSgHg8CyfKTx4BokNSDOVz4eD9vptUr11Kqd06ED1hlH7Sg0goBFAfntNU/QTKwSBaNui -me7C4sSEdgsKrPoAhGb4Mq8y7Ty7RqZz7mkzNMqzL2L2U4yQ2QjvpH8MH0IBqOWEcpSkpwnrCDIm -RoTfd+YlZWKi2JceQixUUYIQ45Ox8+x8hHbvvZdgqtcvo8PW27qoHkp/7hMuJ44kDAGrmxffBXl/ -OBRZp0uO1CSLcMcVJzyr2phKhy406MYdWrtNPEluGs0GFDzd0nrIctiWAO4cmct4S72S9Q6e//0G -O9f3/Ca5Kb2I1xYLj/xE+HgjHX9aD2MhAgMBAAGjggGMMIIBiDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjCB4wYDVR0gBIHbMIHYMIHVBg0rBgEEAb4/AhQKAQEAMIHDMHUGCCsGAQUF -BwICMGkaZ0NlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 -eWthIENlcnR5ZmlrYWNqaSBQQ0EyIC0gQ2VydHlmaWthdHkgVXJ6ZWRvdyBLbGFzeSAyIi4wSgYI -KwYBBQUHAgEWPmh0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9kb2t1bWVudHkva2xh -c2EyL3BjX3BjYTIudHh0MD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly93d3cuc2lnbmV0LnBsL3Jl -cG96eXRvcml1bS9jcmwvcGNhMi5jcmwwHwYDVR0jBBgwFoAUwGxGyl2CfpYHRonE82AVXO08kMIw -HQYDVR0OBBYEFLtFBlILy4HNKVSzvHxBTM0HDowlMA0GCSqGSIb3DQEBBQUAA4IBAQBWTsCbqXrX -hBBev5v5cIuc6gJM8ww7oR0uMQRZoFSqvQUPWBYM2/TLI/f8UM9hSShUVj3zEsSj/vFHagUVmzuV -Xo5u0WK8iaqATSyEVBhADHrPG6wYcLKJlagge/ILA0m+SieyP2sjYD9MUB9KZIEyBKv0429UuDTw -6P7pslxMWJBSNyQxaLIs0SRKsqZZWkc7ZYAj2apSkBMX2Is1oHA+PwkF6jQMwCao/+CndXPUzfCF -6caa9WwW31W26MlXCvSmJgfiTPwGvm4PkPmOnmWZ3CczzhHl4q7ztHFzshJH3sZWDnrWwBFjzz5e -Pr3WHV1wA7EY6oT4zBx+2gT9XBTB ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEUzCCAzugAwIBAgIEPq+qjzANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJQTDE3MDUGA1UE -ChMuQ1ppQyBDZW50cmFzdCBTQSB3IGltaWVuaXUgTWluaXN0cmEgR29zcG9kYXJraTEZMBcGA1UE -AxMQQ1ppQyBDZW50cmFzdCBTQTAeFw0wMzA0MzAxMDUwNTVaFw0wODA0MjgxMDUwNTVaMGgxCzAJ -BgNVBAYTAlBMMR8wHQYDVQQKExZUUCBJbnRlcm5ldCBTcC4geiBvLm8uMR8wHQYDVQQDExZDQyBT -aWduZXQgLSBDQSBLbGFzYSAzMRcwFQYDVQQFEw5OdW1lciB3cGlzdTogNDCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBALVdeOM62cPH2NERFxbS5FIp/HSv3fgesdVsTUFxZbGtE+/E0RMl -KZQJHH9emx7vRYubsi4EOLCjYsCOTFvgGRIpZzx7R7T5c0Di5XFkRU4gjBl7aHJoKb5SLzGlWdoX -GsekVtl6keEACrizV2EafqjI8cnBWY7OxQ1ooLQp5AeFjXg+5PT0lO6TUZAubqjFbhVbxSWjqvdj -93RGfyYE76MnNn4c2xWySD07n7uno06TC0IJe6+3WSX1h+76VsIFouWBXOoM7cxxiLjoqdBVu24+ -P8e81SukE7qEvOwDPmk9ZJFtt1nBNg8a1kaixcljrA/43XwOPz6qnJ+cIj/xywECAwEAAaOCAQow -ggEGMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMDMGA1UdIAEB/wQpMCcwJQYEVR0g -ADAdMBsGCCsGAQUFBwIBFg93d3cuY2VudHJhc3QucGwwgY4GA1UdIwSBhjCBg4AU2a7r85Cp1iJN -W0Ca1LR6VG3996ShZaRjMGExCzAJBgNVBAYTAlBMMTcwNQYDVQQKEy5DWmlDIENlbnRyYXN0IFNB -IHcgaW1pZW5pdSBNaW5pc3RyYSBHb3Nwb2RhcmtpMRkwFwYDVQQDExBDWmlDIENlbnRyYXN0IFNB -ggQ9/0sQMB0GA1UdDgQWBBR7Y8wZkHq0zrY7nn1tFSdQ0PlJuTANBgkqhkiG9w0BAQUFAAOCAQEA -ldt/svO5c1MU08FKgrOXCGEbEPbQxhpM0xcd6Iv3dCo6qugEgjEs9Qm5CwUNKMnFsvR27cJWUvZb -MVcvwlwCwclOdwF6u/QRS8bC2HYErhYo9bp9yuxxzuow2A94c5fPqfVrjXy+vDouchAm6+A5Wjzv -J8wxVFDCs+9iGACmyUWr/JGXCYiQIbQkwlkRKHHlan9ymKf1NvIej/3EpeT8fKr6ywxGuhAfqofW -pg3WJY/RCB4lTzD8vZGNwfMFGkWhJkypad3i9w3lGmDVpsHaWtCgGfd0H7tUtWPkP+t7EjIRCD9J -HYnTR+wbbewc5vOI+UobR15ynGfFIaSIiMTVtQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEejCCA2KgAwIBAgIEP4vk6TANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQ -TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2Vu -dHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBD -QSBLbGFzYSAyMB4XDTAzMTAxNDExNTgyMloXDTE3MDQxODEyNTMwN1owdzELMAkG -A1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6IG8uby4xJDAiBgNV -BAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEhMB8GA1UEAxMYQ0MgU2ln -bmV0IC0gT0NTUCBLbGFzYSAyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCo -VCsaBStblXQYVNthe3dvaCrfvKpPXngh4almm988iIlEv9CVTaAdCfaJNihvA+Vs -Qw8++ix1VqteMQE474/MV/YaXigP0Zr0QB+g+/7PWVlv+5U9Gzp9+Xx4DJay8AoI -iB7Iy5Qf9iZiHm5BiPRIuUXT4ZRbZRYPh0/76vgRsQIDAQABo4IBkjCCAY4wDgYD -VR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMJMEEGA1UdHwQ6MDgwNqA0 -oDKGMGh0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9jcmwva2xhc2Ey -LmNybDCB2AYDVR0gBIHQMIHNMIHKBg4rBgEEAb4/AoFICgwBADCBtzBsBggrBgEF -BQcCAjBgGl5DZXJ0eWZpa2F0IHd5ZGFueSB6Z29kbmllIHogZG9rdW1lbnRlbSAi -UG9saXR5a2EgQ2VydHlmaWthY2ppIC0gQ2VydHlmaWthdHkgcmVzcG9uZGVyb3cg -T0NTUCIuMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnNpZ25ldC5wbC9yZXBvenl0 -b3JpdW0vZG9rdW1lbnR5L3BjX29jc3BfMV8wLnBkZjAfBgNVHSMEGDAWgBS7RQZS -C8uBzSlUs7x8QUzNBw6MJTAdBgNVHQ4EFgQUKEVrOY7cEHvsVgvoyZdytlbtgwEw -CQYDVR0TBAIwADANBgkqhkiG9w0BAQUFAAOCAQEAQrRg5MV6dxr0HU2IsLInxhvt -iUVmSFkIUsBCjzLoewOXA16d2oDyHhI/eE+VgAsp+2ANjZu4xRteHIHoYMsN218M -eD2MLRsYS0U9xxAFK9gDj/KscPbrrdoqLvtPSMhUb4adJS9HLhvUe6BicvBf3A71 -iCNe431axGNDWKnpuj2KUpj4CFHYsWCXky847YtTXDjri9NIwJJauazsrSjK+oXp -ngRS506mdQ7vWrtApkh8zhhWp7duCkjcCo1O8JxqYr2qEW1fXmgOISe010v2mmuv -hHxPyVwoAU4KkOw0nbXZn53yak0is5+XmAjh0wWue44AssHrjC9nUh3mkLt6eQ== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEezCCA2OgAwIBAgIEP4vnLzANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJQ -TDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEfMB0GA1UEAxMWQ0Mg -U2lnbmV0IC0gQ0EgS2xhc2EgMzEXMBUGA1UEBRMOTnVtZXIgd3Bpc3U6IDQwHhcN -MDMxMDE0MTIwODAwWhcNMDgwNDI4MTA1MDU1WjB3MQswCQYDVQQGEwJQTDEfMB0G -A1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBD -ZXJ0eWZpa2FjamkgU2lnbmV0MSEwHwYDVQQDExhDQyBTaWduZXQgLSBPQ1NQIEts -YXNhIDMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM/9GwvARNuCVN+PqZmO -4FqH8vTqhenUyqRkmAVT4YhLu0a9AXeLAYVDu+NTkYzsAUMAfu55rIKHNLlm6WbF -KvLiKKz4p4pbUr+ToPcwl/TDotidloUdBAxDg0SL+PmQqACZDe3seJho2IYf2vDL -/G4TLMbKmNB0mlWFuN0f4fJNAgMBAAGjggGgMIIBnDAOBgNVHQ8BAf8EBAMCB4Aw -EwYDVR0lBAwwCgYIKwYBBQUHAwkwTwYDVR0fBEgwRjBEoEKgQIY+aHR0cDovL3d3 -dy5zaWduZXQucGwva3dhbGlmaWtvd2FuZS9yZXBvenl0b3JpdW0vY3JsL2tsYXNh -My5jcmwwgdgGA1UdIASB0DCBzTCBygYOKwYBBAG+PwKCLAoCAQAwgbcwbAYIKwYB -BQUHAgIwYBpeQ2VydHlmaWthdCB3eWRhbnkgemdvZG5pZSB6IGRva3VtZW50ZW0g -IlBvbGl0eWthIENlcnR5ZmlrYWNqaSAtIENlcnR5ZmlrYXR5IHJlc3BvbmRlcm93 -IE9DU1AiLjBHBggrBgEFBQcCARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5 -dG9yaXVtL2Rva3VtZW50eS9wY19vY3NwXzFfMC5wZGYwHwYDVR0jBBgwFoAUe2PM -GZB6tM62O559bRUnUND5SbkwHQYDVR0OBBYEFG4jnCMvBALRQXtmDn9TyXQ/EKP+ -MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADggEBACXrKG5Def5lpRwmZom3UEDq -bl7y4U3qomG4B+ok2FVZGgPZti+ZgvrenPj7PtbYCUBPsCSTNrznKinoT3gD9lQQ -xkEHwdc6VD1GlFp+qI64u0+wS9Epatrdf7aBnizrOIB4LJd4E2TWQ6trspetjMIU -upyWls1BmYUxB91R7QkTiAUSNZ87s3auhZuG4f0V0JLVCcg2rn7AN1rfMkgxCbHk -GxiQbYWFljl6aatxR3odnnzVUe1I8uoY2JXpmmUcOG4dNGuQYziyKG3mtXCQWvug -5qi9Mf3KUh1oSTKx6HfLjjNl1+wMB5Mdb8LF0XyZLdJM9yIZh7SBRsYm9QiXevY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFGjCCBAKgAwIBAgIEPL7eEDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwNDE4MTQ1NDA4WhcNMjYw -OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v -LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu -ZXQgLSBQQ0EgS2xhc2EgMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM7BrBlbN5ma -M5eg0BOTqoZ+9NBDvU8Lm5rTdrMswFTCathzpVVLK/JD4K3+4oCZ9SRAspEXE4gvwb08ASY6w5s+ -HpRkeJw8YzMFR5kDZD5adgnCAy4vDfIXYZgppXPaTQ8wnfUZ7BZ7Zfa7QBemUIcJIzJBB0UqgtxW -Ceol9IekpBRVmuuSA6QG0Jkm+pGDJ05yj2eQG8jTcBENM7sVA8rGRMyFA4skSZ+D0OG6FS2xC1i9 -JyN0ag1yII/LPx8HK5J4W9MaPRNjAEeaa2qI9EpchwrOxnyVbQfSedCG1VRJfAsE/9tT9CMUPZ3x -W20QjQcSZJqVcmGW9gVsXKQOVLsCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P -AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQEBMIHkMIGaBggrBgEFBQcC -AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 -eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6 -IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z -aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw -OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy -bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUwGxGyl2CfpYHRonE -82AVXO08kMIwDQYJKoZIhvcNAQEFBQADggEBABp1TAUsa+BeVWg4cjowc8yTJ5XN3GvN96GObMkx -UGY7U9kVrLI71xBgoNVyzXTiMNDBvjh7vdPWjpl5SDiRpnnKiOFXA43HvNWzUaOkTu1mxjJsZsan -ot1Xt6j0ZDC+03FjLHdYMyM9kSWp6afb4980EPYZCcSzgM5TOGfJmNii5Tq468VFKrX+52Aou1G2 -2Ohu+EEOlOrG7ylKv1hHUJJCjwN0ZVEIn1nDbrU9FeGCz8J9ihVUvnENEBbBkU37PWqWuHitKQDV -tcwTwJJdR8cmKq3NmkwAm9fPacidQLpaw0WkuGrS+fEDhu1Nhy9xELP6NA9GRTCNxm/dXlcwnmY= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFGjCCBAKgAwIBAgIEPV0tNDANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDIwODE2MTY0OTU2WhcNMjYw -OTIxMTU0MjE5WjB2MQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v -LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MSAwHgYDVQQDExdDQyBTaWdu -ZXQgLSBQQ0EgS2xhc2EgMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALN3LanJtdue -Ne6geWUTFENa+lEuzqELcoqhYB+a/tJcPEkc6TX/bYPzalRRjqs+quMP6KZTU0DixOrV+K7iWaqA -iQ913HX5IBLmKDCrTVW/ZvSDpiBKbxlHfSNuJxAuVT6HdbzK7yAW38ssX+yS2tZYHZ5FhZcfqzPE -OpO94mAKcBUhk6T/ki0evXX/ZvvktwmF3hKattzwtM4JMLurAEl8SInyEYULw5JdlfcBez2Tg6Db -w34hA1A+ckTwhxzecrB8TUe2BnQKOs9vr2cCACpFFcOmPkM0Drtjctr1QHm1tYSqRFRf9VcV5tfC -3P8QqoK4ONjtLPHc9x5NE1uK/FMCAwEAAaOCAbMwggGvMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0P -AQH/BAQDAgEGMIIBBAYDVR0gBIH8MIH5MIH2Bg0rBgEEAb4/AgEKAQECMIHkMIGaBggrBgEFBQcC -AjCBjRqBikNlcnR5ZmlrYXQgd3lzdGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0 -eWthIENlcnR5ZmlrYWNqaSBkbGEgUm9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6 -IFJvb3RDQSB3IGhpZXJhcmNoaWkgQ0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5z -aWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY19yb290Y2EudHh0MEQGA1UdHwQ9MDsw -OaA3oDWGM2h0dHA6Ly93d3cuc2lnbmV0LnBsL3JlcG96eXRvcml1bS9yb290Y2Evcm9vdGNhLmNy -bDAfBgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAdBgNVHQ4EFgQUXvthcPHlH5BgGhlM -ErJNXWlhlgAwDQYJKoZIhvcNAQEFBQADggEBACIce95Mvn710KCAISA0CuHD4aznTU6pLoCDShW4 -7OR+GTpJUm1coTcUqlBHV9mra4VFrBcBuOkHZoBLq/jmE0QJWnpSEULDcH9J3mF0nqO9SM+mWyJG -dsJF/XU/7smummgjMNQXwzQTtWORF+6v5KUbWX85anO2wR+M6YTBWC55zWpWi4RG3vkHFs5Ze2oF -JTlpuxw9ZgxTnWlwI9QR2MvEhYIUMKMOWxw1nt0kKj+5TCNQQGh/VJJ1dsiroGh/io1DOcePEhKz -1Ag52y6Wf0nJJB9yk0sFakqZH18F7eQecQImgZyyeRtsG95leNugB3BXWCW+KxwiBrtQTXv4dTE= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEzzCCA7egAwIBAgIEO6ocGTANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MRswGQYDVQQDExJDQyBTaWduZXQgLSBSb290Q0EwHhcNMDEwOTIwMTY0MjE5WhcNMjYw -OTIxMTU0MjE5WjBxMQswCQYDVQQGEwJQTDEfMB0GA1UEChMWVFAgSW50ZXJuZXQgU3AuIHogby5v -LjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2FjamkgU2lnbmV0MRswGQYDVQQDExJDQyBTaWdu -ZXQgLSBSb290Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrr2vydnNpELfGW3Ks -ARiDhJvwDtUe4AbWev+OfMc3+vA29nX8ZmIwno3gmItjo5DbUCCRiCMq5c9epcGu+kg4a3BJChVX -REl8gVh0ST15rr3RKrSc4VgsvQzl0ZUraeQLl8JoRT5PLsUj3qwF78jUCQVckiiLVcnGfZtFCm+D -CJXliQBDMB9XFAUEiO/DtEBs0B7wJGx7lgJeJpQUcGiaOPjcJDYOk7rNAYmmD2gWeSlepufO8luU -YG/YDxTC4mqhRqfa4MnVO5dqy+ICj2UvUpHbZDB0KfGRibgBYeQP1kuqgIzJN4UqknVAJb0aMBSP -l+9k2fAUdchx1njlbdcbAgMBAAGjggFtMIIBaTAPBgNVHRMBAf8EBTADAQH/MIIBBAYDVR0gBIH8 -MIH5MIH2Bg0rBgEEAb4/AgEKAQEAMIHkMIGaBggrBgEFBQcCAjCBjRqBikNlcnR5ZmlrYXQgd3lz -dGF3aW9ueSB6Z29kbmllIHogZG9rdW1lbnRlbTogIlBvbGl0eWthIENlcnR5ZmlrYWNqaSBkbGEg -Um9vdENBIi4gQ2VydHlmaWthdCB3eXN0YXdpb255IHByemV6IFJvb3RDQSB3IGhpZXJhcmNoaWkg -Q0MgU2lnbmV0LjBFBggrBgEFBQcCARY5aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVt -L2Rva3VtZW50eS9wY19yb290Y2EudHh0MB0GA1UdDgQWBBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAf -BgNVHSMEGDAWgBTAm8UjDQLhpk5Iax8A6eOaFBuxrzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcN -AQEFBQADggEBAGnY5QmYqnnO9OqFOWZxxb25UHRnaRF6IV9aaGit5BZufZj2Tq3v8L3SgE34GOoI -cdRMMG5JEpEU4mN/Ef3oY6Eo+7HfqaPHI4KFmbDSPiK5s+wmf+bQSm0Yq5/h4ZOdcAESlLQeLSt1 -CQk2JoKQJ6pyAf6xJBgWEIlm4RXE4J3324PUiOp83kW6MDvaa1xY976WyInr4rwoLgxVl11LZeKW -ha0RJJxJgw/NyWpKG7LWCm1fglF8JH51vZNndGYq1iKtfnrIOvLZq6bzaCiZm1EurD8HE6P7pmAB -KK6o3C2OXlNfNIgwkDN/cDqk5TYsTkrpfriJPdxXBH8hQOkW89g= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIID/TCCA2agAwIBAgIEP4/gkTANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJQTDEfMB0GA1UE -ChMWVFAgSW50ZXJuZXQgU3AuIHogby5vLjEkMCIGA1UECxMbQ2VudHJ1bSBDZXJ0eWZpa2Fjamkg -U2lnbmV0MR8wHQYDVQQDExZDQyBTaWduZXQgLSBDQSBLbGFzYSAxMB4XDTAzMTAxNzEyMjkwMloX -DTExMDkyMzExMTgxN1owdjELMAkGA1UEBhMCUEwxHzAdBgNVBAoTFlRQIEludGVybmV0IFNwLiB6 -IG8uby4xJDAiBgNVBAsTG0NlbnRydW0gQ2VydHlmaWthY2ppIFNpZ25ldDEgMB4GA1UEAxMXQ0Mg -U2lnbmV0IC0gVFNBIEtsYXNhIDEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJYrISEtSsd -uHajROh5/n7NGrkpYTT9NEaPe9+ucuQ37KxIbfJwXJjgUc1dw4wCkcQ12FJarD1X6mSQ4cfN/60v -LfKI5ZD4nhJTMKlAj1pX9ScQ/MuyvKStCbn5WTkjPhjRAM0tdwXSnzuTEunfw0Oup559y3Iqxg1c -ExflB6cfAgMBAAGjggGXMIIBkzBBBgNVHR8EOjA4MDagNKAyhjBodHRwOi8vd3d3LnNpZ25ldC5w -bC9yZXBvenl0b3JpdW0vY3JsL2tsYXNhMS5jcmwwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQM -MAoGCCsGAQUFBwMIMIHaBgNVHSAEgdIwgc8wgcwGDSsGAQQBvj8CZAoRAgEwgbowbwYIKwYBBQUH -AgIwYxphQ2VydHlmaWthdCB3eXN0YXdpb255IHpnb2RuaWUgeiBkb2t1bWVudGVtICJQb2xpdHlr -YSBDZXJ0eWZpa2FjamkgQ0MgU2lnbmV0IC0gWm5ha293YW5pZSBjemFzZW0iLjBHBggrBgEFBQcC -ARY7aHR0cDovL3d3dy5zaWduZXQucGwvcmVwb3p5dG9yaXVtL2Rva3VtZW50eS9wY190c2ExXzJf -MS5wZGYwHwYDVR0jBBgwFoAUw4Me1Vl3VPtN+1dH+cQjXNHnieMwHQYDVR0OBBYEFJdDwEqtcavO -Yd9u9tej53vWXwNBMAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEFBQADgYEAnpiQkqLCJQYXUrqMHUEz -+z3rOqS0XzSFnVVLhkVssvXc8S3FkJIiQTUrkScjI4CToCzujj3EyfNxH6yiLlMbskF8I31JxIeB -vueqV+s+o76CZm3ycu9hb0I4lswuxoT+q5ZzPR8Irrb51rZXlolR+7KtwMg4sFDJZ8RNgOf7tbA= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIGFTCCBX6gAwIBAgIBEDANBgkqhkiG9w0BAQUFADCBvjELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UE -ChMfU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9z -dG1hc3RlcjEgMB4GA1UEAxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkq -hkiG9w0BCQEWFmhvc3RtYXN0ZXJAc3BpLWluYy5vcmcwHhcNMDYwODE2MjA0NjUy -WhcNMTYwODEzMjA0NjUyWjCBvDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0luZGlh -bmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdhcmUgaW4g -dGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKSG9zdG1hc3RlcjEeMBwGA1UE -AxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MSUwIwYJKoZIhvcNAQkBFhZob3N0bWFz -dGVyQHNwaS1pbmMub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA -uTlCOrOYvCe0Qszlz90rVIQkS2UDa7R+qCTkRE5ipKC+3OZXGgv2EOYk/IOuCE3D -8+tlTAl8MwvmwOHgL0GWnjoluR95narhNiV9Px8xyL2Z8kctwrWXbEii0Ot48VcN -IQMDW5GK8Ww5puMKZr8+bXF2HFzkt8gwaCtrojcF4fLGcm3//bR13CKWbOzacANZ -gAi00pD70ppjJU/uNVOe5HX6x/Id+50G6jwasanEzhteYJdbbHaMqrL4J6XbTwgJ -ZciB0ifOZkwTBvQiRJpTkTWPyn/HptMbJGOwwiNbcgtWV7QVLW1GB3HYVum47Zwp -XcXVM4Fs4XLwfx1Ti87LGdAJJYDS5K1F2prHKW5MsmFLJg61Nd6dZPRDLJLaOPEq -0Jxa1NdfDjJ8rXOIcuLRAozjBui23vUhfOW9z4kpVIg+c+ylV2Oh/7f+fO731P7E -AqsTFmiU7svcvkm2OKslolpnQ+pqGFLM4laQE/Q0kjogm7LiOpRssBW/ZfZ7pPLZ -Ru0/AXrgKwQIM8mLazwlD3wHKPRElhIkxSv4qZ95zgJo6ky/7BpzZ/OAlz3BICbN -WQhW/MBQVFiC6ivhjDq3AzgyykLShB0eIMRN0SBfTy3/aNfIJbqLmTNookXPoSP7 -+mg5OVzVBvDv5ZskWSl8kJB1DzJbN+DOr/i8V3Ugl90CAwEAAaOCAZ0wggGZMB0G -A1UdDgQWBBTON+buqfoMXkWdtvObUS11tnY77DCB6wYDVR0jBIHjMIHggBQHrehB -HX+91r8bgXo/jEuI3gTS+qGBxKSBwTCBvjELMAkGA1UEBhMCVVMxEDAOBgNVBAgT -B0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdh -cmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1hc3RlcjEg -MB4GA1UEAxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkqhkiG9w0BCQEW -Fmhvc3RtYXN0ZXJAc3BpLWluYy5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zARBglg -hkgBhvhCAQEEBAMCAQYwCQYDVR0SBAIwADArBglghkgBhvhCAQ0EHhYcVGlueUNB -IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAhBgNVHREEGjAYgRZob3N0bWFzdGVyQHNw -aS1pbmMub3JnMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQA5HQcqwPE/ -RaN8cb8H1G34rkvSEsj4l8UIivMFEWIKnF3SQT8KVcD7j/eJuhMazwRlTs8Rnu6V -/uTC10w7SS6gELwDqAzR4PiXTzfkW8OJemyQn6JWXKfq2pR1n4fvwEn7htjeNS69 -iFKlFXyE9j2jhGaps1CKHfe1YX0MuwO4Jw== ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIEFTCCA36gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBvjELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0luZGlhbmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UE -ChMfU29mdHdhcmUgaW4gdGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9z -dG1hc3RlcjEgMB4GA1UEAxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkq -hkiG9w0BCQEWFmhvc3RtYXN0ZXJAc3BpLWluYy5vcmcwHhcNMDMwMTE1MTYyOTE3 -WhcNMDcwMTE0MTYyOTE3WjCBvjELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0luZGlh -bmExFTATBgNVBAcTDEluZGlhbmFwb2xpczEoMCYGA1UEChMfU29mdHdhcmUgaW4g -dGhlIFB1YmxpYyBJbnRlcmVzdDETMBEGA1UECxMKaG9zdG1hc3RlcjEgMB4GA1UE -AxMXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJTAjBgkqhkiG9w0BCQEWFmhvc3Rt -YXN0ZXJAc3BpLWluYy5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPB6 -rdoiLR3RodtM22LMcfwfqb5OrJNl7fwmvskgF7yP6sdD2bOfDIXhg9852jhY8/kL -VOFe1ELAL2OyN4RAxk0rliZQVgeTgqvgkOVIBbNwgnjN6mqtuWzFiPL+NXQExq40 -I3whM+4lEiwSHaV+MYxWanMdhc+kImT50LKfkxcdAgMBAAGjggEfMIIBGzAdBgNV -HQ4EFgQUB63oQR1/vda/G4F6P4xLiN4E0vowgesGA1UdIwSB4zCB4IAUB63oQR1/ -vda/G4F6P4xLiN4E0vqhgcSkgcEwgb4xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdJ -bmRpYW5hMRUwEwYDVQQHEwxJbmRpYW5hcG9saXMxKDAmBgNVBAoTH1NvZnR3YXJl -IGluIHRoZSBQdWJsaWMgSW50ZXJlc3QxEzARBgNVBAsTCmhvc3RtYXN0ZXIxIDAe -BgNVBAMTF0NlcnRpZmljYXRpb24gQXV0aG9yaXR5MSUwIwYJKoZIhvcNAQkBFhZo -b3N0bWFzdGVyQHNwaS1pbmMub3JnggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN -AQEEBQADgYEAm/Abn8c2y1nO3fgpAIslxvi9iNBZDhQtJ0VQZY6wgSfANyDOR4DW -iexO/AlorB49KnkFS7TjCAoLOZhcg5FaNiKnlstMI5krQmau1Qnb/vGSNsE/UGms -1ts+QYPUs0KmGEAFUri2XzLy+aQo9Kw74VBvqnxvaaMeY5yMcKNOieY= ------END CERTIFICATE----- diff --git a/gcr/tests/files/cacert.org.cer b/gcr/tests/files/cacert.org.cer Binary files differdeleted file mode 100644 index 719b0ff2..00000000 --- a/gcr/tests/files/cacert.org.cer +++ /dev/null diff --git a/gcr/tests/files/cacert.org.pem b/gcr/tests/files/cacert.org.pem deleted file mode 100644 index e7dfc829..00000000 --- a/gcr/tests/files/cacert.org.pem +++ /dev/null @@ -1,41 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290 -IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB -IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA -Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO -BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi -MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ -ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC -CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ -8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6 -zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y -fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7 -w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc -G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k -epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q -laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ -QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU -fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826 -YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w -ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY -gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe -MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0 -IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy -dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw -czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0 -dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl -aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC -AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg -b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB -ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc -nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg -18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c -gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl -Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY -sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T -SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF -CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum -GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk -zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW -omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD ------END CERTIFICATE----- diff --git a/gcr/tests/files/client.crt b/gcr/tests/files/client.crt Binary files differdeleted file mode 100644 index a4bc2fcc..00000000 --- a/gcr/tests/files/client.crt +++ /dev/null diff --git a/gcr/tests/files/client.key b/gcr/tests/files/client.key deleted file mode 100644 index 206f5272..00000000 --- a/gcr/tests/files/client.key +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEAwSA0Mz92De30Mc0A/P9vzstLERoqGhnwBw0HKbcsQ50KdcYS -cp/Rv2WRPlxpe7kYAzzhqFMInufv1FU2uoYozuNsF1Jf5lR+SolA+E5cPb7SeJhC -Jwf3afPvyTGaOVuLO93d8zUGU74L/741Z/YQCE5FUCO8msc2iQmnc9M1EnVZa14d -5T0/B8aZYcpVzUiC9EUwfTzrTghnNfkJzEiD9vnqDbsDsIE+H8o7+opMMsUU0ZzV -PZqy9j8/f4943rL6V4UdK0JO7tEGL+XiFzNl2fCrcEZPqaeMQ3vBq7azukDTrtJe -KY06RiLl+DCykweLx8laZjIHKlSZAFHPB+bvsQIDAQABAoIBAQCQUI1RYnHIdPFO -qZ+8bvDQ+g8tR30ApjM8QZsBrDRyjg579bhhWVY2jSJdFFdqseTkvoDt9KZzgGQy -Kj9MYOZru3xRbSfmiWsaLbiUFJJPPaIvpa+BVS2oSjX8BYn2pJbF9MRfclc5CsIS -qMNl3XUbj8mx2hKdIpJ5EvLD1adKE4Se6peqSZAmEHONNCsrMrQ0GSQqV3viInJr -tc3kp3HcPffSROWqmc6jAJ77Cs3ApgJavL5RGjx30Kd+dKVq4PXZ+IhWM8dOSput -wcyxEosiP/W2g0rDgNW2mGOVOwa/D5SnOolicHifdV7idjwLAjkyYgvmBMNSsECj -yKBkE0gxAoGBAN8iHMumyvriHuj9bSLZ1bcyYFz7jIwUxpHTT7VqN/j/Y1BoBIBy -ZZLDGMa+ID/brpRHzJQAKSNtbFQ0S1HTSKcFud5OWE8Rp3pQJU+sdeO3pCMWAD1z -Q4ggF07JjTSSnK+4fcXgEN9P2OdfXy7Rj3HFpSahql55Kp5udoUdzUVFAoGBAN2S -krlcEuqsEYjqsCJw5pctIwPMvCM51JgirrdETwSGquMklSrobH0PHMlR67gsA/9I -UGShT0LL4UWYpBn/4xLrLbua5aHIBfQQZp9K6jDZddWS+EFL5JkO/Up4/qM6fUbH -CuweVv1gd6i2Ti35K60mgx6MqVunaB1k8Q9P3Pl9AoGALSVtxha9Qv21W1bLWh3R -C/v5W1baHQ2nD6I9omsXYB3sLjydjI+Y1ZT70lptk/4S2JWeYuOVb0GYhYD/LFMf -hAu4i642V+kuhaTpp7ExOR3S6/ZrngNQSp6TmLFXDKgNY9BkQkEPqN8y971oOMTV -zSM8QxC6s9q4MM4Q1OYuvjECgYEAsO2V1AW95T45Ukd1FktpFlaomyQlJ0vKgyFO -unEFV+vhETfpFTY7SzGCHxAXVh1vo62u5Gwayo/a9qQIhepa/IRnJGNv8luyxU1D -ZPeBQjija0PMkPd1NvNNNuafDuBpoNbX1ev0MqeRZVsN2pAZXE5gbUiNA+8NqEsu -Yre3EFECgYEA13rXE76zZgsefx+2spjqJDUWEmTDd1460xTtxCCgL9dy4rW5bgwo -MvINphSUXOwSkn8Oja/IvpN28zSj9W/ci5wU52P5w4blkBmuj8UoCjP2FN1b1OBa -86mkwVsCYUyyI2apuwrHP77yeb8jXZb+reqSns3hU+HyO/nUTVmnews= ------END RSA PRIVATE KEY----- diff --git a/gcr/tests/files/client.pem b/gcr/tests/files/client.pem deleted file mode 100644 index 04bc8ac7..00000000 --- a/gcr/tests/files/client.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC3DCCAkUCAQkwDQYJKoZIhvcNAQEFBQAwgYYxEzARBgoJkiaJk/IsZAEZFgND -T00xFzAVBgoJkiaJk/IsZAEZFgdFWEFNUExFMR4wHAYDVQQLExVDZXJ0aWZpY2F0 -ZSBBdXRob3JpdHkxFzAVBgNVBAMTDmNhLmV4YW1wbGUuY29tMR0wGwYJKoZIhvcN -AQkBFg5jYUBleGFtcGxlLmNvbTAeFw0xMTAxMTgwNjA0MTFaFw0yMTAxMTUwNjA0 -MTFaMGIxEzARBgoJkiaJk/IsZAEZFgNDT00xFzAVBgoJkiaJk/IsZAEZFgdFWEFN -UExFMQ8wDQYDVQQDEwZDbGllbnQxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFt -cGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMEgNDM/dg3t -9DHNAPz/b87LSxEaKhoZ8AcNBym3LEOdCnXGEnKf0b9lkT5caXu5GAM84ahTCJ7n -79RVNrqGKM7jbBdSX+ZUfkqJQPhOXD2+0niYQicH92nz78kxmjlbizvd3fM1BlO+ -C/++NWf2EAhORVAjvJrHNokJp3PTNRJ1WWteHeU9PwfGmWHKVc1IgvRFMH08604I -ZzX5CcxIg/b56g27A7CBPh/KO/qKTDLFFNGc1T2asvY/P3+PeN6y+leFHStCTu7R -Bi/l4hczZdnwq3BGT6mnjEN7wau2s7pA067SXimNOkYi5fgwspMHi8fJWmYyBypU -mQBRzwfm77ECAwEAATANBgkqhkiG9w0BAQUFAAOBgQA3LuElj2QB9wQvmIxk2Jmb -IPP2/WS8dwPoCv/N3+6nTx8yRsrILf4QsnEbbsxoYO5jW4r9Kt8m8B/M7YgnBDE9 -zlm7JbXKZf2isSm5TyT627Ymzxrzs5d+7o2eS7SN1DB6PyvRh2ye7EMbyEYD8ULi -itDUkYkssNCVivYwVvJoMg== ------END CERTIFICATE----- diff --git a/gcr/tests/files/collabora-ca.cer b/gcr/tests/files/collabora-ca.cer Binary files differdeleted file mode 100644 index 2842c696..00000000 --- a/gcr/tests/files/collabora-ca.cer +++ /dev/null diff --git a/gcr/tests/files/der-certificate-dsa.cer b/gcr/tests/files/der-certificate-dsa.cer Binary files differdeleted file mode 100755 index 024f3c1b..00000000 --- a/gcr/tests/files/der-certificate-dsa.cer +++ /dev/null diff --git a/gcr/tests/files/der-certificate.crt b/gcr/tests/files/der-certificate.crt Binary files differdeleted file mode 100644 index 56fa8491..00000000 --- a/gcr/tests/files/der-certificate.crt +++ /dev/null diff --git a/gcr/tests/files/der-dsa-1024.key b/gcr/tests/files/der-dsa-1024.key Binary files differdeleted file mode 100644 index 61af5251..00000000 --- a/gcr/tests/files/der-dsa-1024.key +++ /dev/null diff --git a/gcr/tests/files/der-key-PBE-MD5-DES.p8 b/gcr/tests/files/der-key-PBE-MD5-DES.p8 Binary files differdeleted file mode 100644 index 71b7d61b..00000000 --- a/gcr/tests/files/der-key-PBE-MD5-DES.p8 +++ /dev/null diff --git a/gcr/tests/files/der-key-PBE-SHA1-3DES.p8 b/gcr/tests/files/der-key-PBE-SHA1-3DES.p8 Binary files differdeleted file mode 100644 index 1c37fe10..00000000 --- a/gcr/tests/files/der-key-PBE-SHA1-3DES.p8 +++ /dev/null diff --git a/gcr/tests/files/der-key-PBE-SHA1-DES.p8 b/gcr/tests/files/der-key-PBE-SHA1-DES.p8 Binary files differdeleted file mode 100644 index 99896139..00000000 --- a/gcr/tests/files/der-key-PBE-SHA1-DES.p8 +++ /dev/null diff --git a/gcr/tests/files/der-key-PBE-SHA1-RC2-40.p8 b/gcr/tests/files/der-key-PBE-SHA1-RC2-40.p8 Binary files differdeleted file mode 100644 index 820926cc..00000000 --- a/gcr/tests/files/der-key-PBE-SHA1-RC2-40.p8 +++ /dev/null diff --git a/gcr/tests/files/der-key-PBE-SHA1-RC4-128.p8 b/gcr/tests/files/der-key-PBE-SHA1-RC4-128.p8 Binary files differdeleted file mode 100644 index 2888450c..00000000 --- a/gcr/tests/files/der-key-PBE-SHA1-RC4-128.p8 +++ /dev/null diff --git a/gcr/tests/files/der-key-dsa.p8 b/gcr/tests/files/der-key-dsa.p8 Binary files differdeleted file mode 100644 index 8b61684e..00000000 --- a/gcr/tests/files/der-key-dsa.p8 +++ /dev/null diff --git a/gcr/tests/files/der-key-encrypted-pkcs5.p8 b/gcr/tests/files/der-key-encrypted-pkcs5.p8 Binary files differdeleted file mode 100644 index 68c6b4a5..00000000 --- a/gcr/tests/files/der-key-encrypted-pkcs5.p8 +++ /dev/null diff --git a/gcr/tests/files/der-key-v2-des.p8 b/gcr/tests/files/der-key-v2-des.p8 Binary files differdeleted file mode 100644 index 4cd80348..00000000 --- a/gcr/tests/files/der-key-v2-des.p8 +++ /dev/null diff --git a/gcr/tests/files/der-key-v2-des3.p8 b/gcr/tests/files/der-key-v2-des3.p8 Binary files differdeleted file mode 100644 index 9e2999c8..00000000 --- a/gcr/tests/files/der-key-v2-des3.p8 +++ /dev/null diff --git a/gcr/tests/files/der-key.p8 b/gcr/tests/files/der-key.p8 Binary files differdeleted file mode 100644 index 16505632..00000000 --- a/gcr/tests/files/der-key.p8 +++ /dev/null diff --git a/gcr/tests/files/der-rsa-1024.key b/gcr/tests/files/der-rsa-1024.key Binary files differdeleted file mode 100644 index 878fda5b..00000000 --- a/gcr/tests/files/der-rsa-1024.key +++ /dev/null diff --git a/gcr/tests/files/dhansak-collabora.cer b/gcr/tests/files/dhansak-collabora.cer Binary files differdeleted file mode 100644 index c411e7d6..00000000 --- a/gcr/tests/files/dhansak-collabora.cer +++ /dev/null diff --git a/gcr/tests/files/email.p12 b/gcr/tests/files/email.p12 Binary files differdeleted file mode 100644 index d45d0f8d..00000000 --- a/gcr/tests/files/email.p12 +++ /dev/null diff --git a/gcr/tests/files/generic-dsa.crt b/gcr/tests/files/generic-dsa.crt Binary files differdeleted file mode 100644 index 5658a20c..00000000 --- a/gcr/tests/files/generic-dsa.crt +++ /dev/null diff --git a/gcr/tests/files/generic-dsa.key b/gcr/tests/files/generic-dsa.key deleted file mode 100644 index cdd7ca54..00000000 --- a/gcr/tests/files/generic-dsa.key +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -MIIBuwIBAAKBgQCdLeaVVA8HNMKFr0UUQe/bj6mJvO+I67hxn/KzCWnMjw9h6vtu -TI06OI4XXmEHCVdUxykTkp1NSaTanoV8seEbJyyUgFQFBVaFOE8xDHp5RZghAKpd -XFP2Yn8wj8y2VYSOveFKXj9ySj9A38nbG8mF0imBXNg/nL/EPCynR7JBVwIVAM1D -KUetENlaaH+QeAO3IwcENMSZAoGBAJFujxH2WB5bU+sjjePwBTRev6qtYzPAXPd+ -srC747afIasS0Q/+pE0Q40bjdGNipf3fs5Cq8s0tYTYeNzAqUej1X5YI7TP+uJyR -L7QdD06pg1BbdaAzSxnnGjf2b25IvPRdxgy1XetgOmT+qA8nXeLROgTLNOQqxG83 -ymuMi/w7AoGAfXLlo8mCQgAGy7y32k/2Onv8LXAL5hcQUEM7WQhHkU2QaXgh7sqm -Ol4vvM97YZi5JIlR0wjP7+dZiJJnYSY5PMaGpAIk7hLGsPbJW6TnozAXwCPli1Xu -ocubvrDWjZ/zSesnO3siGPCIuP97IqVbBKGQG/vJUwFL0ewb/+FUa78CFHgQdcw2 -4vVlnuMrqdmrfXMvzbrw ------END DSA PRIVATE KEY----- diff --git a/gcr/tests/files/generic-dsa.pem b/gcr/tests/files/generic-dsa.pem deleted file mode 100644 index 0d81ef21..00000000 --- a/gcr/tests/files/generic-dsa.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDkjCCAvugAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBhjETMBEGCgmSJomT8ixk -ARkWA0NPTTEXMBUGCgmSJomT8ixkARkWB0VYQU1QTEUxHjAcBgNVBAsTFUNlcnRp -ZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAxMOY2EuZXhhbXBsZS5jb20xHTAbBgkq -hkiG9w0BCQEWDmNhQGV4YW1wbGUuY29tMB4XDTA3MTIyMDE4NDc0N1oXDTA4MDEx -OTE4NDc0N1owbDETMBEGCgmSJomT8ixkARkWA0NPTTEXMBUGCgmSJomT8ixkARkW -B0VYQU1QTEUxFDASBgNVBAMTC0dlbmVyaWMgRFNBMSYwJAYJKoZIhvcNAQkBFhdn -ZW5lcmljLWRzYUBleGFtcGxlLmNvbTCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQCd -LeaVVA8HNMKFr0UUQe/bj6mJvO+I67hxn/KzCWnMjw9h6vtuTI06OI4XXmEHCVdU -xykTkp1NSaTanoV8seEbJyyUgFQFBVaFOE8xDHp5RZghAKpdXFP2Yn8wj8y2VYSO -veFKXj9ySj9A38nbG8mF0imBXNg/nL/EPCynR7JBVwIVAM1DKUetENlaaH+QeAO3 -IwcENMSZAoGBAJFujxH2WB5bU+sjjePwBTRev6qtYzPAXPd+srC747afIasS0Q/+ -pE0Q40bjdGNipf3fs5Cq8s0tYTYeNzAqUej1X5YI7TP+uJyRL7QdD06pg1BbdaAz -SxnnGjf2b25IvPRdxgy1XetgOmT+qA8nXeLROgTLNOQqxG83ymuMi/w7A4GEAAKB -gH1y5aPJgkIABsu8t9pP9jp7/C1wC+YXEFBDO1kIR5FNkGl4Ie7KpjpeL7zPe2GY -uSSJUdMIz+/nWYiSZ2EmOTzGhqQCJO4SxrD2yVuk56MwF8Aj5YtV7qHLm76w1o2f -80nrJzt7IhjwiLj/eyKlWwShkBv7yVMBS9HsG//hVGu/oxAwDjAMBgNVHRMBAf8E -AjAAMA0GCSqGSIb3DQEBBQUAA4GBAPRyHCHjWKKVHZ7wSJQOS/Ve8e4DWFiuP9J8 -X4/sXEg59yWjScy9EovZVj5iELZI6OqUArvwVV6w6tewK0BAed4UGp+TyTHjPuJG -WGxBm2AhtZUlYmpHQ+gA+E9weeFNQWP1QOATmFQ+r18eNH0rUONnR3G0XUYQTgd1 -LgEYxM4t ------END CERTIFICATE----- diff --git a/gcr/tests/files/gnupg-homedir/pubring.gpg b/gcr/tests/files/gnupg-homedir/pubring.gpg Binary files differdeleted file mode 100644 index 10b1372d..00000000 --- a/gcr/tests/files/gnupg-homedir/pubring.gpg +++ /dev/null diff --git a/gcr/tests/files/gnupg-homedir/secring.gpg b/gcr/tests/files/gnupg-homedir/secring.gpg Binary files differdeleted file mode 100644 index 4a21e26c..00000000 --- a/gcr/tests/files/gnupg-homedir/secring.gpg +++ /dev/null diff --git a/gcr/tests/files/gnupg-homedir/trustdb.gpg b/gcr/tests/files/gnupg-homedir/trustdb.gpg Binary files differdeleted file mode 100644 index 3824098b..00000000 --- a/gcr/tests/files/gnupg-homedir/trustdb.gpg +++ /dev/null diff --git a/gcr/tests/files/gnupg-mock/mock-arguments-environ b/gcr/tests/files/gnupg-mock/mock-arguments-environ deleted file mode 100755 index 5282a2f0..00000000 --- a/gcr/tests/files/gnupg-mock/mock-arguments-environ +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -# This script is used with test-gnupg-process -set -euf - -while getopts '1:2:' arg; do - case $arg in - 1) - echo $OPTARG - ;; - 2) - echo $OPTARG - ;; - *) - echo "invalid argument: $arg" - exit 2 - ;; - esac -done - -echo -n $ENVIRON1 >&2 -echo $ENVIRON2 >&2 diff --git a/gcr/tests/files/gnupg-mock/mock-echo b/gcr/tests/files/gnupg-mock/mock-echo deleted file mode 100755 index 7c4e251a..00000000 --- a/gcr/tests/files/gnupg-mock/mock-echo +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# This script is used with test-gnupg-process -set -euf - -while read line; do - echo "$line" -done diff --git a/gcr/tests/files/gnupg-mock/mock-fail-exit b/gcr/tests/files/gnupg-mock/mock-fail-exit deleted file mode 100755 index 4d5634bb..00000000 --- a/gcr/tests/files/gnupg-mock/mock-fail-exit +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -# This script is used with test-gnupg-process -set -euf - -exit $1 diff --git a/gcr/tests/files/gnupg-mock/mock-fail-signal b/gcr/tests/files/gnupg-mock/mock-fail-signal deleted file mode 100755 index decf8a4b..00000000 --- a/gcr/tests/files/gnupg-mock/mock-fail-signal +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# This script is used with test-gnupg-process -set -euf - -echo $1 > /tmp/xxx -kill -s $1 $$ -sleep 5 diff --git a/gcr/tests/files/gnupg-mock/mock-simple-error b/gcr/tests/files/gnupg-mock/mock-simple-error deleted file mode 100755 index 30bb6a97..00000000 --- a/gcr/tests/files/gnupg-mock/mock-simple-error +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -# This script is used with test-gnupg-process -set -euf - -echo -n "line 1: " >&2 -echo "more line 1" >&2 -echo "line 2" >&2 -echo "line 3" >&2
\ No newline at end of file diff --git a/gcr/tests/files/gnupg-mock/mock-simple-output b/gcr/tests/files/gnupg-mock/mock-simple-output deleted file mode 100755 index 0d145fcc..00000000 --- a/gcr/tests/files/gnupg-mock/mock-simple-output +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -# This script is used with test-gnupg-process -set -euf - -echo -n "simple-" -echo -n "outp" -echo "ut"
\ No newline at end of file diff --git a/gcr/tests/files/gnupg-mock/mock-status-and-attribute b/gcr/tests/files/gnupg-mock/mock-status-and-attribute deleted file mode 100755 index abf8607a..00000000 --- a/gcr/tests/files/gnupg-mock/mock-status-and-attribute +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -# This script is used with test-gnupg-process -# Needs to be run with /bin/bash in order to handle two digit -# file descriptor redirects - -set -euf - -SFD= -AFD= - -# Not real 'long' option parsing, but good enough for this -while [ $# -gt 1 ]; do - if [ "$1" = --status-fd ]; then - SFD=$2 - shift - elif [ "$1" = --attribute-fd ]; then - AFD=$2 - shift - fi - shift -done - -# No FD passed :( -if [ -z "$AFD" ]; then - exit 22 -fi -if [ -z "$SFD" ]; then - exit 23 -fi - -echo -n "1lc923g4laoeurc23rc2" >&$AFD -echo "[GNUPG:] SCHEMA one two three four " >&$SFD -echo -n "41lcg2r23c4gr3" >&$AFD diff --git a/gcr/tests/files/gnupg-mock/mock-status-and-output b/gcr/tests/files/gnupg-mock/mock-status-and-output deleted file mode 100755 index 0fd544b4..00000000 --- a/gcr/tests/files/gnupg-mock/mock-status-and-output +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -# This script is used with test-gnupg-process -set -euf - -FD= - -# Not real 'long' option parsing, but good enough for this -while [ $# -gt 1 ]; do - if [ "$1" = --status-fd ]; then - FD=$2 - shift - fi - shift -done - -# No FD passed :( -if [ -z "$FD" ]; then - exit 22 -fi - -echo "Here's some output" -echo "[GNUPG:] SCHEMA one two three four " >&$FD -echo "More output" diff --git a/gcr/tests/files/gnupg-mock/mock-with-homedir b/gcr/tests/files/gnupg-mock/mock-with-homedir deleted file mode 100755 index c537e03a..00000000 --- a/gcr/tests/files/gnupg-mock/mock-with-homedir +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -# This script is used with test-gnupg-process -set -euf - -HOMEDIR= - -# Not real 'long' option parsing, but good enough for this -while [ $# -gt 1 ]; do - if [ "$1" = --homedir ]; then - HOMEDIR=$2 - shift - fi - shift -done - -# No homedir passed :( -if [ -z "$HOMEDIR" ]; then - exit 22 -fi - -echo "DIR: $HOMEDIR" diff --git a/gcr/tests/files/openssh_keys.pub b/gcr/tests/files/openssh_keys.pub deleted file mode 100644 index 00d294bc..00000000 --- a/gcr/tests/files/openssh_keys.pub +++ /dev/null @@ -1,2 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAL4z+ad0ZJYzMOQuGp00UJ+AijKhrPVUEYLcxBmFQonb/KIlLSWJua4Rl9DB4tDj30Y9c/oApqC4n+FIYlUZMSnxmpvcLF6aeXOiHHPvm0EDYjjyVubyYQWI7CROrrzSc+x++ha3TuJEvF3PlKlZmTKKVYEkZNjwFqYysGyPxPalAAAAFQDtDSEF9Gvnv5fQtSbbsp7j78uVBwAAAIAtNpAg/Mbd/E2241enedB9AxAbJWZ5QYnoPe6/zx5dOmU7+qz8mG6tgvF8F7IgXPabuAKslzTDGS3zgaEhWicDS3CIYik2UR8hXdxfovIEqZKZe7u02FCEoXYCEiFUAdzDGzjI7PswgtEJWWNqKeNis3HmDDha9lMkqz/3fLZGXwAAAIEAiaRPYKZDMoJG+aVZ5A3R/m2gl+mYE2MsjPKXuBKcrZ6ItA9BMe4G/An0/+E3A+DuoGxdeNNMF8U9Dy2N8Sch/Ngtg2E/FBo5geljWobJXd1jxmPtF2WAliYJXDdIt6RBVPGL9H/KSjDmBMsVd42wxVJywawzypklVZjSUuWuBMI= dsa-key@example.com -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCs8z2y0cCPYRAPkq8tAt6FC/kdfnR/p8B2ZoY0oiLNt7kQEwJfexgwLqTxWYd2fSDUSSDPrsqAxZAwLLS/eF04kXiJO2VfqAWFpTLNToERHpFF1yZQe26ELTlNNfna7LqfCRvpNDwu6AqndsT3eFt7DWvBDXbbEiTLW21Z2OFAAH/J2iCFn4c0a8Myf7IaMYcy5GG3mpk39kEO4aNV/67U7kfooek24ObwD0vlXzlsi5VZIUFOIUi0UdkNEMCtUWpfkZ1STUlmwp9HVM7xb7/9PESQKDnZdxpB09S9cIjdpDecpDlMDDEbEUECM1PIas3ndhB7gAN1i2JsPHTcXZ1 rsa-key@example.com diff --git a/gcr/tests/files/pem-dsa-1024.key b/gcr/tests/files/pem-dsa-1024.key deleted file mode 100644 index ccb1e7b9..00000000 --- a/gcr/tests/files/pem-dsa-1024.key +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -MIIBuwIBAAKBgQCQ7Atgc1g5x1Tq+PZLsD/DU5jWl3K/rlQAed6i06Yfr/snYwoD -igGj0M1ioQdFpXSifstGL08IhbecYbvpVKYKKWaK1Uu6XAenL9ixEFJJZwsznfLF -nmSkcGTvzwtyNsXHLNVc6zKRdDC+yaAD1OSE+6qE15Vxs41rWslbtz4/ewIVAPoh -ShOFwhv+uq2rJAokMMYH1WJxAoGALeBXUfXa7pfz1DxUWVo+lKCAco8MZsmK6+1X -YvarFVgC2DWerR3h7DakWfvu6kjlm55qjLT1KVk2s8yIGl2VfHM5F14s/+DzDTcR -5DDbZkjC60dKoQpKMpdFBTH/LHxpUSIMnURra2sPACYuHr6zzIYUdqpRjMVVyav5 -5fOQI/wCgYBUc0RR23nU7t8LvOvUO7bLt7hYRgO5VwgAdd0xjrWwJm1LINxe/zdr -38TqKYOx9/AqOe1MYZ7WhxJyn/87fGlq3RttdI9WpLS+xcQ4XlKEI6O4iuZebVUA -+Xg556SGJVmCGJw7T6jZQzjHbw5cr8mjCh7XKLufIJHVlOMlCgnqAAIVAIdvhPcJ -1REI37DL+h8cVpwJxBPs ------END DSA PRIVATE KEY----- diff --git a/gcr/tests/files/pem-pkcs8.key b/gcr/tests/files/pem-pkcs8.key deleted file mode 100644 index 1f0d5edb..00000000 --- a/gcr/tests/files/pem-pkcs8.key +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN ENCRYPTED PRIVATE KEY----- -MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIf4lXzcHXqAICAggA -MBQGCCqGSIb3DQMHBAhV8iKHmoUJDQSCAoDK4fY/dfIzOof1QlYV8mhr0OmhaIAe -aaDz4rER6+OGwq7WQ32ErmHBiJRI8oQRrxy4oHTXx8TR+JxQT1io9V9jjXZCS8HT -Ek0J69pgjPdIUnlZYV1GdJUJq7tWxTKJJFr1tsB0XzgugQLYcui4ikrZ6rHE9PVh -SXFIEbns42xHIvtQ/j3c6ScS63UNpSsKe5pWRNgHUHpjSGPAaZogOdMfStmj3tdN -nIH3mjIM8uisN9nyPV42aziZi5mO9F5JHlNp1H5pDAUWOKkKoXw27MgXnxvSkLAX -HSgpPuK5ejqXu4nkciwHnr4eULV0biwqpmYEWxC4aNuog/t3DoL1gkC74J07jjUU -3gZwxjKsAWfIKnNURsHlBAcYClug5ZWs9ru/4sc27bNV9qRKbHcgGD+nzfTXxZZ2 -BG5eSBVpYT2Jzdkpw8puSHwNW5mQcuY4E+ZEERFsW8q1raPSgYVk5rM8TiVdTD5x -UwQG7ADidVSVTR5KGV8wmonbuDu9b61GgU7VBslEK9Lsd92FO0/u09FF6DgCcICD -yRJ0nM0o9S9FI1lqKoxAdgWyFwrKkBVZ05IDHw+jS6r7D/2irYetPJmVO/dvi87r -aaLvyvzU3nz4LiWHmSl2AgDanjDcxtjGoWR2cc+J0v3r/+VEOctrc5EuAnlhl9Yj -kFcfZDfqthCNb49qNGDgQMGrKTt+Dvrka/ZZxXBN3v96L3K4O32j9c97sZ8LEFaI -RHl91Mx2okjrT9q2+Gef2UR9XEzuFEBRBqxktltlrIQIncn6Xx/TjEvIhf2Dgo4W -isaAwTazyZrzATTWR1JS6Hdm7Eb/nCEHAFmVUbQm0d5BDfKmnRsNaaZK ------END ENCRYPTED PRIVATE KEY----- diff --git a/gcr/tests/files/pem-rsa-enc.key b/gcr/tests/files/pem-rsa-enc.key deleted file mode 100644 index 65439fe6..00000000 --- a/gcr/tests/files/pem-rsa-enc.key +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,24522D4CE5F5CD7B - -2H/8j0HYUya7LWEUxpgjp/LVcCX7yZB7SoREdoJdcqJEBUMWVxU/2OfVB8EZupmy -7YHcnn5v1JwwtmAXAtqM9JGlvNWaRr1m4zDrhJn1fY3tu8YGtMR49IOZmOUBK+X+ -IxWAwaFDqLntuGZZnAmRJtgFVYVABEs5yM9zgoCGDaU4WMK3caD7Jnw8jH5m0nqQ -XiQ1y1dHxFJmAgG0b5h2z7zjQTmmXd3IhXqSqsE/9ryruCCYa0Z7aAN5oAmO89I9 -gOyy3J4h76mTNFfF5btV4Jllwd4LkgGOmm69UxAyUTGzwYJ5gxgB3xFzGBwpVlcu -72PrQCrjZqZ6rj6cTPGUYzcyMtEw3Xd6mFhApqJpVRZwNWUAMMJwHl2oWwKcIxfV -y+OftRX6kc+cunrxCkl9aKuHDoJPEq+/Uh+AEXqir+942Vull0WPyuWUjaPKR1xJ -poYsNfHRWq+klKCggQQL6jwuVbDLhbaXfgaNBQO1XMracgfmnO1PQPw8JSQ5iOkm -Ybt2oHAEnrEWxZGn1PfRq6Z8HAbBlQpfmG7SMJZdQjlndKA6GR+tN5krKfpj6uak -0eklm0Nb0YcDzJ3qqHXxIimK3Kh/WRZ1hVTnX4mS9u3HNQMo5Ov6z8OQN+Q45ffi -ZDFkVwUTEJ+iwmCG7XnxX0v8Bv5LZmAnPu95KQTp4Ds0AZ6Sp+RqxvhnCO25cgWj -+N5jHGzsDk9/Jw7rAHz8pnl3sziNBWdAk5ASPA28HCQQo5peWnWajM3Pk98+/wHY -blTh7gw77gTake6hpiegnhNUXwGm6BXEqmyu7mPW0z5XFRb9W7bpog== ------END RSA PRIVATE KEY----- diff --git a/gcr/tests/files/personal.p12 b/gcr/tests/files/personal.p12 Binary files differdeleted file mode 100644 index 7ae3d05d..00000000 --- a/gcr/tests/files/personal.p12 +++ /dev/null diff --git a/gcr/tests/files/pubring.gpg b/gcr/tests/files/pubring.gpg Binary files differdeleted file mode 100644 index 10b1372d..00000000 --- a/gcr/tests/files/pubring.gpg +++ /dev/null diff --git a/gcr/tests/files/secring.gpg b/gcr/tests/files/secring.gpg Binary files differdeleted file mode 100644 index 4a21e26c..00000000 --- a/gcr/tests/files/secring.gpg +++ /dev/null diff --git a/gcr/tests/files/test-x509-swiss.p7b b/gcr/tests/files/test-x509-swiss.p7b Binary files differdeleted file mode 100755 index d45b9e0e..00000000 --- a/gcr/tests/files/test-x509-swiss.p7b +++ /dev/null diff --git a/gcr/tests/files/unclient.p12 b/gcr/tests/files/unclient.p12 Binary files differdeleted file mode 100644 index 321b4475..00000000 --- a/gcr/tests/files/unclient.p12 +++ /dev/null diff --git a/gcr/tests/files/werner-koch.asc b/gcr/tests/files/werner-koch.asc deleted file mode 100644 index eb70c972..00000000 --- a/gcr/tests/files/werner-koch.asc +++ /dev/null @@ -1,71 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.11 (GNU/Linux) - -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 -/Yn6BAmPF+6YxQo2W98rzq0THS5wKJjXmHw= -=F0ww ------END PGP PUBLIC KEY BLOCK----- diff --git a/gcr/tests/frob-certificate.c b/gcr/tests/frob-certificate.c deleted file mode 100644 index a84dbc7f..00000000 --- a/gcr/tests/frob-certificate.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr/gcr.h" - -#include <gtk/gtk.h> - -#include <unistd.h> -#include <string.h> -#include <errno.h> - -static void -on_parser_parsed (GcrParser *parser, gpointer user_data) -{ - GcrCertificateWidget *details; - GtkDialog *dialog = GTK_DIALOG (user_data); - - details = g_object_new (GCR_TYPE_CERTIFICATE_WIDGET, - "attributes", gcr_parser_get_parsed_attributes (parser), - NULL); - - gtk_widget_show (GTK_WIDGET (details)); - gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)), GTK_WIDGET (details)); - - gtk_container_set_border_width (GTK_CONTAINER (dialog), 20); -} - -static void -test_certificate (const gchar *path) -{ - GcrParser *parser; - GError *err = NULL; - guchar *data; - gsize n_data; - GtkWidget *dialog; - - if (!g_file_get_contents (path, (gchar**)&data, &n_data, NULL)) - g_error ("couldn't read file: %s", path); - - dialog = gtk_dialog_new (); - g_object_ref_sink (dialog); - - parser = gcr_parser_new (); - g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), dialog); - if (!gcr_parser_parse_data (parser, data, n_data, &err)) - g_error ("couldn't parse data: %s", err->message); - - g_object_unref (parser); - g_free (data); - - gtk_widget_show (dialog); - g_signal_connect (dialog, "delete-event", G_CALLBACK (gtk_main_quit), NULL); - gtk_main (); - - g_object_unref (dialog); -} - -int -main(int argc, char *argv[]) -{ - gtk_init (&argc, &argv); - g_set_prgname ("frob-certificate"); - - if (argc > 1) - test_certificate (argv[1]); - else - test_certificate (SRCDIR "/files/der-certificate.crt"); - - return 0; -} diff --git a/gcr/tests/frob-combo-selector.c b/gcr/tests/frob-combo-selector.c deleted file mode 100644 index fd9fc868..00000000 --- a/gcr/tests/frob-combo-selector.c +++ /dev/null @@ -1,95 +0,0 @@ - -#include "config.h" - -#include "gcr/gcr.h" - -#include <gtk/gtk.h> - -#include <unistd.h> -#include <string.h> -#include <errno.h> - -static void -on_parser_parsed (GcrParser *parser, gpointer user_data) -{ - GcrSimpleCollection *collection = user_data; - GcrRenderer *renderer; - - renderer = gcr_renderer_create (gcr_parser_get_parsed_label (parser), - gcr_parser_get_parsed_attributes (parser)); - - if (renderer) { - gcr_simple_collection_add (collection, G_OBJECT (renderer)); - g_object_unref (renderer); - } -} - -static void -add_to_selector (GcrParser *parser, const gchar *path) -{ - GError *err = NULL; - guchar *data; - gsize n_data; - - if (!g_file_get_contents (path, (gchar**)&data, &n_data, NULL)) - g_error ("couldn't read file: %s", path); - - if (!gcr_parser_parse_data (parser, data, n_data, &err)) - g_error ("couldn't parse data: %s", err->message); - - g_free (data); -} - -int -main (int argc, char *argv[]) -{ - GcrCollection *collection; - GcrComboSelector *selector; - GtkDialog *dialog; - GcrParser *parser; - GObject *selected; - int i; - - gtk_init (&argc, &argv); - - dialog = GTK_DIALOG (gtk_dialog_new ()); - g_object_ref_sink (dialog); - - collection = gcr_simple_collection_new (); - selector = gcr_combo_selector_new (collection); - - gtk_widget_show (GTK_WIDGET (selector)); - gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)), GTK_WIDGET (selector)); - - gtk_window_set_default_size (GTK_WINDOW (dialog), 550, 400); - gtk_container_set_border_width (GTK_CONTAINER (dialog), 20); - - parser = gcr_parser_new (); - g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), collection); - - if (argc == 1) { - add_to_selector (parser, "files/ca-certificates.crt"); - } else { - for (i = 1; i < argc; ++i) - add_to_selector (parser, argv[i]); - } - - g_object_unref (parser); - g_object_unref (collection); - - gtk_dialog_run (dialog); - - selected = gcr_combo_selector_get_selected (selector); - if (selected == NULL) { - g_print ("nothing selected\n"); - } else { - gchar *label; - g_object_get (selected, "label", &label, NULL); - g_print ("selected: %s\n", label); - } - - gtk_widget_destroy (GTK_WIDGET (dialog)); - g_object_unref (dialog); - - return 0; -} diff --git a/gcr/tests/frob-gnupg-selector.c b/gcr/tests/frob-gnupg-selector.c deleted file mode 100644 index 444483ee..00000000 --- a/gcr/tests/frob-gnupg-selector.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr/gcr.h" -#include "gcr/gcr-gnupg-collection.h" -#include "gcr/gcr-gnupg-key.h" -#include "gcr/gcr-list-selector-private.h" -#include "gcr/gcr-live-search.h" - -#include <gtk/gtk.h> - -#include <unistd.h> -#include <string.h> -#include <errno.h> - -static void -on_collection_loaded (GObject *source, GAsyncResult *result, gpointer unused) -{ - GError *error = NULL; - - _gcr_gnupg_collection_load_finish (GCR_GNUPG_COLLECTION (source), result, &error); - if (error) { - g_warning ("collection load failed: %s", error->message); - g_clear_error (&error); - } -} - -int -main (int argc, char *argv[]) -{ - GcrCollection *collection; - GcrListSelector *selector; - GtkWidget *scroll; - GtkDialog *dialog; - GtkWidget *search; - GtkBox *box; - - gtk_init (&argc, &argv); - - dialog = GTK_DIALOG (gtk_dialog_new ()); - g_object_ref_sink (dialog); - - collection = _gcr_gnupg_collection_new (NULL); - selector = gcr_list_selector_new (collection); - search = _gcr_live_search_new (GTK_WIDGET (selector)); - _gcr_list_selector_set_live_search (selector, GCR_LIVE_SEARCH (search)); - - scroll = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_ETCHED_IN); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (selector)); - - box = GTK_BOX (gtk_dialog_get_content_area (dialog)); - gtk_box_pack_start (box, GTK_WIDGET (scroll), TRUE, TRUE, 0); - gtk_box_pack_end (box, search, FALSE, TRUE, 0); - - gtk_widget_show (GTK_WIDGET (selector)); - gtk_widget_show (scroll); - - _gcr_gnupg_collection_load_async (GCR_GNUPG_COLLECTION (collection), NULL, - on_collection_loaded, NULL); - - gtk_window_set_default_size (GTK_WINDOW (dialog), 550, 400); - gtk_container_set_border_width (GTK_CONTAINER (dialog), 20); - - g_object_unref (collection); - - gtk_dialog_run (dialog); - gtk_widget_destroy (GTK_WIDGET (dialog)); - g_object_unref (dialog); - - return 0; -} diff --git a/gcr/tests/frob-key.c b/gcr/tests/frob-key.c deleted file mode 100644 index 3eedb493..00000000 --- a/gcr/tests/frob-key.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr/gcr.h" - -#include <gtk/gtk.h> - -#include <unistd.h> -#include <string.h> -#include <errno.h> - -static void -on_parser_parsed (GcrParser *parser, gpointer unused) -{ - GcrKeyWidget *details; - GtkDialog *dialog; - - dialog = GTK_DIALOG (gtk_dialog_new ()); - g_object_ref_sink (dialog); - - details = gcr_key_widget_new (gcr_parser_get_parsed_attributes (parser)); - gtk_widget_show (GTK_WIDGET (details)); - gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)), GTK_WIDGET (details)); - - gtk_window_set_default_size (GTK_WINDOW (dialog), 550, 400); - gtk_container_set_border_width (GTK_CONTAINER (dialog), 20); - gtk_dialog_run (dialog); - - g_object_unref (dialog); - g_object_unref (details); -} - -static void -test_key (const gchar *path) -{ - GcrParser *parser; - GError *err = NULL; - guchar *data; - gsize n_data; - - if (!g_file_get_contents (path, (gchar**)&data, &n_data, NULL)) - g_error ("couldn't read file: %s", path); - - parser = gcr_parser_new (); - g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), NULL); - if (!gcr_parser_parse_data (parser, data, n_data, &err)) - g_error ("couldn't parse data: %s", err->message); - - g_object_unref (parser); - g_free (data); -} - -int -main(int argc, char *argv[]) -{ - gtk_init (&argc, &argv); - g_set_prgname ("frob-key"); - - if (argc > 1) - test_key (argv[1]); - else - test_key (SRCDIR "/files/pem-dsa-1024.key"); - - return 0; -} diff --git a/gcr/tests/frob-openpgp.c b/gcr/tests/frob-openpgp.c deleted file mode 100644 index b83305af..00000000 --- a/gcr/tests/frob-openpgp.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr/gcr.h" -#include "gcr/gcr-openpgp.h" -#include "gcr/gcr-record.h" - -#include "egg/egg-armor.h" - -static void -on_packet_print_records (GPtrArray *records, - const guchar *packet, - gsize n_packet, - gpointer user_data) -{ - gchar *string; - guint i; - - for (i = 0; i < records->len; i++) { - string = _gcr_record_format (records->pdata[i]); - g_print ("%s\n", string); - g_free (string); - } -} - -static gboolean -parse_binary (gconstpointer contents, - gsize length) -{ - guint packets; - - packets = _gcr_openpgp_parse (contents, length, - GCR_OPENPGP_PARSE_KEYS | - GCR_OPENPGP_PARSE_ATTRIBUTES, - on_packet_print_records, NULL); - - return (packets > 0); -} - -static void -on_armor_parsed (GQuark type, - const guchar *data, - gsize n_data, - const gchar *outer, - gsize n_outer, - GHashTable *headers, - gpointer user_data) -{ - const gchar *value; - gboolean *result = user_data; - - value = g_hash_table_lookup (headers, "Version"); - g_assert_cmpstr (value, ==, "GnuPG v1.4.11 (GNU/Linux)"); - - *result = parse_binary (data, n_data); -} - -static gboolean -parse_armor_or_binary (gconstpointer contents, - gsize length) -{ - gboolean result; - guint parts; - - parts = egg_armor_parse (contents, length, on_armor_parsed, &result); - if (parts == 0) - result = parse_binary (contents, length); - return result; -} - -int -main(int argc, char *argv[]) -{ - GError *error = NULL; - gchar *contents; - gsize length; - int ret; - - g_set_prgname ("frob-openpgp"); - - if (argc != 2) { - g_printerr ("usage: frob-openpgp filename\n"); - return 2; - } - - if (!g_file_get_contents (argv[1], &contents, &length, &error)) { - g_printerr ("frob-openpgp: couldn't read file: %s: %s", argv[1], error->message); - g_error_free (error); - return 1; - } - - ret = 0; - if (!parse_armor_or_binary (contents, length)) { - g_printerr ("frob-openpgp: no openpgp data found in data"); - ret = 1; - } - - g_free (contents); - return ret; -} diff --git a/gcr/tests/frob-parser.c b/gcr/tests/frob-parser.c deleted file mode 100644 index 2459a10a..00000000 --- a/gcr/tests/frob-parser.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr/gcr-base.h" - -#include <unistd.h> -#include <string.h> -#include <errno.h> - -static gboolean -dump_certificate (GckAttributes *attrs, const gchar *filename) -{ - GckAttribute *attr; - GcrCertificate *cert; - gchar *subject; - gulong klass; - - if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &klass) || - klass != CKO_CERTIFICATE) - return FALSE; - - attr = gck_attributes_find (attrs, CKA_VALUE); - if (!attr) - return FALSE; - - cert = gcr_simple_certificate_new_static (attr->value, attr->length); - subject = gcr_certificate_get_subject_dn (cert); - g_print ("%s: parsed certificate: %s\n", filename, subject); - g_free (subject); - g_object_unref (cert); - - return TRUE; -} - -static void -on_parser_parsed (GcrParser *parser, gpointer user_data) -{ - GckAttributes *attrs; - const gchar **pointer_filename = (const gchar**)user_data; - - attrs = gcr_parser_get_parsed_attributes (parser); - g_return_if_fail (attrs); - - if (!dump_certificate (attrs, *pointer_filename)) - g_print ("%s: parsed %s\n", *pointer_filename, - gcr_parser_get_parsed_description (parser)); -} - -int -main(int argc, char *argv[]) -{ - GcrParser *parser; - GError *error = NULL; - gchar *contents; - gsize len; - GDir *dir; - const gchar *filename; - gchar *path; - - g_type_init (); - g_set_prgname ("frob-parser"); - - if (argc != 2) { - g_printerr ("usage: frob-parser directory\n"); - return 2; - } - - dir = g_dir_open (argv[1], 0, &error); - if (!dir) { - g_printerr ("couldn't list directory: %s: %s\n", argv[1], error->message); - g_clear_error (&error); - return 1; - } - - parser = gcr_parser_new (); - g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), &filename); - - for (;;) { - filename = g_dir_read_name (dir); - if (!filename) - break; - if (filename[0] == '.') - continue; - - path = g_build_filename (argv[1], filename, NULL); - g_file_get_contents (path, &contents, &len, &error); - g_free (path); - - if (error) { - g_printerr ("%s: couldn't read file: %s\n", filename, error->message); - g_clear_error (&error); - continue; - } - - gcr_parser_parse_data (parser, (const guchar *)contents, len, &error); - g_free (contents); - - if (error) { - g_warning ("%s: couldn't parse: %s\n", filename, error->message); - g_clear_error (&error); - } - - g_print ("%s: finished parsing\n", filename); - } - - g_dir_close (dir); - g_object_unref (parser); - - return 0; -} diff --git a/gcr/tests/frob-tree-selector.c b/gcr/tests/frob-tree-selector.c deleted file mode 100644 index 313781e6..00000000 --- a/gcr/tests/frob-tree-selector.c +++ /dev/null @@ -1,208 +0,0 @@ - -#include "config.h" - -#include "gcr/gcr.h" - -#include <gtk/gtk.h> - -#include <unistd.h> -#include <string.h> -#include <errno.h> - -#define TEST_TYPE_COLLECTION (test_collection_get_type ()) -#define TEST_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_COLLECTION, TestCollection)) -#define TEST_IS_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_COLLECTION)) - -typedef struct _TestCollection TestCollection; -typedef struct _TestCollectionClass TestCollectionClass; -typedef struct _TestCollectionPrivate TestCollectionPrivate; - -struct _TestCollection { - GcrSimpleCollection parent; - gchar *label; -}; - -struct _TestCollectionClass { - GcrSimpleCollectionClass parent_class; -}; - -GType test_collection_get_type (void) G_GNUC_CONST; - -enum { - PROP_0, - PROP_LABEL, -}; - -G_DEFINE_TYPE (TestCollection, test_collection, GCR_TYPE_SIMPLE_COLLECTION); - -static GHashTable *all_collections = NULL; - -static void -test_collection_init (TestCollection *self) -{ - -} - -static void -test_collection_finalize (GObject *obj) -{ - TestCollection *self = TEST_COLLECTION (obj); - g_free (self->label); - g_hash_table_remove (all_collections, self); - G_OBJECT_CLASS (test_collection_parent_class)->finalize (obj); -} - -static void -test_collection_get_property (GObject *obj, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - TestCollection *self = TEST_COLLECTION (obj); - switch (prop_id) { - case PROP_LABEL: - g_value_set_string (value, self->label); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec); - break; - } -} - -static void -test_collection_class_init (TestCollectionClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gobject_class->get_property = test_collection_get_property; - gobject_class->finalize = test_collection_finalize; - - g_object_class_install_property (gobject_class, PROP_LABEL, - g_param_spec_string ("label", "label", "label", NULL, G_PARAM_READABLE)); -} - -static GcrSimpleCollection * -test_collection_instance (const gchar *label) -{ - TestCollection *collection = NULL; - - g_assert (label); - - if (!all_collections) { - all_collections = g_hash_table_new (g_str_hash, g_str_equal); - } else { - collection = g_hash_table_lookup (all_collections, label); - if (collection != NULL) - return g_object_ref (collection); - } - - collection = g_object_new (TEST_TYPE_COLLECTION, NULL); - collection->label = g_strdup (label); - g_hash_table_insert (all_collections, collection->label, collection); - return GCR_SIMPLE_COLLECTION (collection); -} - -static void -on_parser_parsed (GcrParser *parser, gpointer user_data) -{ - GcrSimpleCollection *collection = user_data; - GcrSimpleCollection *testcol; - GcrRenderer *renderer; - gchar *group; - - renderer = gcr_renderer_create (gcr_parser_get_parsed_label (parser), - gcr_parser_get_parsed_attributes (parser)); - if (renderer == NULL) - return; - - if (GCR_IS_CERTIFICATE (renderer)) - group = gcr_certificate_get_subject_part (GCR_CERTIFICATE (renderer), "O"); - else - group = g_strdup (G_OBJECT_TYPE_NAME (renderer)); - - - testcol = test_collection_instance (group); - if (!gcr_simple_collection_contains (collection, G_OBJECT (testcol))) - gcr_simple_collection_add (collection, G_OBJECT (testcol)); - - gcr_simple_collection_add (GCR_SIMPLE_COLLECTION (testcol), G_OBJECT (renderer)); - g_object_unref (renderer); - g_object_unref (testcol); - g_free (group); -} - -static void -add_to_selector (GcrParser *parser, const gchar *path) -{ - GError *err = NULL; - guchar *data; - gsize n_data; - - if (!g_file_get_contents (path, (gchar**)&data, &n_data, NULL)) - g_error ("couldn't read file: %s", path); - - if (!gcr_parser_parse_data (parser, data, n_data, &err)) - g_error ("couldn't parse data: %s", err->message); - - g_free (data); -} - -int -main (int argc, char *argv[]) -{ - GcrCollection *collection; - GcrTreeSelector *selector; - GtkDialog *dialog; - GcrParser *parser; - GtkWidget *scroll; - GList *selected, *l; - int i; - - gtk_init (&argc, &argv); - - dialog = GTK_DIALOG (gtk_dialog_new ()); - g_object_ref_sink (dialog); - - collection = gcr_simple_collection_new (); - selector = gcr_tree_selector_new (collection, GCR_CERTIFICATE_COLUMNS); - - scroll = gtk_scrolled_window_new (NULL, NULL); - gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_ETCHED_IN); - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - gtk_container_add (GTK_CONTAINER (scroll), GTK_WIDGET (selector)); - gtk_widget_show_all (scroll); - - gtk_widget_show (GTK_WIDGET (selector)); - gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (dialog)), GTK_WIDGET (scroll), TRUE, TRUE, 0); - - gtk_window_set_default_size (GTK_WINDOW (dialog), 550, 400); - gtk_container_set_border_width (GTK_CONTAINER (dialog), 20); - - parser = gcr_parser_new (); - g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), collection); - - if (argc == 1) { - add_to_selector (parser, SRCDIR "/files/ca-certificates.crt"); - } else { - for (i = 1; i < argc; ++i) - add_to_selector (parser, argv[i]); - } - - g_object_unref (parser); - g_object_unref (collection); - - gtk_dialog_run (dialog); - - selected = gcr_tree_selector_get_selected (selector); - for (l = selected; l; l = g_list_next (l)) { - gchar *label; - g_object_get (l->data, "label", &label, NULL); - g_print ("selected: %s\n", label); - g_free (label); - } - g_list_free (selected); - - gtk_widget_destroy (GTK_WIDGET (dialog)); - g_object_unref (dialog); - - return 0; -} diff --git a/gcr/tests/frob-unlock-options.c b/gcr/tests/frob-unlock-options.c deleted file mode 100644 index fdcf116e..00000000 --- a/gcr/tests/frob-unlock-options.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2010 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr/gcr.h" - -#include <gtk/gtk.h> - -#include <unistd.h> -#include <string.h> -#include <errno.h> - -static void -test_unlock_options (void) -{ - GcrUnlockOptionsWidget *unlock; - GtkDialog *dialog; - - dialog = GTK_DIALOG (gtk_dialog_new ()); - g_object_ref_sink (dialog); - - unlock = GCR_UNLOCK_OPTIONS_WIDGET (gcr_unlock_options_widget_new ()); - gtk_widget_show (GTK_WIDGET (unlock)); - gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (dialog)), GTK_WIDGET (unlock)); - - gcr_unlock_options_widget_set_sensitive (unlock, GCR_UNLOCK_OPTION_IDLE, FALSE, - "This is a test of the tooltip."); - gcr_unlock_options_widget_set_sensitive (unlock, GCR_UNLOCK_OPTION_ALWAYS, TRUE, NULL); - gcr_unlock_options_widget_set_label (unlock, GCR_UNLOCK_OPTION_IDLE, "Disabled label test"); - gcr_unlock_options_widget_set_ttl (unlock, 80); - gcr_unlock_options_widget_set_choice (unlock, GCR_UNLOCK_OPTION_ALWAYS); - - gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 400); - gtk_dialog_run (dialog); - - g_printerr ("choice: %s\n", - gcr_unlock_options_widget_get_choice (unlock)); - - g_printerr ("ttl: %u\n", - gcr_unlock_options_widget_get_ttl (unlock)); - - g_printerr ("idle sensitive: %s\n", - gcr_unlock_options_widget_get_sensitive (unlock, GCR_UNLOCK_OPTION_IDLE) ? "T" : "F"); - - g_printerr ("always sensitive: %s\n", - gcr_unlock_options_widget_get_sensitive (unlock, GCR_UNLOCK_OPTION_ALWAYS) ? "T" : "F"); - - g_printerr ("label: %s\n", - gcr_unlock_options_widget_get_label (unlock, GCR_UNLOCK_OPTION_ALWAYS)); - - g_object_unref (dialog); -} - -int -main(int argc, char *argv[]) -{ - gtk_init (&argc, &argv); - g_set_prgname ("frob-unlock-options"); - - test_unlock_options (); - - return 0; -} diff --git a/gcr/tests/frob-unlock.c b/gcr/tests/frob-unlock.c deleted file mode 100644 index b39f218f..00000000 --- a/gcr/tests/frob-unlock.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2011 Collabora Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - * - * Author: Stef Walter <stefw@collabora.co.uk> - */ - -#include "config.h" - -#include "gcr/gcr.h" -#include "gcr/gcr-unlock-renderer.h" -#include "gcr/gcr-viewer-window.h" - -#include <gtk/gtk.h> - -#include <unistd.h> -#include <string.h> -#include <errno.h> - -static gboolean -delete_event(GtkWidget *widget, - GdkEvent *event, - gpointer data) -{ - gtk_main_quit (); - return FALSE; -} - -static void -on_parser_parsed (GcrParser *parser, gpointer unused) -{ - -} - -static void -on_parser_authenticate (GcrParser *parser, - gint count, - gpointer user_data) -{ - GcrUnlockRenderer *renderer; - GtkWindow *window; - - window = GTK_WINDOW (gcr_viewer_window_new ()); - g_object_ref_sink (window); - - renderer = _gcr_unlock_renderer_new_for_parsed (parser); - gcr_viewer_add_renderer (GCR_VIEWER (window), GCR_RENDERER (renderer)); - g_object_unref (renderer); - - gtk_window_set_default_size (window, 550, 400); - gtk_container_set_border_width (GTK_CONTAINER (window), 20); - - g_signal_connect (window, "delete-event", G_CALLBACK (delete_event), NULL); - gtk_widget_show (GTK_WIDGET (window)); - - gtk_main (); - - g_object_unref (window); - -} - -static void -test_key (const gchar *path) -{ - GcrParser *parser; - GError *err = NULL; - guchar *data; - gsize n_data; - - if (!g_file_get_contents (path, (gchar**)&data, &n_data, NULL)) - g_error ("couldn't read file: %s", path); - - parser = gcr_parser_new (); - g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), NULL); - g_signal_connect (parser, "authenticate", G_CALLBACK (on_parser_authenticate), NULL); - if (!gcr_parser_parse_data (parser, data, n_data, &err)) - g_error ("couldn't parse data: %s", err->message); - - g_object_unref (parser); - g_free (data); -} - -int -main(int argc, char *argv[]) -{ - gtk_init (&argc, &argv); - g_set_prgname ("frob-unlock"); - - if (argc > 1) { - test_key (argv[1]); - } else { - test_key (SRCDIR "/files/email.p12"); - } - - return 0; -} diff --git a/gcr/tests/test-certificate-chain.c b/gcr/tests/test-certificate-chain.c deleted file mode 100644 index 715bd495..00000000 --- a/gcr/tests/test-certificate-chain.c +++ /dev/null @@ -1,658 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2010 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr-base.h" -#include "gcr/gcr-internal.h" - -#include "egg/egg-asn1x.h" -#include "egg/egg-asn1-defs.h" -#include "egg/egg-testing.h" - -#include "gck/gck-mock.h" -#include "gck/gck-test.h" - -#include "pkcs11/pkcs11.h" -#include "pkcs11/pkcs11x.h" - -#include <glib.h> - -#include <errno.h> -#include <string.h> - -/* --------------------------------------------------------------------------- - * A Mock certificate that checks that it's always called on the - * same thread. A GcrCertificate implemented on top of a non-thread-safe - * crypto library would require this behavior. - */ - -GType mock_certificate_get_type (void); - -#define MOCK_CERTIFICATE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), mock_certificate_get_type (), MockCertificate)) - -typedef struct _MockCertificate { - GObject parent; - GThread *created_on; - gpointer data; - gsize n_data; -} MockCertificate; - -typedef struct _MockCertificateClass { - GObjectClass parent_class; -} MockCertificateClass; - -static void mock_certificate_iface (GcrCertificateIface *iface); -G_DEFINE_TYPE_WITH_CODE (MockCertificate, mock_certificate, G_TYPE_OBJECT, - GCR_CERTIFICATE_MIXIN_IMPLEMENT_COMPARABLE (); - G_IMPLEMENT_INTERFACE (GCR_TYPE_CERTIFICATE, mock_certificate_iface); -); - -static void -mock_certificate_init (MockCertificate *self) -{ - self->created_on = g_thread_self (); -} - -static void -mock_certificate_finalize (GObject *obj) -{ - MockCertificate *self = MOCK_CERTIFICATE (obj); - g_assert (self->created_on == g_thread_self ()); - g_free (self->data); - G_OBJECT_CLASS (mock_certificate_parent_class)->finalize (obj); -} - -static void -mock_certificate_class_init (MockCertificateClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - gobject_class->finalize = mock_certificate_finalize; - gobject_class->get_property = gcr_certificate_mixin_get_property; - gcr_certificate_mixin_class_init (gobject_class); -} - -static gconstpointer -mock_certificate_real_get_der_data (GcrCertificate *base, gsize *n_data) -{ - MockCertificate *self = MOCK_CERTIFICATE (base); - g_assert (self->created_on == g_thread_self ()); - *n_data = self->n_data; - return self->data; -} - -static void -mock_certificate_iface (GcrCertificateIface *iface) -{ - iface->get_der_data = (gpointer)mock_certificate_real_get_der_data; -} - -static GcrCertificate* -mock_certificate_new (gconstpointer data, gsize n_data) -{ - MockCertificate *self = g_object_new (mock_certificate_get_type (), NULL); - self->data = g_memdup (data, n_data); - self->n_data = n_data; - g_assert (self->created_on == g_thread_self ()); - return GCR_CERTIFICATE (self); -} - -/* ---------------------------------------------------------------------------- - * TESTS - */ - -typedef struct { - GcrCertificate *cert_self; - GcrCertificate *cert_ca; - GcrCertificate *cert_signed; - CK_FUNCTION_LIST funcs; -} Test; - -static void -setup (Test *test, gconstpointer unused) -{ - GList *modules = NULL; - CK_FUNCTION_LIST_PTR f; - gchar *contents; - gsize n_contents; - const gchar *uris[2]; - CK_RV rv; - GckModule *module; - - rv = gck_mock_C_GetFunctionList (&f); - gck_assert_cmprv (rv, ==, CKR_OK); - memcpy (&test->funcs, f, sizeof (test->funcs)); - - /* Open a session */ - rv = (test->funcs.C_Initialize) (NULL); - gck_assert_cmprv (rv, ==, CKR_OK); - - g_assert (!modules); - module = gck_module_new (&test->funcs); - modules = g_list_prepend (modules, module); - gcr_pkcs11_set_modules (modules); - uris[0] = GCK_MOCK_SLOT_ONE_URI; - uris[1] = NULL; - gcr_pkcs11_set_trust_lookup_uris (uris); - gcr_pkcs11_set_trust_store_uri (GCK_MOCK_SLOT_ONE_URI); - gck_list_unref_free (modules); - - /* A self-signed certificate */ - if (!g_file_get_contents (SRCDIR "/files/der-certificate.crt", &contents, &n_contents, NULL)) - g_assert_not_reached (); - test->cert_self = gcr_simple_certificate_new ((const guchar *)contents, n_contents); - g_free (contents); - - /* A signed certificate */ - if (!g_file_get_contents (SRCDIR "/files/dhansak-collabora.cer", &contents, &n_contents, NULL)) - g_assert_not_reached (); - test->cert_signed = mock_certificate_new (contents, n_contents); - g_free (contents); - - /* The signer for the above certificate */ - if (!g_file_get_contents (SRCDIR "/files/collabora-ca.cer", &contents, &n_contents, NULL)) - g_assert_not_reached (); - test->cert_ca = mock_certificate_new (contents, n_contents); - g_free (contents); -} - -static void -add_certificate_to_module (GcrCertificate *certificate) -{ - GckAttributes *attrs; - gconstpointer data; - gsize n_data, n_subject; - gpointer subject; - - data = gcr_certificate_get_der_data (certificate, &n_data); - g_assert (data); - - subject = gcr_certificate_get_subject_raw (certificate, &n_subject); - g_assert (subject); - - /* Add a certificate to the module */ - attrs = gck_attributes_new (); - gck_attributes_add_data (attrs, CKA_VALUE, data, n_data); - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE); - gck_attributes_add_ulong (attrs, CKA_CERTIFICATE_TYPE, CKC_X_509); - gck_attributes_add_data (attrs, CKA_SUBJECT, subject, n_subject); - gck_mock_module_take_object (attrs); - - g_free (subject); -} - -static void -add_anchor_to_module (GcrCertificate *certificate, const gchar *purpose) -{ - GckAttributes *attrs; - gconstpointer data; - gsize n_data; - - data = gcr_certificate_get_der_data (certificate, &n_data); - g_assert (data); - - /* And add a pinned certificate for the signed certificate */ - attrs = gck_attributes_new (); - gck_attributes_add_data (attrs, CKA_X_CERTIFICATE_VALUE, data, n_data); - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_X_TRUST_ASSERTION); - gck_attributes_add_ulong (attrs, CKA_X_ASSERTION_TYPE, CKT_X_ANCHORED_CERTIFICATE); - gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose); - gck_mock_module_take_object (attrs); -} - -static void -add_pinned_to_module (GcrCertificate *certificate, const gchar *purpose, const gchar *host) -{ - GckAttributes *attrs; - gconstpointer data; - gsize n_data; - - data = gcr_certificate_get_der_data (certificate, &n_data); - g_assert (data); - - /* And add a pinned certificate for the signed certificate */ - attrs = gck_attributes_new (); - gck_attributes_add_data (attrs, CKA_X_CERTIFICATE_VALUE, data, n_data); - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_X_TRUST_ASSERTION); - gck_attributes_add_ulong (attrs, CKA_X_ASSERTION_TYPE, CKT_X_PINNED_CERTIFICATE); - gck_attributes_add_string (attrs, CKA_X_PURPOSE, purpose); - gck_attributes_add_string (attrs, CKA_X_PEER, host); - gck_mock_module_take_object (attrs); -} - -static void -teardown (Test *test, gconstpointer unused) -{ - CK_RV rv; - - g_object_unref (test->cert_self); - g_object_unref (test->cert_signed); - g_object_unref (test->cert_ca); - - rv = (test->funcs.C_Finalize) (NULL); - gck_assert_cmprv (rv, ==, CKR_OK); -} - -static void -test_new (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - - chain = gcr_certificate_chain_new (); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_UNKNOWN); - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 0); - - g_assert (gcr_certificate_chain_get_endpoint (chain) == NULL); - - g_object_unref (chain); -} - -static void -test_new_with_cert (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GcrCertificate *check; - guint status, length; - - chain = gcr_certificate_chain_new (); - gcr_certificate_chain_add (chain, test->cert_signed); - gcr_certificate_chain_add (chain, test->cert_ca); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_UNKNOWN); - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 2); - - status = G_MAXUINT; - length = 0; - g_object_get (chain, "status", &status, "length", &length, NULL); - g_assert_cmpuint (status, ==, GCR_CERTIFICATE_CHAIN_UNKNOWN); - g_assert_cmpuint (length, ==, 2); - - check = gcr_certificate_chain_get_certificate (chain, 1); - g_assert (check == test->cert_ca); - - /* Not yet completed */ - check = gcr_certificate_chain_get_anchor (chain); - g_assert (check == NULL); - - check = gcr_certificate_chain_get_endpoint (chain); - g_assert (check == test->cert_signed); - - g_object_unref (chain); -} - -static void -test_selfsigned (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - - chain = gcr_certificate_chain_new (); - - /* Add a self-signed certificate */ - gcr_certificate_chain_add (chain, test->cert_self); - - if (!gcr_certificate_chain_build (chain, GCR_PURPOSE_CLIENT_AUTH, - NULL, 0, NULL, &error)) - g_assert_not_reached (); - g_assert_no_error (error); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_SELFSIGNED); - - g_object_unref (chain); -} - -static void -test_incomplete (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - - chain = gcr_certificate_chain_new (); - - /* Add a signed certificate */ - gcr_certificate_chain_add (chain, test->cert_signed); - - if (!gcr_certificate_chain_build (chain, GCR_PURPOSE_CLIENT_AUTH, - NULL, 0, NULL, &error)) - g_assert_not_reached (); - g_assert_no_error (error); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_INCOMPLETE); - - g_object_unref (chain); -} - -static void -test_empty (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - - chain = gcr_certificate_chain_new (); - - /* Add no certificate */ - - if (!gcr_certificate_chain_build (chain, GCR_PURPOSE_CLIENT_AUTH, - NULL, 0, NULL, &error)) - g_assert_not_reached (); - g_assert_no_error (error); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_UNKNOWN); - - g_object_unref (chain); -} - -static void -test_trim_extras (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - - chain = gcr_certificate_chain_new (); - - /* Add two unrelated certificates */ - gcr_certificate_chain_add (chain, test->cert_self); - gcr_certificate_chain_add (chain, test->cert_signed); - - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 2); - - if (!gcr_certificate_chain_build (chain, GCR_PURPOSE_CLIENT_AUTH, - NULL, 0, NULL, &error)) - g_assert_not_reached (); - g_assert_no_error (error); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_SELFSIGNED); - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 1); - - g_object_unref (chain); -} - -static void -fetch_async_result (GObject *source, GAsyncResult *result, gpointer user_data) -{ - *((GAsyncResult**)user_data) = result; - g_object_ref (result); - egg_test_wait_stop (); -} - -static void -test_complete_async (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - GAsyncResult *result = NULL; - - chain = gcr_certificate_chain_new (); - - /* Add a whole bunch of certificates */ - gcr_certificate_chain_add (chain, test->cert_signed); - gcr_certificate_chain_add (chain, test->cert_ca); - gcr_certificate_chain_add (chain, test->cert_self); - - gcr_certificate_chain_build_async (chain, GCR_PURPOSE_CLIENT_AUTH, - NULL, 0, NULL, fetch_async_result, &result); - egg_test_wait_until (500); - if (!gcr_certificate_chain_build_finish (chain, result, &error)) - g_assert_not_reached (); - g_assert_no_error (error); - g_object_unref (result); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_SELFSIGNED); - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 2); - - g_object_unref (chain); -} - -static void -test_with_anchor (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - - chain = gcr_certificate_chain_new (); - - /* Two certificates in chain with ca trust anchor */ - gcr_certificate_chain_add (chain, test->cert_signed); - gcr_certificate_chain_add (chain, test->cert_ca); - add_anchor_to_module (test->cert_ca, GCR_PURPOSE_CLIENT_AUTH); - - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 2); - - if (!gcr_certificate_chain_build (chain, GCR_PURPOSE_CLIENT_AUTH, - NULL, 0, NULL, &error)) - g_assert_not_reached (); - g_assert_no_error (error); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_ANCHORED); - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 2); - g_assert (gcr_certificate_chain_get_anchor (chain) == test->cert_ca); - - g_object_unref (chain); -} - -static void -test_with_anchor_and_lookup_ca (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - - chain = gcr_certificate_chain_new (); - - /* One signed certificate, with CA in pkcs11, and trust anchor */ - gcr_certificate_chain_add (chain, test->cert_signed); - add_certificate_to_module (test->cert_ca); - add_anchor_to_module (test->cert_ca, GCR_PURPOSE_CLIENT_AUTH); - - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 1); - - if (!gcr_certificate_chain_build (chain, GCR_PURPOSE_CLIENT_AUTH, - NULL, 0, NULL, &error)) - g_assert_not_reached (); - g_assert_no_error (error); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_ANCHORED); - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 2); - g_assert (gcr_certificate_chain_get_anchor (chain) != NULL); - - g_object_unref (chain); -} - -static void -test_with_pinned (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - - chain = gcr_certificate_chain_new (); - - /* One certificate, and add CA to pkcs11 */ - gcr_certificate_chain_add (chain, test->cert_signed); - gcr_certificate_chain_add (chain, test->cert_ca); - add_pinned_to_module (test->cert_signed, GCR_PURPOSE_CLIENT_AUTH, "pinned.example.com"); - - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 2); - - /* But we don't allow the lookup to happen */ - if (!gcr_certificate_chain_build (chain, GCR_PURPOSE_CLIENT_AUTH, - "pinned.example.com", 0, NULL, &error)) - g_assert_not_reached (); - g_assert_no_error (error); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_PINNED); - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 1); - g_assert (gcr_certificate_chain_get_anchor (chain) == NULL); - - g_object_unref (chain); -} - -static void -test_without_lookups (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - - chain = gcr_certificate_chain_new (); - - /* One certificate, and add CA to pkcs11 */ - gcr_certificate_chain_add (chain, test->cert_signed); - add_certificate_to_module (test->cert_ca); - - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 1); - - /* But we don't allow the lookup to happen */ - if (!gcr_certificate_chain_build (chain, GCR_PURPOSE_CLIENT_AUTH, - NULL, GCR_CERTIFICATE_CHAIN_NO_LOOKUPS, - NULL, &error)) - g_assert_not_reached (); - g_assert_no_error (error); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_INCOMPLETE); - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 1); - g_assert (gcr_certificate_chain_get_anchor (chain) == NULL); - - g_object_unref (chain); -} - -static void -test_with_lookup_error (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - - /* Make the lookup fail */ - test->funcs.C_GetAttributeValue = gck_mock_fail_C_GetAttributeValue; - - chain = gcr_certificate_chain_new (); - - /* Two certificates in chain with ca trust anchor */ - gcr_certificate_chain_add (chain, test->cert_signed); - add_certificate_to_module (test->cert_ca); - - g_assert_cmpuint (gcr_certificate_chain_get_length (chain), ==, 1); - - if (gcr_certificate_chain_build (chain, GCR_PURPOSE_CLIENT_AUTH, - NULL, 0, NULL, &error)) - g_assert_not_reached (); - g_assert_error (error, GCK_ERROR, CKR_FUNCTION_FAILED); - g_clear_error (&error); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_UNKNOWN); - - g_object_unref (chain); -} - -static void -test_with_anchor_error (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - - /* Make the lookup fail */ - test->funcs.C_GetAttributeValue = gck_mock_fail_C_GetAttributeValue; - - chain = gcr_certificate_chain_new (); - - /* Two certificates in chain with ca trust anchor */ - gcr_certificate_chain_add (chain, test->cert_signed); - add_certificate_to_module (test->cert_ca); - - if (gcr_certificate_chain_build (chain, GCR_PURPOSE_CLIENT_AUTH, - NULL, 0, NULL, &error)) - g_assert_not_reached (); - g_assert_error (error, GCK_ERROR, CKR_FUNCTION_FAILED); - g_clear_error (&error); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_UNKNOWN); - - g_object_unref (chain); -} - -static void -test_with_anchor_error_async (Test *test, gconstpointer unused) -{ - GcrCertificateChain *chain; - GError *error = NULL; - GAsyncResult *result; - - /* Make the lookup fail */ - test->funcs.C_GetAttributeValue = gck_mock_fail_C_GetAttributeValue; - - chain = gcr_certificate_chain_new (); - - /* Two certificates in chain with ca trust anchor */ - gcr_certificate_chain_add (chain, test->cert_signed); - add_certificate_to_module (test->cert_ca); - - gcr_certificate_chain_build_async (chain, GCR_PURPOSE_CLIENT_AUTH, - NULL, 0, NULL, fetch_async_result, &result); - egg_test_wait_until (500); - if (gcr_certificate_chain_build_finish (chain, result, &error)) - g_assert_not_reached (); - g_assert_error (error, GCK_ERROR, CKR_FUNCTION_FAILED); - g_clear_error (&error); - g_object_unref (result); - - g_assert_cmpuint (gcr_certificate_chain_get_status (chain), ==, - GCR_CERTIFICATE_CHAIN_UNKNOWN); - - g_object_unref (chain); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - g_set_prgname ("test-certificate-chain"); - - g_test_add ("/gcr/certificate-chain/new", Test, NULL, setup, test_new, teardown); - g_test_add ("/gcr/certificate-chain/new_with_cert", Test, NULL, setup, test_new_with_cert, teardown); - g_test_add ("/gcr/certificate-chain/selfsigned", Test, NULL, setup, test_selfsigned, teardown); - g_test_add ("/gcr/certificate-chain/incomplete", Test, NULL, setup, test_incomplete, teardown); - g_test_add ("/gcr/certificate-chain/empty", Test, NULL, setup, test_empty, teardown); - g_test_add ("/gcr/certificate-chain/trim_extras", Test, NULL, setup, test_trim_extras, teardown); - g_test_add ("/gcr/certificate-chain/complete_async", Test, NULL, setup, test_complete_async, teardown); - g_test_add ("/gcr/certificate-chain/with_anchor", Test, NULL, setup, test_with_anchor, teardown); - g_test_add ("/gcr/certificate-chain/with_anchor_and_lookup_ca", Test, NULL, setup, test_with_anchor_and_lookup_ca, teardown); - g_test_add ("/gcr/certificate-chain/with_pinned", Test, NULL, setup, test_with_pinned, teardown); - g_test_add ("/gcr/certificate-chain/without_lookups", Test, NULL, setup, test_without_lookups, teardown); - g_test_add ("/gcr/certificate-chain/with_lookup_error", Test, NULL, setup, test_with_lookup_error, teardown); - g_test_add ("/gcr/certificate-chain/with_anchor_error", Test, NULL, setup, test_with_anchor_error, teardown); - g_test_add ("/gcr/certificate-chain/with_anchor_error_async", Test, NULL, setup, test_with_anchor_error_async, teardown); - - return egg_tests_run_in_thread_with_loop (); -} diff --git a/gcr/tests/test-certificate.c b/gcr/tests/test-certificate.c deleted file mode 100644 index 6fb68c98..00000000 --- a/gcr/tests/test-certificate.c +++ /dev/null @@ -1,279 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2010 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr-base.h" -#include "gcr/gcr-internal.h" - -#include "egg/egg-testing.h" - -#include <glib.h> - -#include <errno.h> -#include <string.h> - -typedef struct { - GcrCertificate *certificate; - GcrCertificate *dsa_cert; - GcrCertificate *dhansak_cert; -} Test; - -static void -setup (Test *test, gconstpointer unused) -{ - gchar *contents; - gsize n_contents; - - if (!g_file_get_contents (SRCDIR "/files/der-certificate.crt", &contents, &n_contents, NULL)) - g_assert_not_reached (); - test->certificate = gcr_simple_certificate_new ((const guchar *)contents, n_contents); - g_assert (test->certificate); - g_free (contents); - - if (!g_file_get_contents (SRCDIR "/files/der-certificate-dsa.cer", &contents, &n_contents, NULL)) - g_assert_not_reached (); - test->dsa_cert = gcr_simple_certificate_new ((const guchar *)contents, n_contents); - g_assert (test->dsa_cert); - g_free (contents); - - if (!g_file_get_contents (SRCDIR "/files/dhansak-collabora.cer", &contents, &n_contents, NULL)) - g_assert_not_reached (); - test->dhansak_cert = gcr_simple_certificate_new ((const guchar *)contents, n_contents); - g_assert (test->certificate); - g_free (contents); -} - -static void -teardown (Test *test, gconstpointer unused) -{ - g_object_unref (test->certificate); - g_object_unref (test->dsa_cert); - g_object_unref (test->dhansak_cert); -} - -static void -test_issuer_cn (Test *test, gconstpointer unused) -{ - gchar *cn = gcr_certificate_get_issuer_cn (test->certificate); - g_assert (cn); - g_assert_cmpstr (cn, ==, "http://www.valicert.com/"); - g_free (cn); -} - -static void -test_issuer_dn (Test *test, gconstpointer unused) -{ - gchar *dn = gcr_certificate_get_issuer_dn (test->certificate); - g_assert (dn); - g_assert_cmpstr (dn, ==, "L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 3 Policy Validation Authority, CN=http://www.valicert.com/, EMAIL=info@valicert.com"); - g_free (dn); -} - -static void -test_issuer_part (Test *test, gconstpointer unused) -{ - gchar *part = gcr_certificate_get_issuer_part (test->certificate, "l"); - g_assert (part); - g_assert_cmpstr (part, ==, "ValiCert Validation Network"); - g_free (part); -} - -static void -test_issuer_raw (Test *test, gconstpointer unused) -{ - gpointer der; - gsize n_der; - - der = gcr_certificate_get_issuer_raw (test->certificate, &n_der); - g_assert (der); - egg_assert_cmpsize (n_der, ==, 190); - g_free (der); -} - -static void -test_subject_cn (Test *test, gconstpointer unused) -{ - gchar *cn = gcr_certificate_get_subject_cn (test->certificate); - g_assert (cn); - g_assert_cmpstr (cn, ==, "http://www.valicert.com/"); - g_free (cn); - - cn = gcr_certificate_get_subject_cn (test->dhansak_cert); - g_assert (cn); - g_assert_cmpstr (cn, ==, "dhansak.collabora.co.uk"); - g_free (cn); -} - -static void -test_subject_dn (Test *test, gconstpointer unused) -{ - gchar *dn = gcr_certificate_get_subject_dn (test->certificate); - g_assert (dn); - g_assert_cmpstr (dn, ==, "L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 3 Policy Validation Authority, CN=http://www.valicert.com/, EMAIL=info@valicert.com"); - g_free (dn); - - dn = gcr_certificate_get_subject_dn (test->dhansak_cert); - g_assert (dn); - g_assert_cmpstr (dn, ==, "CN=dhansak.collabora.co.uk, EMAIL=sysadmin@collabora.co.uk"); - g_free (dn); - -} - -static void -test_subject_part (Test *test, gconstpointer unused) -{ - gchar *part = gcr_certificate_get_subject_part (test->certificate, "OU"); - g_assert (part); - g_assert_cmpstr (part, ==, "ValiCert Class 3 Policy Validation Authority"); - g_free (part); - - part = gcr_certificate_get_subject_part (test->dhansak_cert, "EMAIL"); - g_assert (part); - g_assert_cmpstr (part, ==, "sysadmin@collabora.co.uk"); - g_free (part); - -} - -static void -test_subject_raw (Test *test, gconstpointer unused) -{ - gpointer der; - gsize n_der; - - der = gcr_certificate_get_subject_raw (test->certificate, &n_der); - g_assert (der); - egg_assert_cmpsize (n_der, ==, 190); - g_free (der); - - der = gcr_certificate_get_subject_raw (test->dhansak_cert, &n_der); - g_assert (der); - egg_assert_cmpsize (n_der, ==, 77); - g_free (der); -} - -static void -test_issued_date (Test *test, gconstpointer unused) -{ - GDate *date = gcr_certificate_get_issued_date (test->certificate); - g_assert (date); - g_assert_cmpuint (g_date_get_year (date), ==, 1999); - g_assert_cmpuint (g_date_get_month (date), ==, 6); - g_assert_cmpuint (g_date_get_day (date), ==, 26); - g_date_free (date); -} - -static void -test_expiry_date (Test *test, gconstpointer unused) -{ - GDate *date = gcr_certificate_get_expiry_date (test->certificate); - g_assert (date); - g_assert_cmpuint (g_date_get_year (date), ==, 2019); - g_assert_cmpuint (g_date_get_month (date), ==, 6); - g_assert_cmpuint (g_date_get_day (date), ==, 26); - g_date_free (date); -} - -static void -test_serial_number (Test *test, gconstpointer unused) -{ - gsize n_serial; - guchar *serial; - gchar *hex; - - serial = gcr_certificate_get_serial_number (test->certificate, &n_serial); - g_assert (serial); - g_assert_cmpuint (n_serial, ==, 1); - g_assert (memcmp (serial, "\1", n_serial) == 0); - g_free (serial); - - hex = gcr_certificate_get_serial_number_hex (test->certificate); - g_assert (hex); - g_assert_cmpstr (hex, ==, "01"); - g_free (hex); -} - -static void -test_fingerprint (Test *test, gconstpointer unused) -{ - gsize n_print; - guchar *print = gcr_certificate_get_fingerprint (test->certificate, G_CHECKSUM_MD5, &n_print); - g_assert (print); - g_assert_cmpuint (n_print, ==, g_checksum_type_get_length (G_CHECKSUM_MD5)); - g_assert (memcmp (print, "\xa2\x6f\x53\xb7\xee\x40\xdb\x4a\x68\xe7\xfa\x18\xd9\x10\x4b\x72", n_print) == 0); - g_free (print); -} - -static void -test_fingerprint_hex (Test *test, gconstpointer unused) -{ - gchar *print = gcr_certificate_get_fingerprint_hex (test->certificate, G_CHECKSUM_MD5); - g_assert (print); - g_assert_cmpstr (print, ==, "A2 6F 53 B7 EE 40 DB 4A 68 E7 FA 18 D9 10 4B 72"); - g_free (print); -} - -static void -test_certificate_key_size (Test *test, gconstpointer unused) -{ - guint key_size = gcr_certificate_get_key_size (test->certificate); - g_assert_cmpuint (key_size, ==, 1024); - - key_size = gcr_certificate_get_key_size (test->dsa_cert); - g_assert_cmpuint (key_size, ==, 1024); -} - -static void -test_certificate_is_issuer (Test *test, gconstpointer unused) -{ - gboolean ret = gcr_certificate_is_issuer (test->certificate, test->certificate); - g_assert (ret == TRUE); - - ret = gcr_certificate_is_issuer (test->certificate, test->dsa_cert); - g_assert (ret == FALSE); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - g_set_prgname ("test-certificate"); - - g_test_add ("/gcr/certificate/issuer_cn", Test, NULL, setup, test_issuer_cn, teardown); - g_test_add ("/gcr/certificate/issuer_dn", Test, NULL, setup, test_issuer_dn, teardown); - g_test_add ("/gcr/certificate/issuer_part", Test, NULL, setup, test_issuer_part, teardown); - g_test_add ("/gcr/certificate/issuer_raw", Test, NULL, setup, test_issuer_raw, teardown); - g_test_add ("/gcr/certificate/subject_cn", Test, NULL, setup, test_subject_cn, teardown); - g_test_add ("/gcr/certificate/subject_dn", Test, NULL, setup, test_subject_dn, teardown); - g_test_add ("/gcr/certificate/subject_part", Test, NULL, setup, test_subject_part, teardown); - g_test_add ("/gcr/certificate/subject_raw", Test, NULL, setup, test_subject_raw, teardown); - g_test_add ("/gcr/certificate/issued_date", Test, NULL, setup, test_issued_date, teardown); - g_test_add ("/gcr/certificate/expiry_date", Test, NULL, setup, test_expiry_date, teardown); - g_test_add ("/gcr/certificate/serial_number", Test, NULL, setup, test_serial_number, teardown); - g_test_add ("/gcr/certificate/fingerprint", Test, NULL, setup, test_fingerprint, teardown); - g_test_add ("/gcr/certificate/fingerprint_hex", Test, NULL, setup, test_fingerprint_hex, teardown); - g_test_add ("/gcr/certificate/certificate_key_size", Test, NULL, setup, test_certificate_key_size, teardown); - g_test_add ("/gcr/certificate/certificate_is_issuer", Test, NULL, setup, test_certificate_is_issuer, teardown); - - return g_test_run (); -} diff --git a/gcr/tests/test-fingerprint.c b/gcr/tests/test-fingerprint.c deleted file mode 100644 index 0270758b..00000000 --- a/gcr/tests/test-fingerprint.c +++ /dev/null @@ -1,212 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2010 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" -#define GCR_COMPILATION 1 - -#include "gcr/gcr-base.h" -#include "gcr/gcr-internal.h" -#include "gcr/gcr-fingerprint.h" - -#include "gck/gck-test.h" - -#include "pkcs11/pkcs11n.h" - -#include "egg/egg-asn1x.h" -#include "egg/egg-asn1-defs.h" -#include "egg/egg-testing.h" - -#include <glib.h> - -#include <errno.h> - -typedef struct { - gpointer cert_rsa; - gsize n_cert_rsa; - gpointer key_rsa; - gsize n_key_rsa; - gpointer cert_dsa; - gsize n_cert_dsa; - gpointer key_dsa; - gsize n_key_dsa; -} Test; - -static void -setup (Test *test, gconstpointer unused) -{ - GError *error = NULL; - - g_file_get_contents (SRCDIR "/files/client.crt", (gchar**)&test->cert_rsa, - &test->n_cert_rsa, &error); - g_assert_no_error (error); - g_assert (test->cert_rsa); - - g_file_get_contents (SRCDIR "/files/client.key", (gchar**)&test->key_rsa, - &test->n_key_rsa, &error); - g_assert_no_error (error); - g_assert (test->key_rsa); - - g_file_get_contents (SRCDIR "/files/generic-dsa.crt", (gchar**)&test->cert_dsa, - &test->n_cert_dsa, &error); - g_assert_no_error (error); - g_assert (test->cert_dsa); - - g_file_get_contents (SRCDIR "/files/generic-dsa.key", (gchar**)&test->key_dsa, - &test->n_key_dsa, &error); - g_assert_no_error (error); - g_assert (test->key_dsa); -} - -static void -teardown (Test *test, gconstpointer unused) -{ - g_free (test->cert_rsa); - g_free (test->key_rsa); - g_free (test->cert_dsa); - g_free (test->key_dsa); -} - -static void -on_parser_parsed (GcrParser *parser, - gpointer user_data) -{ - GckAttributes **attrs = user_data; - g_assert (!*attrs); - *attrs = gcr_parser_get_parsed_attributes (parser); - g_assert (*attrs); - gck_attributes_ref (*attrs); -} - -static GckAttributes* -parse_attributes_for_key (gpointer data, gsize n_data) -{ - GcrParser *parser; - GckAttributes *attrs = NULL; - GError *error = NULL; - - parser = gcr_parser_new (); - g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), &attrs); - gcr_parser_parse_data (parser, data, n_data, &error); - g_assert_no_error (error); - g_object_unref (parser); - - g_assert (attrs); - return attrs; -} - -static GckAttributes * -build_attributes_for_cert (guchar *data, - gsize n_data) -{ - GckAttributes *attrs; - - attrs = gck_attributes_new (); - gck_attributes_add_data (attrs, CKA_VALUE, data, n_data); - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE); - gck_attributes_add_ulong (attrs, CKA_CERTIFICATE_TYPE, CKC_X_509); - - return attrs; -} - -static gconstpointer -parse_subject_public_key_info_for_cert (gpointer data, gsize n_data, gsize *n_info) -{ - gconstpointer info; - GNode *asn; - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data); - g_assert (asn); - - info = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", NULL), n_info); - g_assert (info); - - egg_asn1x_destroy (asn); - return info; -} - -static void -test_rsa (Test *test, gconstpointer unused) -{ - GckAttributes *key, *cert; - gconstpointer info; - gsize n_info; - guchar *fingerprint1, *fingerprint2, *fingerprint3; - gsize n_fingerprint1, n_fingerprint2, n_fingerprint3; - - key = parse_attributes_for_key (test->key_rsa, test->n_key_rsa); - info = parse_subject_public_key_info_for_cert (test->cert_rsa, test->n_cert_rsa, &n_info); - cert = build_attributes_for_cert (test->cert_rsa, test->n_cert_rsa); - - fingerprint1 = gcr_fingerprint_from_subject_public_key_info (info, n_info, G_CHECKSUM_SHA1, &n_fingerprint1); - fingerprint2 = gcr_fingerprint_from_attributes (key, G_CHECKSUM_SHA1, &n_fingerprint2); - fingerprint3 = gcr_fingerprint_from_attributes (cert, G_CHECKSUM_SHA1, &n_fingerprint3); - - egg_assert_cmpmem (fingerprint1, n_fingerprint1, ==, fingerprint2, n_fingerprint2); - egg_assert_cmpmem (fingerprint1, n_fingerprint1, ==, fingerprint3, n_fingerprint3); - - g_free (fingerprint1); - g_free (fingerprint2); - g_free (fingerprint3); - - gck_attributes_unref (key); - gck_attributes_unref (cert); -} - -static void -test_dsa (Test *test, gconstpointer unused) -{ - GckAttributes *key, *cert; - gconstpointer info; - gsize n_info; - guchar *fingerprint1, *fingerprint2, *fingerprint3; - gsize n_fingerprint1, n_fingerprint2, n_fingerprint3; - - key = parse_attributes_for_key (test->key_dsa, test->n_key_dsa); - info = parse_subject_public_key_info_for_cert (test->cert_dsa, test->n_cert_dsa, &n_info); - cert = build_attributes_for_cert (test->cert_dsa, test->n_cert_dsa); - - fingerprint1 = gcr_fingerprint_from_subject_public_key_info (info, n_info, G_CHECKSUM_SHA1, &n_fingerprint1); - fingerprint2 = gcr_fingerprint_from_attributes (key, G_CHECKSUM_SHA1, &n_fingerprint2); - fingerprint3 = gcr_fingerprint_from_attributes (cert, G_CHECKSUM_SHA1, &n_fingerprint3); - - egg_assert_cmpmem (fingerprint1, n_fingerprint1, ==, fingerprint2, n_fingerprint2); - egg_assert_cmpmem (fingerprint1, n_fingerprint1, ==, fingerprint3, n_fingerprint3); - - g_free (fingerprint1); - g_free (fingerprint2); - g_free (fingerprint3); - - gck_attributes_unref (key); - gck_attributes_unref (cert); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - - g_test_add ("/gcr/fingerprint/rsa", Test, NULL, setup, test_rsa, teardown); - g_test_add ("/gcr/fingerprint/dsa", Test, NULL, setup, test_dsa, teardown); - - return g_test_run (); -} diff --git a/gcr/tests/test-gnupg-collection.c b/gcr/tests/test-gnupg-collection.c deleted file mode 100644 index c8304a78..00000000 --- a/gcr/tests/test-gnupg-collection.c +++ /dev/null @@ -1,222 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2010 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr-base.h" -#include "gcr/gcr-gnupg-collection.h" -#include "gcr/gcr-gnupg-key.h" -#include "gcr/gcr-record.h" - -#include "egg/egg-testing.h" - -#include <glib.h> - -#include <errno.h> -#include <string.h> - -typedef struct { - GcrGnupgCollection *collection; - gchar *directory; - GHashTable *keys; - GAsyncResult *result; -} Test; - -static void -on_collection_added (GcrCollection *collection, GObject *object, gpointer user_data) -{ - Test *test = user_data; - GcrGnupgKey *key; - const gchar *keyid; - - g_assert (GCR_COLLECTION (test->collection) == collection); - - g_assert (GCR_IS_GNUPG_KEY (object)); - key = GCR_GNUPG_KEY (object); - - keyid = _gcr_gnupg_key_get_keyid (key); - g_assert (keyid); - g_assert (!g_hash_table_lookup (test->keys, keyid)); - - g_hash_table_insert (test->keys, g_strdup (keyid), key); -} - -static void -on_collection_removed (GcrCollection *collection, GObject *object, gpointer user_data) -{ - Test *test = user_data; - GcrGnupgKey *key; - const gchar *keyid; - - g_assert (GCR_COLLECTION (test->collection) == collection); - g_assert (GCR_IS_GNUPG_KEY (object)); - - keyid = _gcr_gnupg_key_get_keyid (GCR_GNUPG_KEY (object)); - key = g_hash_table_lookup (test->keys, keyid); - g_assert (key == GCR_GNUPG_KEY (object)); - - if (!g_hash_table_remove (test->keys, keyid)) - g_assert_not_reached (); -} - -static void -setup (Test *test, gconstpointer unused) -{ - GcrCollection *collection; - - test->directory = g_build_filename (SRCDIR, "files", "gnupg-homedir", NULL); - - collection = _gcr_gnupg_collection_new (test->directory); - test->collection = GCR_GNUPG_COLLECTION (collection); - - test->keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - g_signal_connect (collection, "added", G_CALLBACK (on_collection_added), test); - g_signal_connect (collection, "removed", G_CALLBACK (on_collection_removed), test); -} - -static void -teardown (Test *test, gconstpointer unused) -{ - g_hash_table_destroy (test->keys); - - if (test->result) - g_object_unref (test->result); - - g_object_unref (test->collection); - g_free (test->directory); -} - -static void -on_async_ready (GObject *source, GAsyncResult *res, gpointer user_data) -{ - Test *test = user_data; - g_assert (G_OBJECT (test->collection) == source); - g_assert (test->result == NULL); - test->result = g_object_ref (res); - egg_test_wait_stop (); -} - -static void -test_properties (Test *test, gconstpointer unused) -{ - gchar *directory; - g_object_get (test->collection, "directory", &directory, NULL); - g_assert_cmpstr (directory, ==, test->directory); - g_free (directory); -} - -static void -test_load (Test *test, gconstpointer unused) -{ - GError *error = NULL; - GcrGnupgKey *key; - GList *l, *objects; - GcrRecord *record; - GHashTable *check; - - _gcr_gnupg_collection_load_async (test->collection, NULL, on_async_ready, test); - egg_test_wait_until (500000); - - g_assert (test->result); - _gcr_gnupg_collection_load_finish (test->collection, test->result, &error); - g_assert_no_error (error); - - /* Werner Koch (a public key) */ - key = g_hash_table_lookup (test->keys, "5DE249965B0358A2"); - g_assert (GCR_IS_GNUPG_KEY (key)); - g_assert (_gcr_gnupg_key_get_secret_records (key) == NULL); - - /* Test Number 2 (a secret key)*/ - key = g_hash_table_lookup (test->keys, "268FEE686262C395"); - g_assert (GCR_IS_GNUPG_KEY (key)); - g_assert (_gcr_gnupg_key_get_secret_records (key)); - - /* The length of collection should be correct */ - g_assert_cmpuint (g_hash_table_size (test->keys), ==, - gcr_collection_get_length (GCR_COLLECTION (test->collection))); - - /* The list of objects should be correct */ - objects = gcr_collection_get_objects (GCR_COLLECTION (test->collection)); - g_assert_cmpuint (g_hash_table_size (test->keys), ==, g_list_length (objects)); - check = g_hash_table_new (g_str_hash, g_str_equal); - for (l = objects; l != NULL; l = g_list_next (l)) { - g_assert (GCR_IS_GNUPG_KEY (l->data)); - key = g_hash_table_lookup (test->keys, _gcr_gnupg_key_get_keyid (l->data)); - g_assert (key == l->data); - g_hash_table_replace (check, (gchar*)_gcr_gnupg_key_get_keyid (l->data), ""); - } - g_assert_cmpuint (g_hash_table_size (check), ==, g_hash_table_size (test->keys)); - g_hash_table_destroy (check); - g_list_free (objects); - - /* Phillip R. Zimmerman's key should have a photo */ - key = g_hash_table_lookup (test->keys, "C7463639B2D7795E"); - g_assert (GCR_IS_GNUPG_KEY (key)); - record = _gcr_records_find (_gcr_gnupg_key_get_public_records (key), GCR_RECORD_SCHEMA_XA1); - g_assert (record); -} - -static void -test_reload (Test *test, gconstpointer unused) -{ - GError *error = NULL; - GcrGnupgKey *key; - - _gcr_gnupg_collection_load_async (test->collection, NULL, on_async_ready, test); - egg_test_wait_until (500); - g_assert (test->result); - _gcr_gnupg_collection_load_finish (test->collection, test->result, &error); - g_assert_no_error (error); - - g_object_unref (test->result); - test->result = NULL; - - _gcr_gnupg_collection_load_async (test->collection, NULL, on_async_ready, test); - egg_test_wait_until (500000); - g_assert (test->result); - _gcr_gnupg_collection_load_finish (test->collection, test->result, &error); - g_assert_no_error (error); - - /* Werner Koch (a public key) */ - key = g_hash_table_lookup (test->keys, "5DE249965B0358A2"); - g_assert (GCR_IS_GNUPG_KEY (key)); - g_assert (_gcr_gnupg_key_get_secret_records (key) == NULL); - - /* Test Number 2 (a secret key)*/ - key = g_hash_table_lookup (test->keys, "268FEE686262C395"); - g_assert (GCR_IS_GNUPG_KEY (key)); - g_assert (_gcr_gnupg_key_get_secret_records (key)); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - g_set_prgname ("test-gnupg-collection"); - - g_test_add ("/gcr/gnupg-collection/properties", Test, NULL, setup, test_properties, teardown); - g_test_add ("/gcr/gnupg-collection/load", Test, NULL, setup, test_load, teardown); - g_test_add ("/gcr/gnupg-collection/reload", Test, NULL, setup, test_reload, teardown); - - return egg_tests_run_in_thread_with_loop (); -} diff --git a/gcr/tests/test-gnupg-key.c b/gcr/tests/test-gnupg-key.c deleted file mode 100644 index 59008041..00000000 --- a/gcr/tests/test-gnupg-key.c +++ /dev/null @@ -1,228 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2011 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr-record.h" -#include "gcr/gcr-gnupg-key.h" -#include "gcr/gcr-gnupg-records.h" - -#include "egg/egg-testing.h" - -#include <glib.h> - -#include <errno.h> -#include <stdlib.h> -#include <string.h> - -typedef struct { - GPtrArray *records; - GPtrArray *pubset; - GPtrArray *secset; - GcrGnupgKey *key; -} Test; - -static void -setup (Test *test, gconstpointer unused) -{ - GPtrArray *records; - - records = g_ptr_array_new_with_free_func (_gcr_record_free); - g_ptr_array_add (records, _gcr_record_parse_colons ("pub:f:1024:17:6C7EE1B8621CC013:899817715:1055898235::m:::scESC:", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("fpr:::::::::ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013:", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("uid:f::::::::Werner Koch <wk@g10code.com>:\n", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("uid:f::::::::Werner Koch <wk@gnupg.org>:\n", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("sub:f:1536:16:06AD222CADF6A6E1:919537416:1036177416:::::e:\n", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("fpr:::::::::CF8BCC4B18DE08FCD8A1615906AD222CADF6A6E1:\n", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("sub:r:1536:20:5CE086B5B5A18FF4:899817788:1025961788:::::esc:\n", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("fpr:::::::::AB059359A3B81F410FCFF97F5CE086B5B5A18FF4:", -1)); - test->records = records; - - test->key = _gcr_gnupg_key_new (records, NULL); - - records = g_ptr_array_new_with_free_func (_gcr_record_free); - g_ptr_array_add (records, _gcr_record_parse_colons ("pub:u:2048:1:4842D952AFC000FD:1305189489:::u:::scESC:", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("uid:u::::1305189849::D0A8FA7B15DC4BE3F8F03A49C372F2718C78AFC0::Dr. Strangelove <lovingbomb@example.com>:", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("uid:u::::1305189489::D449F1605254754B0BBFA424FC34E50609103BBB::Test Number 1 (unlimited) <test-number-1@example.com>:", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("sub:u:2048:1:4852132BBED15014:1305189489::::::e:", -1)); - test->pubset = records; - - records = g_ptr_array_new_with_free_func (_gcr_record_free); - g_ptr_array_add (records, _gcr_record_parse_colons ("sec::2048:1:4842D952AFC000FD:1305189489::::::::::", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("uid:::::::D449F1605254754B0BBFA424FC34E50609103BBB::Test Number 1 (unlimited) <test-number-1@example.com>:", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("uid:::::::D0A8FA7B15DC4BE3F8F03A49C372F2718C78AFC0::Dr. Strangelove <lovingbomb@example.com>:", -1)); - g_ptr_array_add (records, _gcr_record_parse_colons ("ssb::2048:1:4852132BBED15014:1305189489::::::::::", -1)); - test->secset = records; -} - -static void -teardown (Test *test, gconstpointer unused) -{ - g_object_unref (test->key); - g_assert (!GCR_IS_GNUPG_KEY (test->key)); - - g_ptr_array_unref (test->records); - g_ptr_array_unref (test->pubset); - g_ptr_array_unref (test->secset); -} - -static void -test_label (Test *test, gconstpointer unused) -{ - gchar *label; - - g_object_get (test->key, "label", &label, NULL); - g_assert_cmpstr (label, ==, "Werner Koch <wk@g10code.com>"); - - g_free (label); -} - -static void -test_markup (Test *test, gconstpointer unused) -{ - gchar *markup; - - g_object_get (test->key, "markup", &markup, NULL); - g_assert_cmpstr (markup, ==, "Werner Koch\n<small>wk@g10code.com</small>"); - - g_free (markup); -} - -static void -test_description (Test *test, gconstpointer unused) -{ - gchar *description; - - g_object_get (test->key, "description", &description, NULL); - g_assert_cmpstr (description, ==, "PGP Key"); - - g_free (description); -} - -static void -test_records (Test *test, gconstpointer unused) -{ - GPtrArray *records; - - g_object_get (test->key, "public-records", &records, NULL); - g_assert (records == test->records); - - _gcr_gnupg_key_set_public_records (test->key, records); - g_assert (records == _gcr_gnupg_key_get_public_records (test->key)); - - g_ptr_array_unref (records); -} - -static void -test_keyid (Test *test, gconstpointer unused) -{ - gchar *keyid; - - g_object_get (test->key, "keyid", &keyid, NULL); - g_assert_cmpstr (keyid, ==, "6C7EE1B8621CC013"); - - g_free (keyid); - - g_assert_cmpstr (_gcr_gnupg_key_get_keyid (test->key), ==, "6C7EE1B8621CC013"); -} - -static void -test_short_keyid (Test *test, gconstpointer unused) -{ - gchar *keyid; - - g_object_get (test->key, "short-keyid", &keyid, NULL); - g_assert_cmpstr (keyid, ==, "621CC013"); - - g_free (keyid); -} - -static void -test_keyid_for_records (Test *test, gconstpointer unused) -{ - const gchar *keyid; - - keyid = _gcr_gnupg_records_get_keyid (test->records); - g_assert_cmpstr (keyid, ==, "6C7EE1B8621CC013"); -} - -static void -test_with_secret (Test *test, gconstpointer unused) -{ - GcrGnupgKey *key; - GPtrArray *secset; - - key = _gcr_gnupg_key_new (test->pubset, test->secset); - g_assert (GCR_IS_GNUPG_KEY (key)); - - g_object_get (key, "secret-records", &secset, NULL); - g_assert (secset == _gcr_gnupg_key_get_secret_records (key)); - g_object_set (key, "secret-records", secset, NULL); - - g_object_unref (key); -} - -static void -test_no_change_keyid (Test *test, gconstpointer unused) -{ - if (g_test_trap_fork (50000, G_TEST_TRAP_SILENCE_STDERR)) { - /* Changing the keyid. This should fail with a warning */ - _gcr_gnupg_key_set_public_records (test->key, test->pubset); - exit (0); - } - - g_test_trap_assert_failed (); - g_test_trap_assert_stderr ("*fingerprint is no longer the same:*"); -} - -static void -test_secret_mismatched_keyid (Test *test, gconstpointer unused) -{ - if (g_test_trap_fork (50000, G_TEST_TRAP_SILENCE_STDERR)) { - /* Different keyid for secret part. This should fail with a warning */ - _gcr_gnupg_key_set_secret_records (test->key, test->secset); - exit (0); - } - - g_test_trap_assert_failed (); - g_test_trap_assert_stderr ("*pub and sec parts are not the same:*"); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - - g_test_add ("/gcr/gnupg-key/label", Test, NULL, setup, test_label, teardown); - g_test_add ("/gcr/gnupg-key/description", Test, NULL, setup, test_description, teardown); - g_test_add ("/gcr/gnupg-key/markup", Test, NULL, setup, test_markup, teardown); - g_test_add ("/gcr/gnupg-key/records", Test, NULL, setup, test_records, teardown); - g_test_add ("/gcr/gnupg-key/keyid", Test, NULL, setup, test_keyid, teardown); - g_test_add ("/gcr/gnupg-key/short_keyid", Test, NULL, setup, test_short_keyid, teardown); - g_test_add ("/gcr/gnupg-key/keyid_for_records", Test, NULL, setup, test_keyid_for_records, teardown); - g_test_add ("/gcr/gnupg-key/with_secret", Test, NULL, setup, test_with_secret, teardown); - g_test_add ("/gcr/gnupg-key/no_change_keyid", Test, NULL, setup, test_no_change_keyid, teardown); - g_test_add ("/gcr/gnupg-key/secret_mismatched_keyid", Test, NULL, setup, test_secret_mismatched_keyid, teardown); - - return g_test_run (); -} diff --git a/gcr/tests/test-gnupg-process.c b/gcr/tests/test-gnupg-process.c deleted file mode 100644 index 740b2329..00000000 --- a/gcr/tests/test-gnupg-process.c +++ /dev/null @@ -1,600 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2011 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr-base.h" -#include "gcr/gcr-callback-output-stream.h" -#include "gcr/gcr-gnupg-process.h" - -#include "egg/egg-testing.h" - -#include <glib.h> - -#include <errno.h> -#include <string.h> - -#define WAIT 50000 - -typedef struct { - GcrGnupgProcess *process; - GAsyncResult *result; - GString *output_buf; - GString *error_buf; - GString *attribute_buf; - GcrRecord *record; -} Test; - -static void -setup (Test *test, gconstpointer unused) -{ - test->output_buf = g_string_new (""); - test->error_buf = g_string_new (""); - test->attribute_buf = g_string_new (""); -} - -static void -teardown (Test *test, gconstpointer unused) -{ - g_assert (!test->result); - g_assert (!test->process); - if (test->output_buf) - g_string_free (test->output_buf, TRUE); - if (test->error_buf) - g_string_free (test->error_buf, TRUE); - if (test->attribute_buf) - g_string_free (test->attribute_buf, TRUE); - _gcr_record_free (test->record); -} - -static void -test_create (Test *test, gconstpointer unused) -{ - gchar *value; - - test->process = _gcr_gnupg_process_new ("/the/directory", "/path/to/executable"); - - g_object_get (test->process, "directory", &value, NULL); - g_assert_cmpstr (value, ==, "/the/directory"); - g_free (value); - - g_object_get (test->process, "executable", &value, NULL); - g_assert_cmpstr (value, ==, "/path/to/executable"); - g_free (value); - - g_clear_object (&test->process); -} - -static void -on_async_ready (GObject *source, GAsyncResult *result, gpointer user_data) -{ - Test *test = user_data; - - g_assert (G_OBJECT (test->process) == source); - g_assert (test->result == NULL); - g_assert (g_async_result_get_source_object (result) == source); - - test->result = g_object_ref (result); - egg_test_wait_stop (); -} - -static gchar* -build_script_path (const gchar *name) -{ - gchar *path; - - path = g_build_filename (SRCDIR, "files", "gnupg-mock", name, NULL); - - return path; -} - -static gssize -on_process_output_data (gconstpointer buffer, - gsize count, - GCancellable *cancellable, - gpointer user_data, - GError **error) -{ - Test *test = user_data; - g_string_append_len (test->output_buf, buffer, count); - return count; -} - -static gssize -on_process_attribute_data (gconstpointer buffer, - gsize count, - GCancellable *cancellable, - gpointer user_data, - GError **error) -{ - Test *test = user_data; - g_string_append_len (test->attribute_buf, buffer, count); - return count; -} - -static void -on_process_error_line (GcrGnupgProcess *process, const gchar *line, gpointer user_data) -{ - Test *test = user_data; - - g_assert (process == test->process); - g_assert (line); - g_assert (!strchr (line, '\n')); - - g_string_append_printf (test->error_buf, "%s\n", line); -} - -static void -on_process_status_record (GcrGnupgProcess *process, GcrRecord *record, gpointer user_data) -{ - Test *test = user_data; - - g_assert (process == test->process); - g_assert (record); - - g_assert (!test->record); - test->record = _gcr_record_copy (record); -} - -static void -test_run_simple_output (Test *test, gconstpointer unused) -{ - const gchar *argv[] = { NULL }; - GOutputStream *output; - GError *error = NULL; - gboolean ret; - gchar *script; - - script = build_script_path ("mock-simple-output"); - test->process = _gcr_gnupg_process_new (NULL, script); - g_free (script); - - output = _gcr_callback_output_stream_new (on_process_output_data, test, NULL); - _gcr_gnupg_process_set_output_stream (test->process, output); - g_object_unref (output); - - _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert_cmpstr ("simple-output\n", ==, test->output_buf->str); - - g_clear_object (&test->result); - g_clear_object (&test->process); -} - -static void -test_run_simple_error (Test *test, gconstpointer unused) -{ - const gchar *argv[] = { NULL }; - GError *error = NULL; - gchar *script; - gboolean ret; - - script = build_script_path ("mock-simple-error"); - test->process = _gcr_gnupg_process_new (NULL, script); - g_free (script); - - g_signal_connect (test->process, "error-line", G_CALLBACK (on_process_error_line), test); - - _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert_cmpstr ("line 1: more line 1\nline 2\nline 3\n", ==, test->error_buf->str); - - g_clear_object (&test->result); - g_clear_object (&test->process); -} - -static void -test_run_status_and_output (Test *test, gconstpointer unused) -{ - const gchar *argv[] = { NULL }; - GOutputStream *output; - GError *error = NULL; - gchar *script; - gboolean ret; - - script = build_script_path ("mock-status-and-output"); - test->process = _gcr_gnupg_process_new (NULL, script); - g_free (script); - - output = _gcr_callback_output_stream_new (on_process_output_data, test, NULL); - _gcr_gnupg_process_set_output_stream (test->process, output); - g_object_unref (output); - - g_signal_connect (test->process, "status-record", G_CALLBACK (on_process_status_record), test); - - _gcr_gnupg_process_run_async (test->process, argv, NULL, GCR_GNUPG_PROCESS_WITH_STATUS, - NULL, on_async_ready, test); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert (test->record); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 0), ==, "SCHEMA"); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 1), ==, "one"); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 2), ==, "two"); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 3), ==, "three"); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 4), ==, "four"); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 5), ==, NULL); - g_assert_cmpstr ("Here's some output\nMore output\n", ==, test->output_buf->str); - - g_clear_object (&test->result); - g_clear_object (&test->process); -} - -static void -test_run_status_and_attribute (Test *test, gconstpointer unused) -{ - const gchar *argv[] = { NULL }; - GOutputStream *output; - GError *error = NULL; - gchar *script; - gboolean ret; - - script = build_script_path ("mock-status-and-attribute"); - test->process = _gcr_gnupg_process_new (NULL, script); - g_free (script); - - output = _gcr_callback_output_stream_new (on_process_attribute_data, test, NULL); - _gcr_gnupg_process_set_attribute_stream (test->process, output); - g_object_unref (output); - - g_signal_connect (test->process, "status-record", G_CALLBACK (on_process_status_record), test); - - _gcr_gnupg_process_run_async (test->process, argv, NULL, - GCR_GNUPG_PROCESS_WITH_STATUS | GCR_GNUPG_PROCESS_WITH_ATTRIBUTES, - NULL, on_async_ready, test); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - g_assert (test->record); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 0), ==, "SCHEMA"); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 1), ==, "one"); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 2), ==, "two"); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 3), ==, "three"); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 4), ==, "four"); - g_assert_cmpstr (_gcr_record_get_raw (test->record, 5), ==, NULL); - g_assert_cmpstr ("1lc923g4laoeurc23rc241lcg2r23c4gr3", ==, test->attribute_buf->str); - - g_clear_object (&test->result); - g_clear_object (&test->process); -} - - -static void -test_run_arguments_and_environment (Test *test, gconstpointer unused) -{ - GError *error = NULL; - GOutputStream *output; - gchar *script; - gboolean ret; - - const gchar *argv[] = { - "-1", "value1", - "-2", "value2", - NULL - }; - - const gchar *envp[] = { - "ENVIRON1=VALUE1", - "ENVIRON2=VALUE2", - NULL - }; - - script = build_script_path ("mock-arguments-environ"); - test->process = _gcr_gnupg_process_new (NULL, script); - g_free (script); - - output = _gcr_callback_output_stream_new (on_process_output_data, test, NULL); - _gcr_gnupg_process_set_output_stream (test->process, output); - g_object_unref (output); - - g_signal_connect (test->process, "error-line", G_CALLBACK (on_process_error_line), test); - - _gcr_gnupg_process_run_async (test->process, argv, envp, 0, NULL, on_async_ready, test); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - if (error) { - g_printerr ("%s\n", test->error_buf->str); - g_assert_no_error (error); - } - g_assert (ret == TRUE); - - g_assert_cmpstr ("value1\nvalue2\n", ==, test->output_buf->str); - g_assert_cmpstr ("VALUE1VALUE2\n", ==, test->error_buf->str); - - g_clear_object (&test->result); - g_clear_object (&test->process); -} - -static void -test_run_with_homedir (Test *test, gconstpointer unused) -{ - const gchar *argv[] = { NULL }; - GOutputStream *output; - GError *error = NULL; - gchar *script; - gchar *check; - gboolean ret; - - script = build_script_path ("mock-with-homedir"); - test->process = _gcr_gnupg_process_new (SRCDIR, script); - g_free (script); - - output = _gcr_callback_output_stream_new (on_process_output_data, test, NULL); - _gcr_gnupg_process_set_output_stream (test->process, output); - g_object_unref (output); - - _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - check = g_strdup_printf ("DIR: %s\n", SRCDIR); - g_assert_cmpstr (check, ==, test->output_buf->str); - g_free (check); - - g_clear_object (&test->result); - g_clear_object (&test->process); -} - -static void -test_run_with_input_and_output (Test *test, - gconstpointer unused) -{ - const gchar *argv[] = { NULL }; - const gchar *data = "one\ntwenty two\nthree\nfourty four\n"; - GInputStream *input; - GOutputStream *output; - GError *error = NULL; - GString *string; - gchar *script; - gboolean ret; - - script = build_script_path ("mock-echo"); - test->process = _gcr_gnupg_process_new (SRCDIR, script); - g_free (script); - - input = g_memory_input_stream_new_from_data ((gpointer)data, -1, NULL); - output = g_memory_output_stream_new (NULL, 0, g_realloc, g_free); - - _gcr_gnupg_process_set_input_stream (test->process, input); - _gcr_gnupg_process_set_output_stream (test->process, output); - - _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - g_assert_no_error (error); - g_assert (ret == TRUE); - - string = g_string_new_len (g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (output)), - g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (output))); - g_assert_cmpstr (data, ==, string->str); - g_string_free (string, TRUE); - - g_clear_object (&input); - g_clear_object (&output); - g_clear_object (&test->result); - g_clear_object (&test->process); - -} - -static void -test_run_bad_executable (Test *test, gconstpointer unused) -{ - GError *error = NULL; - gchar *script; - const gchar *argv[] = { NULL }; - gboolean ret; - - script = build_script_path ("mock-invalid"); - test->process = _gcr_gnupg_process_new (NULL, script); - g_free (script); - - _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_NOENT); - g_clear_error (&error); - g_assert (ret == FALSE); - - g_clear_object (&test->result); - g_clear_object (&test->process); -} - -static void -test_run_fail_exit (Test *test, gconstpointer unused) -{ - GError *error = NULL; - gchar *script; - const gchar *argv[] = { "55" }; - gboolean ret; - - script = build_script_path ("mock-fail-exit"); - test->process = _gcr_gnupg_process_new (NULL, script); - g_free (script); - - _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED); - g_assert_cmpstr (error->message, ==, "Gnupg process exited with code: 55"); - g_clear_error (&error); - g_assert (ret == FALSE); - - g_clear_object (&test->result); - g_clear_object (&test->process); -} - -static void -test_run_fail_signal (Test *test, gconstpointer unused) -{ - GError *error = NULL; - gchar *script; - const gchar *argv[] = { "15" }; - gboolean ret; - - script = build_script_path ("mock-fail-signal"); - test->process = _gcr_gnupg_process_new (NULL, script); - g_free (script); - - _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, NULL, on_async_ready, test); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - g_assert_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED); - g_assert_cmpstr (error->message, ==, "Gnupg process was terminated with signal: 15"); - g_clear_error (&error); - g_assert (ret == FALSE); - - g_clear_object (&test->result); - g_clear_object (&test->process); -} - -static void -test_run_and_cancel (Test *test, gconstpointer unused) -{ - GError *error = NULL; - gchar *script; - const gchar *argv[] = { "15" }; - GCancellable *cancellable; - gboolean ret; - - cancellable = g_cancellable_new (); - - script = build_script_path ("mock-simple-output"); - test->process = _gcr_gnupg_process_new (NULL, script); - g_free (script); - - _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, cancellable, on_async_ready, test); - g_cancellable_cancel (cancellable); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); - g_clear_error (&error); - g_assert (ret == FALSE); - - g_object_unref (cancellable); - g_clear_object (&test->result); - g_clear_object (&test->process); -} - -static gssize -on_process_output_cancel (gconstpointer buffer, - gsize count, - GCancellable *cancellable, - gpointer user_data, - GError **error) -{ - g_cancellable_cancel (cancellable); - g_cancellable_set_error_if_cancelled (cancellable, error); - return -1; -} - -static void -test_run_and_cancel_later (Test *test, gconstpointer unused) -{ - GError *error = NULL; - GOutputStream *output; - gchar *script; - const gchar *argv[] = { "15" }; - GCancellable *cancellable; - gboolean ret; - - cancellable = g_cancellable_new (); - - script = build_script_path ("mock-simple-output"); - test->process = _gcr_gnupg_process_new (NULL, script); - output = _gcr_callback_output_stream_new (on_process_output_cancel, NULL, NULL); - _gcr_gnupg_process_set_output_stream (test->process, output); - g_object_unref (output); - g_free (script); - - _gcr_gnupg_process_run_async (test->process, argv, NULL, 0, cancellable, on_async_ready, test); - egg_test_wait_until (WAIT); - - g_assert (test->result); - ret = _gcr_gnupg_process_run_finish (test->process, test->result, &error); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); - g_clear_error (&error); - g_assert (ret == FALSE); - - g_object_unref (cancellable); - g_clear_object (&test->result); - g_clear_object (&test->process); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - g_set_prgname ("test-gnupg-process"); - - g_test_add ("/gcr/gnupg-process/create", Test, NULL, setup, test_create, teardown); - g_test_add ("/gcr/gnupg-process/run_simple_output", Test, NULL, setup, test_run_simple_output, teardown); - g_test_add ("/gcr/gnupg-process/run_simple_error", Test, NULL, setup, test_run_simple_error, teardown); - g_test_add ("/gcr/gnupg-process/run_status_and_output", Test, NULL, setup, test_run_status_and_output, teardown); - g_test_add ("/gcr/gnupg-process/run_status_and_attribute", Test, NULL, setup, test_run_status_and_attribute, teardown); - g_test_add ("/gcr/gnupg-process/run_arguments_and_environment", Test, NULL, setup, test_run_arguments_and_environment, teardown); - g_test_add ("/gcr/gnupg-process/run_with_homedir", Test, NULL, setup, test_run_with_homedir, teardown); - g_test_add ("/gcr/gnupg-process/run_with_input_and_output", Test, NULL, setup, test_run_with_input_and_output, teardown); - g_test_add ("/gcr/gnupg-process/run_bad_executable", Test, NULL, setup, test_run_bad_executable, teardown); - g_test_add ("/gcr/gnupg-process/run_fail_exit", Test, NULL, setup, test_run_fail_exit, teardown); - g_test_add ("/gcr/gnupg-process/run_fail_signal", Test, NULL, setup, test_run_fail_signal, teardown); - g_test_add ("/gcr/gnupg-process/run_and_cancel", Test, NULL, setup, test_run_and_cancel, teardown); - g_test_add ("/gcr/gnupg-process/run_and_cancel_later", Test, NULL, setup, test_run_and_cancel_later, teardown); - - return egg_tests_run_in_thread_with_loop (); -} diff --git a/gcr/tests/test-memory-icon.c b/gcr/tests/test-memory-icon.c deleted file mode 100644 index c232be19..00000000 --- a/gcr/tests/test-memory-icon.c +++ /dev/null @@ -1,206 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2011 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr-memory-icon.h" - -#include "egg/egg-testing.h" - -#include <glib.h> - -#include <errno.h> -#include <stdlib.h> -#include <string.h> - -typedef struct { - GIcon *icon; - GAsyncResult *result; -} Test; - -static const guint8 test_data[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, -}; - -static void -setup (Test *test, gconstpointer unused) -{ - test->icon = _gcr_memory_icon_new ("application/octet-stream", - test_data, sizeof (test_data)); -} - -static void -teardown (Test *test, gconstpointer unused) -{ - g_object_unref (test->icon); - if (test->result) - g_object_unref (test->result); -} - -static void -test_equal_same (Test *test, gconstpointer unused) -{ - g_assert (g_icon_equal (test->icon, test->icon) == TRUE); -} - -static void -test_equal_not (Test *test, gconstpointer unused) -{ - GIcon *icon; - - icon = g_themed_icon_new ("folder"); - g_assert (g_icon_equal (test->icon, icon) == FALSE); - g_object_unref (icon); -} - -static void -test_equal_data (Test *test, gconstpointer unused) -{ - GIcon *icon; - - icon = _gcr_memory_icon_new ("application/octet-stream", - test_data, sizeof (test_data)); - g_assert (g_icon_equal (test->icon, icon) == TRUE); - g_assert_cmpuint (g_icon_hash (test->icon), ==, g_icon_hash (icon)); - g_object_unref (icon); -} - -static void -test_different_type (Test *test, gconstpointer unused) -{ - GIcon *icon; - - icon = _gcr_memory_icon_new ("application/x-other", - test_data, sizeof (test_data)); - g_assert (g_icon_equal (test->icon, icon) == FALSE); - g_assert_cmpuint (g_icon_hash (test->icon), !=, g_icon_hash (icon)); - g_object_unref (icon); -} - -static void -test_different_offset (Test *test, gconstpointer unused) -{ - GIcon *icon; - - icon = _gcr_memory_icon_new_full ("application/octet-stream", (gpointer)test_data, - sizeof (test_data) - 16, 16, NULL); - g_assert (g_icon_equal (test->icon, icon) == FALSE); - g_assert_cmpuint (g_icon_hash (test->icon), !=, g_icon_hash (icon)); - g_object_unref (icon); -} - -static void -test_load_sync (Test *test, gconstpointer unused) -{ - GError *error = NULL; - GInputStream *is; - gchar buf[1024]; - gsize length; - gchar *type; - - is = g_loadable_icon_load (G_LOADABLE_ICON (test->icon), 0, &type, NULL, &error); - g_assert (is != NULL); - g_assert_no_error (error); - g_assert_cmpstr (type, ==, "application/octet-stream"); - - if (!g_input_stream_read_all (is, buf, sizeof (buf), &length, NULL, &error)) - g_assert_not_reached (); - g_assert_no_error (error); - egg_assert_cmpsize (length, ==, sizeof (test_data)); - egg_assert_cmpmem (buf, length, ==, test_data, sizeof (test_data)); - - g_free (type); - g_object_unref (is); -} - -static void -on_async_ready (GObject *source, GAsyncResult *result, gpointer user_data) -{ - Test *test = user_data; - - g_assert (G_OBJECT (test->icon) == source); - g_assert (test->result == NULL); - g_assert (g_async_result_get_source_object (result) == source); - - test->result = g_object_ref (result); - egg_test_wait_stop (); -} - -static void -test_load_async (Test *test, gconstpointer unused) -{ - GError *error = NULL; - GInputStream *is; - gchar buf[1024]; - gsize length; - gchar *type; - - g_loadable_icon_load_async (G_LOADABLE_ICON (test->icon), 0, NULL, on_async_ready, test); - egg_test_wait_until (500); - - g_assert (test->result); - is = g_loadable_icon_load_finish (G_LOADABLE_ICON (test->icon), test->result, &type, &error); - g_assert (is != NULL); - g_assert_no_error (error); - g_assert_cmpstr (type, ==, "application/octet-stream"); - - if (!g_input_stream_read_all (is, buf, sizeof (buf), &length, NULL, &error)) - g_assert_not_reached (); - g_assert_no_error (error); - egg_assert_cmpsize (length, ==, sizeof (test_data)); - egg_assert_cmpmem (buf, length, ==, test_data, sizeof (test_data)); - - g_free (type); - g_object_unref (is); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - - g_test_add ("/gcr/memory-icon/equal_same", Test, NULL, setup, test_equal_same, teardown); - g_test_add ("/gcr/memory-icon/equal_not", Test, NULL, setup, test_equal_not, teardown); - g_test_add ("/gcr/memory-icon/equal_data", Test, NULL, setup, test_equal_data, teardown); - g_test_add ("/gcr/memory-icon/different_type", Test, NULL, setup, test_different_type, teardown); - g_test_add ("/gcr/memory-icon/different_offset", Test, NULL, setup, test_different_offset, teardown); - g_test_add ("/gcr/memory-icon/load_sync", Test, NULL, setup, test_load_sync, teardown); - g_test_add ("/gcr/memory-icon/load_async", Test, NULL, setup, test_load_async, teardown); - - return egg_tests_run_in_thread_with_loop (); -} diff --git a/gcr/tests/test-openpgp.c b/gcr/tests/test-openpgp.c deleted file mode 100644 index be41f407..00000000 --- a/gcr/tests/test-openpgp.c +++ /dev/null @@ -1,354 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2011 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr.h" -#include "gcr/gcr-openpgp.h" -#include "gcr/gcr-record.h" - -#include "egg/egg-armor.h" -#include "egg/egg-testing.h" - -#include <gcrypt.h> -#include <glib.h> -#include <string.h> - -typedef struct { - const gchar *name; - const gchar **records; - const gchar *filename; - const gchar *version; - GcrOpenpgpParseFlags flags; -} Fixture; - -static const gchar *werner_koch_records[] = { - "pub:e:1024:17:68B7AB8957548DCD:899816990:1136043547::o:::sca:\n" - "fpr:::::::::6BD9050FD8FC941B43412DCC68B7AB8957548DCD:\n" - "uid:e::::1102866526::B712A25DC2ABEF1579696C2925859931078C2C3E::Werner Koch (gnupg sig) <dd9jn@gnu.org>:\n", - - "pub:e:1024:17:5DE249965B0358A2:921520361:1247335656::o:::sc:\n" - "fpr:::::::::A4D94E92B0986AB5EE9DCD755DE249965B0358A2:\n" - "uid:e::::1113145458::F5B5738FAFB7543A01BAB31A6D767FBC789FF8A8::Werner Koch <wk@gnupg.org>:\n" - "uid:e::::1113145466::60095F7DAD08129CCE39E15BEB6BBE21937E3AA6::Werner Koch <wk@g10code.com>:\n" - "uid:e::::921520362::392B892CF897AD0F03EB26343C4C20A48B36513E::Werner Koch:\n" - "uid:e::::1113145466::3E000C0F7D13A3C57C633C16ABDC97F12EAF16C1::Werner Koch <werner@fsfe.org>:\n" - "sub:e:1024:17:60784E94010A57ED:1079892559:1199124559:::::s:\n" - "sub:e:2048:1:7299C628B604F148:1079892777:1136052777:::::e:\n" - "sub:e:2048:1:35E52D69C3680A6E:1136137762:1199123362:::::e:\n", - - "pub:e:1024:1:53B620D01CE0C630:1136130759:1230738759::o:::sc:\n" - "fpr:::::::::7B96D396E6471601754BE4DB53B620D01CE0C630:\n" - "uid:e::::1136130760::142B958D9816ECF810DBB83BD257E5C7DB36C99A::Werner Koch (dist sig) <dd9jn@gnu.org>:\n", - - NULL -}; - -static const gchar *werner_sig_records[] = { - "pub:e:1024:17:68B7AB8957548DCD:899816990:1136043547::o:::sca:\n" - "fpr:::::::::6BD9050FD8FC941B43412DCC68B7AB8957548DCD:\n" - "uid:e::::1102866526::B712A25DC2ABEF1579696C2925859931078C2C3E::Werner Koch (gnupg sig) <dd9jn@gnu.org>:\n" - "sig:::17:68B7AB8957548DCD:1102866526:::::13x:\n", - - "pub:e:1024:17:5DE249965B0358A2:921520361:1247335656::o:::sc:\n" - "fpr:::::::::A4D94E92B0986AB5EE9DCD755DE249965B0358A2:\n" - "uid:e::::1113145458::F5B5738FAFB7543A01BAB31A6D767FBC789FF8A8::Werner Koch <wk@gnupg.org>:\n" - "sig:::17:5DE249965B0358A2:1113145458:::::13x:\n" - "uid:e::::1113145466::60095F7DAD08129CCE39E15BEB6BBE21937E3AA6::Werner Koch <wk@g10code.com>:\n" - "sig:::17:5DE249965B0358A2:1113145466:::::13x:\n" - "uid:e::::921520362::392B892CF897AD0F03EB26343C4C20A48B36513E::Werner Koch:\n" - "sig:::17:5DE249965B0358A2:921520362:::::13x:\n" - "uid:e::::1113145466::3E000C0F7D13A3C57C633C16ABDC97F12EAF16C1::Werner Koch <werner@fsfe.org>:\n" - "sig:::17:5DE249965B0358A2:1113145466:::::13x:\n" - "sub:e:1024:17:60784E94010A57ED:1079892559:1199124559:::::s:\n" - "sig:::17:5DE249965B0358A2:1148562461:::::18x:\n" - "sub:e:2048:1:7299C628B604F148:1079892777:1136052777:::::e:\n" - "sig:::17:5DE249965B0358A2:1079892777:::::18x:\n" - "sub:e:2048:1:35E52D69C3680A6E:1136137762:1199123362:::::e:\n" - "sig:::17:5DE249965B0358A2:1136137762:::::18x:\n", - - "pub:e:1024:1:53B620D01CE0C630:1136130759:1230738759::o:::sc:\n" - "fpr:::::::::7B96D396E6471601754BE4DB53B620D01CE0C630:\n" - "uid:e::::1136130760::142B958D9816ECF810DBB83BD257E5C7DB36C99A::Werner Koch (dist sig) <dd9jn@gnu.org>:\n" - "sig:::1:53B620D01CE0C630:1136130760:::::13x:\n", - - NULL -}; - -static const gchar *pubring_records[] = { - "pub:o:2048:1:4842D952AFC000FD:1305189489:::o:::scSCE:\n" - "fpr:::::::::61A6EA3E0115080227A32EC94842D952AFC000FD:\n" - "uid:o::::1305189489::D449F1605254754B0BBFA424FC34E50609103BBB::Test Number 1 (unlimited) <test-number-1@example.com>:\n" - "uid:o::::1305189849::D0A8FA7B15DC4BE3F8F03A49C372F2718C78AFC0::Dr. Strangelove <lovingbomb@example.com>:\n" - "sub:o:2048:1:4852132BBED15014:1305189489::::::e:\n", - - "pub:e:1024:1:268FEE686262C395:1305189628:1305276028::o:::sc:\n" - "fpr:::::::::A4853C22EA82C8ADC6692751268FEE686262C395:\n" - "uid:e::::1305189628::2E9D48BD771DA765D2B48A0233D0E8F393F6E839::Test Number 2 (all gone) <test-number-2@example.com>:\n" - "sub:e:1024:1:C5877FABF4772E4F:1305189628:1305276028:::::e:\n", - - "pub:e:1024:17:68B7AB8957548DCD:899816990:1136043547::o:::sca:\n" - "fpr:::::::::6BD9050FD8FC941B43412DCC68B7AB8957548DCD:\n" - "uid:e::::1102866526::B712A25DC2ABEF1579696C2925859931078C2C3E::Werner Koch (gnupg sig) <dd9jn@gnu.org>:\n", - - "pub:e:1024:17:5DE249965B0358A2:921520361:1247335656::o:::sc:\n" - "fpr:::::::::A4D94E92B0986AB5EE9DCD755DE249965B0358A2:\n" - "uid:e::::1113145458::F5B5738FAFB7543A01BAB31A6D767FBC789FF8A8::Werner Koch <wk@gnupg.org>:\n" - "uid:e::::1113145466::60095F7DAD08129CCE39E15BEB6BBE21937E3AA6::Werner Koch <wk@g10code.com>:\n" - "uid:e::::921520362::392B892CF897AD0F03EB26343C4C20A48B36513E::Werner Koch:\n" - "uid:e::::1113145466::3E000C0F7D13A3C57C633C16ABDC97F12EAF16C1::Werner Koch <werner@fsfe.org>:\n" - "sub:e:1024:17:60784E94010A57ED:1079892559:1199124559:::::s:\n" - "sub:e:2048:1:7299C628B604F148:1079892777:1136052777:::::e:\n" - "sub:e:2048:1:35E52D69C3680A6E:1136137762:1199123362:::::e:\n", - - "pub:o:1024:17:C7463639B2D7795E:978642983:::o:::scSCE:\n" - "fpr:::::::::055FC78F112193492C4F37AFC7463639B2D7795E:\n" - "rvk:o::17::::::3FC732041D23E9EA66DDB5009C9DBC21DF74DC61:80:\n" - "uid:o::::978642983::44C6F00AAE524A8955CAB76F2BB16126530BB203::Philip R. Zimmermann <prz@mit.edu>:\n" - "uid:o::::978643127::BD93DF0D0D564E85F73ECBECFFB1B5BA5FF2838D::Philip R. Zimmermann <prz@acm.org>:\n" - "uat:o::::978751266::E0F87F37495D4ED247BB66A08D7360D8D81F9976::1 3391:\n" - "uat:o::::1013326898::10A2C49F62C540090ECD679C518AACAA8E960BA5::1 3479:\n" - "uid:o::::1052692250::09D1F68A1C44AC42E7FCC5615EEDBB0FD581DCDE::Philip R. Zimmermann <prz@philzimmermann.com>:\n" - "sub:o:3072:16:C4EB1C56A8E92834:978642983::::::e:\n", - - "pub:o:4096:1:DB698D7199242560:1012189561:::o:::scSCEA:\n" - "fpr:::::::::7D92FD313AB6F3734CC59CA1DB698D7199242560:\n" - "uid:o::::1012189561::0E5FC22DD5518890217F20F1FF832597932B46C1::David M. Shaw <dshaw@jabberwocky.com>:\n" - "sub:o:2048:16:AE2827D11643B926:1012189956:1327549956:::::e:\n" - "sub:o:1024:17:E2665C8749E1CBC9:1012190171:1327550171:::::sca:\n", - - "pub:o:2048:1:9710B89BCA57AD7C:1102303986:::o:::scSC:\n" - "fpr:::::::::50BB6FFC9719DFD2BEBB04C69710B89BCA57AD7C:\n" - "uid:o::::1112650864::A96F758EFD5D67EA9450860C7D15A96DAA1B40E2::PGP Global Directory Verification Key:\n" - "uat:o::::1112650864::83B0B68B95892BBCE32F04BA0FBAC6CEAD4EDE49::1 3422:\n", - - "pub:e:1024:1:53B620D01CE0C630:1136130759:1230738759::o:::sc:\n" - "fpr:::::::::7B96D396E6471601754BE4DB53B620D01CE0C630:\n" - "uid:e::::1136130760::142B958D9816ECF810DBB83BD257E5C7DB36C99A::Werner Koch (dist sig) <dd9jn@gnu.org>:\n", - - NULL -}; - -static const gchar *secring_records[] = { - "sec::2048:1:4842D952AFC000FD:1305189489::::::::::\n" - "fpr:::::::::61A6EA3E0115080227A32EC94842D952AFC000FD:\n" - "uid:::::::D449F1605254754B0BBFA424FC34E50609103BBB::Test Number 1 (unlimited) <test-number-1@example.com>:\n" - "uid:::::::D0A8FA7B15DC4BE3F8F03A49C372F2718C78AFC0::Dr. Strangelove <lovingbomb@example.com>:\n" - "ssb::2048:1:4852132BBED15014:1305189489::::::::::\n", - - "sec::1024:1:268FEE686262C395:1305189628:1305276028:::::::::\n" - "fpr:::::::::A4853C22EA82C8ADC6692751268FEE686262C395:\n" - "uid:::::::2E9D48BD771DA765D2B48A0233D0E8F393F6E839::Test Number 2 (all gone) <test-number-2@example.com>:\n" - "ssb::1024:1:C5877FABF4772E4F:1305189628::::::::::\n", - - NULL -}; - -static Fixture fixtures[] = { - { - "werner_koch", - werner_koch_records, - SRCDIR "/files/werner-koch.asc", - "GnuPG v1.4.11 (GNU/Linux)", - GCR_OPENPGP_PARSE_KEYS - }, - { - "werner_koch_with_sigs", - werner_sig_records, - SRCDIR "/files/werner-koch.asc", - "GnuPG v1.4.11 (GNU/Linux)", - GCR_OPENPGP_PARSE_KEYS | GCR_OPENPGP_PARSE_SIGNATURES - }, - { - "pubring", - pubring_records, - SRCDIR "/files/pubring.gpg", - NULL, - GCR_OPENPGP_PARSE_KEYS - }, - { - "secring", - secring_records, - SRCDIR "/files/secring.gpg", - NULL, - GCR_OPENPGP_PARSE_KEYS - } -}; - -typedef struct { - const gchar **at; - const Fixture *fixture; -} Test; - -static void -setup (Test *test, - gconstpointer data) -{ - const Fixture *fixture = data; - test->fixture = fixture; - test->at = fixture->records; -} - -static void -teardown (Test *test, - gconstpointer data) -{ - -} - -static void -compare_fixture_with_records (const gchar *fixture, - GPtrArray *records) -{ - gchar *record; - gchar **lines; - guint i; - - lines = g_strsplit (fixture, "\n", -1); - for (i = 0; i < records->len; i++) { - record = _gcr_record_format (records->pdata[i]); - g_assert_cmpstr (record, ==, lines[i]); - g_free (record); - } - - if (lines[i] == NULL) { - g_test_message ("more openpgp records parsed than in fixture"); - g_assert_not_reached (); - } - - g_strfreev (lines); -} - -static void -on_openpgp_packet (GPtrArray *records, - const guchar *outer, - gsize n_outer, - gpointer user_data) -{ - Test *test = user_data; - guint seen; - - /* Should be parseable again */ - seen = _gcr_openpgp_parse (outer, n_outer, test->fixture->flags | - GCR_OPENPGP_PARSE_NO_RECORDS, NULL, NULL); - g_assert_cmpuint (seen, ==, 1); - - if (*(test->at) == NULL) { - g_test_message ("more openpgp packets parsed than in fixture"); - g_assert_not_reached (); - } - - compare_fixture_with_records (*(test->at), records); - test->at++; -} - -static void -on_armor_parsed (GQuark type, - const guchar *data, - gsize n_data, - const gchar *outer, - gsize n_outer, - GHashTable *headers, - gpointer user_data) -{ - Test *test = user_data; - const gchar *value; - guint seen; - - if (test->fixture->version) { - value = g_hash_table_lookup (headers, "Version"); - g_assert_cmpstr (value, ==, test->fixture->version); - } - - seen = _gcr_openpgp_parse (data, n_data, test->fixture->flags, - on_openpgp_packet, test); - g_assert_cmpuint (seen, >, 0); - - if (*(test->at) != NULL) { - g_test_message ("less openpgp packets parsed than in fixture"); - g_assert_not_reached (); - } -} - -static void -test_openpgp_armor (Test *test, - gconstpointer data) -{ - GError *error = NULL; - gchar *armor; - gsize length; - guint parts; - - g_file_get_contents (test->fixture->filename, &armor, &length, &error); - g_assert_no_error (error); - - parts = egg_armor_parse (armor, length, on_armor_parsed, test); - g_assert_cmpuint (parts, ==, 1); - - g_free (armor); -} - -static void -test_openpgp_binary (Test *test, - gconstpointer data) -{ - GError *error = NULL; - gchar *binary; - gsize length; - guint seen; - - g_file_get_contents (test->fixture->filename, &binary, &length, &error); - g_assert_no_error (error); - - seen = _gcr_openpgp_parse (binary, length, test->fixture->flags, - on_openpgp_packet, test); - g_assert_cmpuint (seen, >, 0); - - if (*(test->at) != NULL) { - g_test_message ("less openpgp packets parsed than in fixture"); - g_assert_not_reached (); - } - - g_free (binary); -} - -int -main (int argc, char **argv) -{ - guint i; - gchar *test_path; - - g_type_init (); - g_test_init (&argc, &argv, NULL); - g_set_prgname ("test-openpgp"); - - for (i = 0; i < G_N_ELEMENTS (fixtures); i++) { - test_path = g_strdup_printf ("/gcr/openpgp/%s", fixtures[i].name); - if (g_str_has_suffix (fixtures[i].filename, ".asc")) - g_test_add (test_path, Test, fixtures + i, setup, test_openpgp_armor, teardown); - else - g_test_add (test_path, Test, fixtures + i, setup, test_openpgp_binary, teardown); - g_free (test_path); - } - - return g_test_run (); -} diff --git a/gcr/tests/test-openssh.c b/gcr/tests/test-openssh.c deleted file mode 100644 index 81634daf..00000000 --- a/gcr/tests/test-openssh.c +++ /dev/null @@ -1,196 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2011 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr.h" -#include "gcr/gcr-openssh.h" - -#include "egg/egg-testing.h" - -#include <gcrypt.h> -#include <glib.h> -#include <string.h> - -typedef struct { - const gchar *expected_label; - const gchar *expected_options; -} Test; - -#define OPENSSH_PUBLIC_RSA1 \ - "2048 65537 19574029774826276058535216798260123376543523095248321838931" \ - "8476099051534660565418100376122247153936738716140984293302866595208305" \ - "7124376564328644357957081508003798389808113087527047927841196160520784" \ - "3971799891833860159372766201922902824211581515042106928142039998651198" \ - "7806024885997262427984841536983221992403267030558391252672804492615887" \ - "9294713324466630490990131504557923061505441555447586185019409756877006" \ - "5871190731807718592844942425524851665039303855329966512492845780563670" \ - "0617451083369174928502647995734856960603065454655489558179113130210712" \ - "74638931037011169213563881172297734240201883475566393175838117784693 r" \ - "sa-key@example.com\n" - -#define OPENSSH_PUBLIC_RSA2 \ - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDCs8z2y0cCPYRAPkq8tAt6FC/kdfnR/p" \ - "8B2ZoY0oiLNt7kQEwJfexgwLqTxWYd2fSDUSSDPrsqAxZAwLLS/eF04kXiJO2VfqAWFpTL" \ - "NToERHpFF1yZQe26ELTlNNfna7LqfCRvpNDwu6AqndsT3eFt7DWvBDXbbEiTLW21Z2OFAA" \ - "H/J2iCFn4c0a8Myf7IaMYcy5GG3mpk39kEO4aNV/67U7kfooek24ObwD0vlXzlsi5VZIUF" \ - "OIUi0UdkNEMCtUWpfkZ1STUlmwp9HVM7xb7/9PESQKDnZdxpB09S9cIjdpDecpDlMDDEbE" \ - "UECM1PIas3ndhB7gAN1i2JsPHTcXZ1 rsa-key@example.com\r\n" \ - "# Comment\n" - -#define OPENSSH_PUBLIC_DSA2 \ - "ssh-dss AAAAB3NzaC1kc3MAAACBAL4z+ad0ZJYzMOQuGp00UJ+AijKhrPVUEYLcxBmFQo" \ - "nb/KIlLSWJua4Rl9DB4tDj30Y9c/oApqC4n+FIYlUZMSnxmpvcLF6aeXOiHHPvm0EDYjjy" \ - "VubyYQWI7CROrrzSc+x++ha3TuJEvF3PlKlZmTKKVYEkZNjwFqYysGyPxPalAAAAFQDtDS" \ - "EF9Gvnv5fQtSbbsp7j78uVBwAAAIAtNpAg/Mbd/E2241enedB9AxAbJWZ5QYnoPe6/zx5d" \ - "OmU7+qz8mG6tgvF8F7IgXPabuAKslzTDGS3zgaEhWicDS3CIYik2UR8hXdxfovIEqZKZe7" \ - "u02FCEoXYCEiFUAdzDGzjI7PswgtEJWWNqKeNis3HmDDha9lMkqz/3fLZGXwAAAIEAiaRP" \ - "YKZDMoJG+aVZ5A3R/m2gl+mYE2MsjPKXuBKcrZ6ItA9BMe4G/An0/+E3A+DuoGxdeNNMF8" \ - "U9Dy2N8Sch/Ngtg2E/FBo5geljWobJXd1jxmPtF2WAliYJXDdIt6RBVPGL9H/KSjDmBMsV" \ - "d42wxVJywawzypklVZjSUuWuBMI= dsa-key@example.com \n" - -#define EXTRA_LINES_WITHOUT_KEY \ - "\n# Comment\n\n" \ - "20aa3\n" \ - "not a key\n" - -static void -setup (Test *test, - gconstpointer unused) -{ - -} - -static void -teardown (Test *test, - gconstpointer unused) -{ - -} - -static void -on_openssh_pub_parse (GckAttributes *attrs, - const gchar *label, - const gchar *options, - const gchar *outer, - gsize n_outer, - gpointer user_data) -{ - Test *test = user_data; - guint keys; - - if (test->expected_label) - g_assert_cmpstr (label, ==, test->expected_label); - if (test->expected_options) - g_assert_cmpstr (options, ==, test->expected_options); - - /* The block should parse properly */ - keys = _gcr_openssh_pub_parse (outer, n_outer, NULL, NULL); - g_assert_cmpuint (keys, ==, 1); -} - -static void -test_parse_v1_rsa (Test *test, - gconstpointer unused) -{ - const gchar *data = OPENSSH_PUBLIC_RSA1 EXTRA_LINES_WITHOUT_KEY; - gint keys; - - test->expected_label = "rsa-key@example.com"; - - keys = _gcr_openssh_pub_parse (data, strlen (data), - on_openssh_pub_parse, test); - g_assert_cmpint (keys, ==, 1); - -} - -static void -test_parse_v2_rsa (Test *test, - gconstpointer unused) -{ - const gchar *data = OPENSSH_PUBLIC_RSA2 EXTRA_LINES_WITHOUT_KEY; - gint keys; - - test->expected_label = "rsa-key@example.com"; - - keys = _gcr_openssh_pub_parse (data, strlen (data), - on_openssh_pub_parse, test); - g_assert_cmpint (keys, ==, 1); -} - -static void -test_parse_v2_dsa (Test *test, - gconstpointer unused) -{ - const gchar *data = OPENSSH_PUBLIC_DSA2 EXTRA_LINES_WITHOUT_KEY; - gint keys; - - test->expected_label = "dsa-key@example.com"; - - keys = _gcr_openssh_pub_parse (data, strlen (data), - on_openssh_pub_parse, test); - g_assert_cmpint (keys, ==, 1); -} - -static void -test_parse_v1_options (Test *test, - gconstpointer unused) -{ - const gchar *data = "option1,option2=\"value 2\",option3 " OPENSSH_PUBLIC_RSA1; - gint keys; - - test->expected_options = "option1,option2=\"value 2\",option3"; - - keys = _gcr_openssh_pub_parse (data, strlen (data), - on_openssh_pub_parse, test); - g_assert_cmpint (keys, ==, 1); -} - -static void -test_parse_v2_options (Test *test, - gconstpointer unused) -{ - const gchar *data = "option1,option2=\"value 2\",option3 " OPENSSH_PUBLIC_RSA2; - gint keys; - - test->expected_options = "option1,option2=\"value 2\",option3"; - - keys = _gcr_openssh_pub_parse (data, strlen (data), - on_openssh_pub_parse, test); - g_assert_cmpint (keys, ==, 1); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - g_set_prgname ("test-gnupg-process"); - - g_test_add ("/gcr/openssh/parse_v1_rsa", Test, NULL, setup, test_parse_v1_rsa, teardown); - g_test_add ("/gcr/openssh/parse_v2_rsa", Test, NULL, setup, test_parse_v2_rsa, teardown); - g_test_add ("/gcr/openssh/parse_v2_dsa", Test, NULL, setup, test_parse_v2_dsa, teardown); - g_test_add ("/gcr/openssh/parse_v1_options", Test, NULL, setup, test_parse_v1_options, teardown); - g_test_add ("/gcr/openssh/parse_v2_options", Test, NULL, setup, test_parse_v2_options, teardown); - - return egg_tests_run_in_thread_with_loop (); -} diff --git a/gcr/tests/test-parser.c b/gcr/tests/test-parser.c deleted file mode 100644 index 6984be29..00000000 --- a/gcr/tests/test-parser.c +++ /dev/null @@ -1,249 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* unit-test-pkix-parser.c: Test PKIX parser - - Copyright (C) 2007 Stefan Walter - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stef@memberwebs.com> -*/ - -#include "config.h" - -#include "egg/egg-error.h" -#include "egg/egg-secure-memory.h" - -#include "gcr/gcr-base.h" -#include "gcr/gcr-internal.h" - -#include "gck/gck.h" - -#include <glib.h> -#include <gcrypt.h> - -#include <errno.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -/* - * Each test looks like (on one line): - * void unit_test_xxxxx (CuTest* cu) - * - * Each setup looks like (on one line): - * void unit_setup_xxxxx (void); - * - * Each teardown looks like (on one line): - * void unit_teardown_xxxxx (void); - * - * Tests be run in the order specified here. - */ - -typedef struct { - GcrParser *parser; - const gchar* filedesc; -} Test; - -static void -ensure_block_can_be_parsed (GcrDataFormat format, - gconstpointer block, - gsize n_block) -{ - GcrParser *parser; - gboolean result; - GError *error = NULL; - - g_assert (block); - g_assert (n_block); - - parser = gcr_parser_new (); - gcr_parser_format_disable (parser, -1); - gcr_parser_format_enable (parser, format); - result = gcr_parser_parse_data (parser, block, n_block, &error); - - if (!result) { - g_critical ("The data returned from gcr_parser_get_parsed_block() " - "cannot be parsed: %s", error->message); - g_assert_not_reached (); - } - - g_object_unref (parser); -} - -static void -parsed_item (GcrParser *par, gpointer user_data) -{ - GckAttributes *attrs; - const gchar *description; - const gchar *label; - Test *test = user_data; - gconstpointer block; - gsize n_block; - GcrDataFormat format; - - g_assert (GCR_IS_PARSER (par)); - g_assert (par == test->parser); - - attrs = gcr_parser_get_parsed_attributes (test->parser); - g_assert (attrs); - - description = gcr_parser_get_parsed_description (test->parser); - label = gcr_parser_get_parsed_label (test->parser); - block = gcr_parser_get_parsed_block (test->parser, &n_block); - format = gcr_parser_get_parsed_format (test->parser); - ensure_block_can_be_parsed (format, block, n_block); - - if (g_test_verbose ()) - g_print ("%s: '%s'\n", description, label); -} - -static gboolean -authenticate (GcrParser *par, gint state, gpointer user_data) -{ - Test *test = user_data; - - g_assert (GCR_IS_PARSER (par)); - g_assert (par == test->parser); - - switch (state) { - case 0: - gcr_parser_add_password (test->parser, "booo"); - return TRUE; - default: - g_printerr ("decryption didn't work for: %s", test->filedesc); - g_assert_not_reached (); - return FALSE; - }; -} - -static void -setup (Test *test, gconstpointer unused) -{ - test->parser = gcr_parser_new (); - g_signal_connect (test->parser, "parsed", G_CALLBACK (parsed_item), test); - g_signal_connect (test->parser, "authenticate", G_CALLBACK (authenticate), test); -} - -static void -teardown (Test *test, gconstpointer unused) -{ - g_object_unref (test->parser); -} - -static void -test_parse_one (Test *test, - gconstpointer user_data) -{ - const gchar *path = user_data; - gchar *contents; - GError *error = NULL; - gboolean result; - gsize len; - - if (!g_file_get_contents (path, &contents, &len, NULL)) - g_assert_not_reached (); - - test->filedesc = path; - result = gcr_parser_parse_data (test->parser, (const guchar *)contents, len, &error); - g_assert_no_error (error); - g_assert (result); - - g_free (contents); -} - -static void -test_parse_null (void) -{ - GcrParser *parser = gcr_parser_new (); - GError *error = NULL; - gboolean result; - - result = gcr_parser_parse_data (parser, NULL, 0, &error); - g_assert_error (error, GCR_DATA_ERROR, GCR_ERROR_UNRECOGNIZED); - g_assert (!result); - g_error_free (error); - - g_object_unref (parser); -} - -static void -test_parse_empty (void) -{ - GcrParser *parser = gcr_parser_new (); - GError *error = NULL; - gboolean result; - - result = gcr_parser_parse_data (parser, (const guchar *)"", 0, &error); - g_assert_error (error, GCR_DATA_ERROR, GCR_ERROR_UNRECOGNIZED); - g_assert (!result); - g_error_free (error); - - g_object_unref (parser); -} - -int -main (int argc, char **argv) -{ - const gchar *filename; - GError *error = NULL; - GPtrArray *strings; - GDir *dir; - gchar *path; - gchar *lower; - gchar *test; - int ret; - - g_type_init (); - g_test_init (&argc, &argv, NULL); - g_set_prgname ("test-parser"); - - strings = g_ptr_array_new_with_free_func (g_free); - dir = g_dir_open (SRCDIR "/files", 0, &error); - g_assert_no_error (error); - - for (;;) { - filename = g_dir_read_name (dir); - if (!filename) - break; - if (filename[0] == '.') - continue; - - path = g_build_filename (SRCDIR "/files", filename, NULL); - - if (g_file_test (path, G_FILE_TEST_IS_DIR)) { - g_free (path); - continue; - } - - lower = g_ascii_strdown (filename, -1); - test = g_strdup_printf ("/gcr/parser/%s", - g_strcanon (lower, "abcdefghijklmnopqrstuvwxyz012345789", '_')); - g_free (lower); - - g_test_add (test, Test, path, setup, test_parse_one, teardown); - g_ptr_array_add (strings, path); - g_ptr_array_add (strings, test); - } - - g_dir_close (dir); - - g_test_add_func ("/gcr/parser/parse_null", test_parse_null); - g_test_add_func ("/gcr/parser/parse_empty", test_parse_empty); - - ret = g_test_run (); - g_ptr_array_free (strings, TRUE); - return ret; -} diff --git a/gcr/tests/test-pkcs11-certificate.c b/gcr/tests/test-pkcs11-certificate.c deleted file mode 100644 index dd03371b..00000000 --- a/gcr/tests/test-pkcs11-certificate.c +++ /dev/null @@ -1,279 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2010 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "egg/egg-asn1x.h" -#include "egg/egg-asn1-defs.h" - -#include "gcr/gcr-base.h" -#include "gcr/gcr-internal.h" - -#include "egg/egg-testing.h" - -#include "gck/gck-mock.h" -#include "gck/gck-test.h" - -#include "pkcs11/pkcs11n.h" - -#include <glib.h> - -#include <errno.h> - -typedef struct { - gpointer cert_data; - gsize n_cert_data; - gpointer cert2_data; - gsize n_cert2_data; - CK_FUNCTION_LIST funcs; -} Test; - -static void -setup (Test *test, gconstpointer unused) -{ - GList *modules = NULL; - GckAttributes *attrs; - CK_FUNCTION_LIST_PTR f; - GckModule *module; - gconstpointer subject; - gsize n_subject; - GNode *asn, *node; - CK_RV rv; - - if (!g_file_get_contents (SRCDIR "/files/der-certificate.crt", (gchar**)&test->cert_data, - &test->n_cert_data, NULL)) - g_assert_not_reached (); - g_assert (test->cert_data); - - if (!g_file_get_contents (SRCDIR "/files/der-certificate-dsa.cer", (gchar**)&test->cert2_data, - &test->n_cert2_data, NULL)) - g_assert_not_reached (); - g_assert (test->cert2_data); - - rv = gck_mock_C_GetFunctionList (&f); - gck_assert_cmprv (rv, ==, CKR_OK); - memcpy (&test->funcs, f, sizeof (test->funcs)); - - /* Open a session */ - rv = (test->funcs.C_Initialize) (NULL); - gck_assert_cmprv (rv, ==, CKR_OK); - - g_assert (!modules); - module = gck_module_new (&test->funcs); - modules = g_list_prepend (modules, module); - gcr_pkcs11_set_modules (modules); - gck_list_unref_free (modules); - - asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", - test->cert_data, test->n_cert_data); - g_assert (asn); - node = egg_asn1x_node (asn, "tbsCertificate", "subject", NULL); - subject = egg_asn1x_get_raw_element (node, &n_subject); - - /* Add a certificate to the module */ - attrs = gck_attributes_new (); - gck_attributes_add_data (attrs, CKA_VALUE, test->cert_data, test->n_cert_data); - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE); - gck_attributes_add_ulong (attrs, CKA_CERTIFICATE_TYPE, CKC_X_509); - gck_attributes_add_data (attrs, CKA_SUBJECT, subject, n_subject); - gck_mock_module_take_object (attrs); - - egg_asn1x_destroy (asn); -} - -static void -teardown (Test *test, gconstpointer unused) -{ - CK_RV rv; - - g_free (test->cert_data); - g_free (test->cert2_data); - - rv = (test->funcs.C_Finalize) (NULL); - gck_assert_cmprv (rv, ==, CKR_OK); -} - -static void -test_lookup_certificate_issuer (Test *test, gconstpointer unused) -{ - GcrCertificate *cert, *issuer; - GError *error = NULL; - GckAttributes *attrs; - GckAttribute *attr; - gconstpointer der; - gsize n_der; - - cert = gcr_simple_certificate_new_static (test->cert_data, test->n_cert_data); - g_assert (cert); - - /* Should be self-signed, so should find itself (added in setup) */ - issuer = gcr_pkcs11_certificate_lookup_issuer (cert, NULL, &error); - g_assert (GCR_IS_PKCS11_CERTIFICATE (issuer)); - g_assert (error == NULL); - - /* Should be the same certificate */ - der = gcr_certificate_get_der_data (issuer, &n_der); - egg_assert_cmpsize (n_der, ==, test->n_cert_data); - g_assert (memcmp (der, test->cert_data, test->n_cert_data) == 0); - - /* Should return the same certificate here too */ - attrs = gcr_pkcs11_certificate_get_attributes (GCR_PKCS11_CERTIFICATE (issuer)); - g_assert (attrs); - attr = gck_attributes_find (attrs, CKA_VALUE); - g_assert (attr); - egg_assert_cmpsize (attr->length, ==, test->n_cert_data); - g_assert (memcmp (attr->value, test->cert_data, test->n_cert_data) == 0); - - /* Should return the same certificate here too */ - attrs = NULL; - g_object_get (issuer, "attributes", &attrs, NULL); - g_assert (attrs); - attr = gck_attributes_find (attrs, CKA_VALUE); - g_assert (attr); - egg_assert_cmpsize (attr->length, ==, test->n_cert_data); - g_assert (memcmp (attr->value, test->cert_data, test->n_cert_data) == 0); - gck_attributes_unref (attrs); - - g_object_unref (cert); - g_object_unref (issuer); -} - -static void -test_lookup_certificate_issuer_not_found (Test *test, gconstpointer unused) -{ - GcrCertificate *cert, *issuer; - GError *error = NULL; - - cert = gcr_simple_certificate_new_static (test->cert2_data, test->n_cert2_data); - g_assert (cert); - - /* Issuer shouldn't be found */ - issuer = gcr_pkcs11_certificate_lookup_issuer (cert, NULL, &error); - g_assert (issuer == NULL); - g_assert (error == NULL); - - g_object_unref (cert); -} - -static void -fetch_async_result (GObject *source, GAsyncResult *result, gpointer user_data) -{ - *((GAsyncResult**)user_data) = result; - g_object_ref (result); - egg_test_wait_stop (); -} - -static void -test_lookup_certificate_issuer_async (Test *test, gconstpointer unused) -{ - GAsyncResult *result = NULL; - GcrCertificate *cert, *issuer; - GError *error = NULL; - gconstpointer der; - gsize n_der; - - cert = gcr_simple_certificate_new_static (test->cert_data, test->n_cert_data); - g_assert (cert); - - /* Should be self-signed, so should find itself (added in setup) */ - gcr_pkcs11_certificate_lookup_issuer_async (cert, NULL, fetch_async_result, &result); - egg_test_wait_until (500); - g_assert (result); - issuer = gcr_pkcs11_certificate_lookup_issuer_finish (result, &error); - g_assert (GCR_IS_PKCS11_CERTIFICATE (issuer)); - g_assert (error == NULL); - g_object_unref (result); - result = NULL; - - /* Should be the same certificate */ - der = gcr_certificate_get_der_data (issuer, &n_der); - egg_assert_cmpsize (n_der, ==, test->n_cert_data); - g_assert (memcmp (der, test->cert_data, test->n_cert_data) == 0); - - g_object_unref (cert); - g_object_unref (issuer); -} - -static void -test_lookup_certificate_issuer_failure (Test *test, gconstpointer unused) -{ - GcrCertificate *cert, *issuer; - GError *error = NULL; - - cert = gcr_simple_certificate_new_static (test->cert_data, test->n_cert_data); - g_assert (cert); - - /* Make the lookup fail */ - test->funcs.C_GetAttributeValue = gck_mock_fail_C_GetAttributeValue; - - issuer = gcr_pkcs11_certificate_lookup_issuer (cert, NULL, &error); - g_assert (issuer == NULL); - g_assert_error (error, GCK_ERROR, CKR_FUNCTION_FAILED); - g_assert (error->message); - g_clear_error (&error); - - g_object_unref (cert); -} - -static void -test_lookup_certificate_issuer_fail_async (Test *test, gconstpointer unused) -{ - GAsyncResult *result = NULL; - GcrCertificate *cert, *issuer; - GError *error = NULL; - - cert = gcr_simple_certificate_new_static (test->cert_data, test->n_cert_data); - g_assert (cert); - - /* Make the lookup fail */ - test->funcs.C_GetAttributeValue = gck_mock_fail_C_GetAttributeValue; - - /* Should be self-signed, so should find itself (added in setup) */ - gcr_pkcs11_certificate_lookup_issuer_async (cert, NULL, fetch_async_result, &result); - egg_test_wait_until (500); - g_assert (result); - issuer = gcr_pkcs11_certificate_lookup_issuer_finish (result, &error); - g_assert (issuer == NULL); - g_assert_error (error, GCK_ERROR, CKR_FUNCTION_FAILED); - g_assert (error->message); - g_clear_error (&error); - g_object_unref (result); - result = NULL; - - g_object_unref (cert); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - g_set_prgname ("test-pkcs11-certificate"); - - g_test_add ("/gcr/pkcs11-certificate/lookup_certificate_issuer", Test, NULL, setup, test_lookup_certificate_issuer, teardown); - g_test_add ("/gcr/pkcs11-certificate/lookup_certificate_issuer_not_found", Test, NULL, setup, test_lookup_certificate_issuer_not_found, teardown); - g_test_add ("/gcr/pkcs11-certificate/lookup_certificate_issuer_async", Test, NULL, setup, test_lookup_certificate_issuer_async, teardown); - g_test_add ("/gcr/pkcs11-certificate/lookup_certificate_issuer_failure", Test, NULL, setup, test_lookup_certificate_issuer_failure, teardown); - g_test_add ("/gcr/pkcs11-certificate/lookup_certificate_issuer_fail_async", Test, NULL, setup, test_lookup_certificate_issuer_fail_async, teardown); - - return egg_tests_run_in_thread_with_loop (); -} diff --git a/gcr/tests/test-record.c b/gcr/tests/test-record.c deleted file mode 100644 index cfb65932..00000000 --- a/gcr/tests/test-record.c +++ /dev/null @@ -1,294 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2011 Collabora Ltd. - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr-record.h" - -#include "egg/egg-testing.h" - -#include <glib.h> - -typedef struct { - GcrRecord *record; -} Test; - -static void -setup (Test *test, gconstpointer unused) -{ - test->record = _gcr_record_parse_colons ("one:tab\\there::YW9ldTM4Mzg=:f\xfc""nf:3533333:-88", -1); -} - -static void -teardown (Test *test, gconstpointer unused) -{ - _gcr_record_free (test->record); -} - -static void -test_count (Test *test, gconstpointer unused) -{ - g_assert_cmpuint (_gcr_record_get_count (test->record), ==, 7); -} - -static void -test_parse_colons (void) -{ - GcrRecord *record; - - record = _gcr_record_parse_colons ("one:two::four::six", -1); - g_assert (record); - - g_assert_cmpstr (_gcr_record_get_raw (record, 0), ==, "one"); - g_assert_cmpstr (_gcr_record_get_raw (record, 1), ==, "two"); - g_assert_cmpstr (_gcr_record_get_raw (record, 2), ==, ""); - g_assert_cmpstr (_gcr_record_get_raw (record, 3), ==, "four"); - g_assert_cmpstr (_gcr_record_get_raw (record, 4), ==, ""); - g_assert_cmpstr (_gcr_record_get_raw (record, 5), ==, "six"); - g_assert (_gcr_record_get_raw (record, 6) == NULL); - - _gcr_record_free (record); -} - -static void -test_parse_spaces (void) -{ - GcrRecord *record; - - record = _gcr_record_parse_spaces (" one two four six ", -1); - g_assert (record); - - g_assert_cmpstr (_gcr_record_get_raw (record, 0), ==, "one"); - g_assert_cmpstr (_gcr_record_get_raw (record, 1), ==, "two"); - g_assert_cmpstr (_gcr_record_get_raw (record, 2), ==, "four"); - g_assert_cmpstr (_gcr_record_get_raw (record, 3), ==, "six"); - g_assert (_gcr_record_get_raw (record, 4) == NULL); - g_assert_cmpuint (_gcr_record_get_count (record), ==, 4); - - _gcr_record_free (record); -} - -static void -test_parse_part (void) -{ - GcrRecord *record; - - record = _gcr_record_parse_colons ("one:two::four::six", 8); - g_assert (record); - - g_assert_cmpstr (_gcr_record_get_raw (record, 0), ==, "one"); - g_assert_cmpstr (_gcr_record_get_raw (record, 1), ==, "two"); - g_assert_cmpstr (_gcr_record_get_raw (record, 2), ==, ""); - g_assert (_gcr_record_get_raw (record, 3) == NULL); - - _gcr_record_free (record); -} - -static void -test_parse_too_long (void) -{ - GcrRecord *record; - - /* Too many columns */ - record = _gcr_record_parse_colons (":::::::::::::::::::::::::::::::::::::::::::::::::::::", -1); - g_assert (record == NULL); -} - -static void -test_find (void) -{ - GcrRecord *uid, *pub, *one, *check; - GPtrArray *records; - - records = g_ptr_array_new_with_free_func (_gcr_record_free); - - one = _gcr_record_parse_colons ("one:two::four::six", -1); - g_ptr_array_add (records, one); - pub = _gcr_record_parse_colons ("pub:two", -1); - g_ptr_array_add (records, pub); - uid = _gcr_record_parse_colons ("uid:two", -1); - g_ptr_array_add (records, uid); - - check = _gcr_records_find (records, GCR_RECORD_SCHEMA_PUB); - g_assert (check == pub); - - check = _gcr_records_find (records, GCR_RECORD_SCHEMA_UID); - g_assert (check == uid); - - g_ptr_array_unref (records); -} - -static void -test_get_string (Test *test, gconstpointer unused) -{ - gchar *value = _gcr_record_get_string (test->record, 1); - g_assert (value); - - g_assert_cmpstr (value, ==, "tab\there"); - g_free (value); -} - -static void -test_get_string_null (Test *test, gconstpointer unused) -{ - gchar *value = _gcr_record_get_string (test->record, 35); - g_assert (value == NULL); -} - -static void -test_get_string_latin1 (Test *test, gconstpointer unused) -{ - gchar *value = _gcr_record_get_string (test->record, 4); - g_assert (value); - - g_assert_cmpstr (value, ==, "f\xc3\xbc""nf"); - g_assert (g_utf8_validate (value, -1, NULL)); - g_free (value); -} - -static void -test_get_uint (Test *test, gconstpointer unused) -{ - guint value = 0; - - if (!_gcr_record_get_uint (test->record, 5, &value)) - g_assert_not_reached (); - g_assert_cmpuint (value, ==, 3533333); -} - -static void -test_get_uint_range (Test *test, gconstpointer unused) -{ - guint value = 0; - - if (_gcr_record_get_uint (test->record, 6, &value)) - g_assert_not_reached (); -} - -static void -test_get_uint_invalid (Test *test, gconstpointer unused) -{ - guint value = 0; - - if (_gcr_record_get_uint (test->record, 0, &value)) - g_assert_not_reached (); -} - -static void -test_get_base64 (Test *test, gconstpointer unused) -{ - gchar *value; - gsize n_value; - - value = _gcr_record_get_base64 (test->record, 3, &n_value); - g_assert (value); - egg_assert_cmpsize (n_value, ==, 8); - g_assert (memcmp (value, "aoeu3838", n_value) == 0); - - g_free (value); -} - - -static void -test_free_null (void) -{ - _gcr_record_free (NULL); -} - -static void -test_get_schema (Test *test, gconstpointer unused) -{ - GQuark schema; - GQuark check; - - /* Initialize this quark */ - check = g_quark_from_static_string ("one"); - - schema = _gcr_record_get_schema (test->record); - g_assert (check == schema); - g_assert_cmpstr (g_quark_to_string (schema), ==, "one"); -} - -static void -test_copy (Test *test, gconstpointer unused) -{ - GcrRecord *copy; - guint count, i; - - copy = _gcr_record_copy (test->record); - - count = _gcr_record_get_count (test->record); - g_assert_cmpuint (_gcr_record_get_count (copy), ==, count); - for (i = 0; i < count; i++) { - g_assert_cmpstr (_gcr_record_get_raw (copy, i), ==, - _gcr_record_get_raw (test->record, i)); - } - - g_assert (_gcr_record_get_raw (copy, count) == NULL); - _gcr_record_free (copy); -} - -static void -test_boxed (Test *test, gconstpointer unused) -{ - GcrRecord *copy; - guint count, i; - - copy = g_boxed_copy (GCR_TYPE_RECORD, test->record); - - count = _gcr_record_get_count (test->record); - g_assert_cmpuint (_gcr_record_get_count (copy), ==, count); - for (i = 0; i < count; i++) { - g_assert_cmpstr (_gcr_record_get_raw (copy, i), ==, - _gcr_record_get_raw (test->record, i)); - } - - g_assert (_gcr_record_get_raw (copy, count) == NULL); - g_boxed_free (GCR_TYPE_RECORD, copy); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - - g_test_add_func ("/gcr/record/parse_colons", test_parse_colons); - g_test_add_func ("/gcr/record/parse_colons", test_parse_spaces); - g_test_add_func ("/gcr/record/parse_part", test_parse_part); - g_test_add_func ("/gcr/record/parse_too_long", test_parse_too_long); - g_test_add_func ("/gcr/record/free_null", test_free_null); - g_test_add_func ("/gcr/record/find", test_find); - g_test_add ("/gcr/record/count", Test, NULL, setup, test_count, teardown); - g_test_add ("/gcr/record/copy", Test, NULL, setup, test_copy, teardown); - g_test_add ("/gcr/record/boxed", Test, NULL, setup, test_boxed, teardown); - g_test_add ("/gcr/record/get_string", Test, NULL, setup, test_get_string, teardown); - g_test_add ("/gcr/record/get_string_null", Test, NULL, setup, test_get_string_null, teardown); - g_test_add ("/gcr/record/get_string_latin1", Test, NULL, setup, test_get_string_latin1, teardown); - g_test_add ("/gcr/record/get_uint", Test, NULL, setup, test_get_uint, teardown); - g_test_add ("/gcr/record/get_uint_invalid", Test, NULL, setup, test_get_uint_invalid, teardown); - g_test_add ("/gcr/record/get_uint_range", Test, NULL, setup, test_get_uint_range, teardown); - g_test_add ("/gcr/record/get_base64", Test, NULL, setup, test_get_base64, teardown); - g_test_add ("/gcr/record/get_schema", Test, NULL, setup, test_get_schema, teardown); - - return g_test_run (); -} diff --git a/gcr/tests/test-secret-exchange.c b/gcr/tests/test-secret-exchange.c deleted file mode 100644 index 79647450..00000000 --- a/gcr/tests/test-secret-exchange.c +++ /dev/null @@ -1,162 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2011 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr.h" - -#include <glib.h> - -#include <errno.h> - -typedef struct { - GcrSecretExchange *caller; - GcrSecretExchange *callee; -} Test; - -static void -setup (Test *test, gconstpointer unused) -{ - test->caller = gcr_secret_exchange_new (NULL); - g_assert (GCR_IS_SECRET_EXCHANGE (test->caller)); - test->callee = gcr_secret_exchange_new (NULL); - g_assert (GCR_IS_SECRET_EXCHANGE (test->callee)); -} - -static void -teardown (Test *test, - gconstpointer unused) -{ - g_object_unref (test->caller); - g_assert (!GCR_IS_SECRET_EXCHANGE (test->caller)); - g_object_unref (test->callee); - g_assert (!GCR_IS_SECRET_EXCHANGE (test->callee)); -} - -static void -test_perform_exchange (Test *test, - gconstpointer unused) -{ - gchar *exchange; - - exchange = gcr_secret_exchange_begin (test->caller); - g_assert (exchange); - - if (!gcr_secret_exchange_receive (test->callee, exchange)) - g_assert_not_reached (); - - g_free (exchange); - - exchange = gcr_secret_exchange_send (test->callee, "the secret", -1); - g_assert (exchange); - - if (!gcr_secret_exchange_receive (test->caller, exchange)) - g_assert_not_reached (); - - g_assert_cmpstr (gcr_secret_exchange_get_secret (test->caller, NULL), ==, "the secret"); - - g_free (exchange); -} - -static void -test_perform_reverse (Test *test, - gconstpointer unused) -{ - gchar *exchange; - - exchange = gcr_secret_exchange_begin (test->caller); - g_assert (exchange); - - if (!gcr_secret_exchange_receive (test->callee, exchange)) - g_assert_not_reached (); - - g_free (exchange); - - exchange = gcr_secret_exchange_send (test->callee, NULL, -1); - g_assert (exchange); - - if (!gcr_secret_exchange_receive (test->caller, exchange)) - g_assert_not_reached (); - - g_free (exchange); - - g_assert (gcr_secret_exchange_get_secret (test->caller, NULL) == NULL); - - exchange = gcr_secret_exchange_send (test->caller, "reverse secret", -1); - g_assert (exchange); - - if (!gcr_secret_exchange_receive (test->callee, exchange)) - g_assert_not_reached (); - - g_free (exchange); - - g_assert_cmpstr (gcr_secret_exchange_get_secret (test->callee, NULL), ==, "reverse secret"); -} - -static void -test_perform_multiple (Test *test, - gconstpointer unused) -{ - gchar *exchange; - - exchange = gcr_secret_exchange_begin (test->caller); - g_assert (exchange); - - if (!gcr_secret_exchange_receive (test->callee, exchange)) - g_assert_not_reached (); - - g_free (exchange); - - exchange = gcr_secret_exchange_send (test->callee, "first secret", -1); - g_assert (exchange); - - if (!gcr_secret_exchange_receive (test->caller, exchange)) - g_assert_not_reached (); - - g_free (exchange); - - g_assert_cmpstr (gcr_secret_exchange_get_secret (test->caller, NULL), ==, "first secret"); - - exchange = gcr_secret_exchange_send (test->callee, "second secret", -1); - g_assert (exchange); - - if (!gcr_secret_exchange_receive (test->caller, exchange)) - g_assert_not_reached (); - - g_free (exchange); - - g_assert_cmpstr (gcr_secret_exchange_get_secret (test->caller, NULL), ==, "second secret"); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - g_set_prgname ("test-secret-exchange"); - - g_test_add ("/gcr/secret-exchange/perform-exchange", Test, NULL, setup, test_perform_exchange, teardown); - g_test_add ("/gcr/secret-exchange/perform-reverse", Test, NULL, setup, test_perform_reverse, teardown); - g_test_add ("/gcr/secret-exchange/perform-multiple", Test, NULL, setup, test_perform_multiple, teardown); - - return g_test_run (); -} diff --git a/gcr/tests/test-simple-certificate.c b/gcr/tests/test-simple-certificate.c deleted file mode 100644 index 60441359..00000000 --- a/gcr/tests/test-simple-certificate.c +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2010 Collabora Ltd - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr-base.h" -#include "gcr/gcr-internal.h" - -#include "gck/gck-test.h" - -#include "pkcs11/pkcs11n.h" - -#include "egg/egg-testing.h" - -#include <glib.h> - -#include <errno.h> - -typedef struct { - gpointer cert_data; - gsize n_cert_data; -} Test; - -static void -setup (Test *test, gconstpointer unused) -{ - if (!g_file_get_contents (SRCDIR "/files/der-certificate.crt", (gchar**)&test->cert_data, - &test->n_cert_data, NULL)) - g_assert_not_reached (); - g_assert (test->cert_data); -} - -static void -teardown (Test *test, gconstpointer unused) -{ - g_free (test->cert_data); -} - -static void -test_new (Test *test, gconstpointer unused) -{ - GcrCertificate *cert; - gconstpointer der; - gsize n_der; - - cert = gcr_simple_certificate_new (test->cert_data, test->n_cert_data); - g_assert (GCR_IS_SIMPLE_CERTIFICATE (cert)); - - der = gcr_certificate_get_der_data (cert, &n_der); - g_assert (der); - egg_assert_cmpmem (der, n_der, ==, test->cert_data, test->n_cert_data); - - g_object_unref (cert); -} - -static void -test_new_static (Test *test, gconstpointer unused) -{ - GcrCertificate *cert; - gconstpointer der; - gsize n_der; - - cert = gcr_simple_certificate_new_static (test->cert_data, test->n_cert_data); - g_assert (GCR_IS_SIMPLE_CERTIFICATE (cert)); - - der = gcr_certificate_get_der_data (cert, &n_der); - g_assert (der); - egg_assert_cmpsize (n_der, ==, test->n_cert_data); - g_assert (der == test->cert_data); /* Must be same pointer */ - - g_object_unref (cert); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - g_set_prgname ("test-simple-certificate"); - - g_test_add ("/gcr/simple-certificate/new", Test, NULL, setup, test_new, teardown); - g_test_add ("/gcr/simple-certificate/new_static", Test, NULL, setup, test_new_static, teardown); - - return g_test_run (); -} diff --git a/gcr/tests/test-trust.c b/gcr/tests/test-trust.c deleted file mode 100644 index d41596cf..00000000 --- a/gcr/tests/test-trust.c +++ /dev/null @@ -1,327 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2010 Stefan Walter - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stef@memberwebs.com> -*/ - -#include "config.h" - -#include "gcr/gcr-base.h" -#include "gcr/gcr-internal.h" - -#include "gck/gck-mock.h" -#include "gck/gck-test.h" - -#include "pkcs11/pkcs11.h" -#include "pkcs11/pkcs11n.h" -#include "pkcs11/pkcs11x.h" - -#include "egg/egg-testing.h" - -#include <glib.h> - -#include <errno.h> - -typedef struct { - CK_FUNCTION_LIST funcs; - GcrCertificate *certificate; -} Test; - -static void -setup (Test *test, gconstpointer unused) -{ - GList *modules = NULL; - CK_FUNCTION_LIST_PTR f; - GckModule *module; - gchar *contents; - const gchar *uris[2]; - gsize len; - CK_RV rv; - - if (!g_file_get_contents (SRCDIR "/files/der-certificate.crt", &contents, &len, NULL)) - g_assert_not_reached (); - g_assert (contents); - - test->certificate = gcr_simple_certificate_new ((const guchar *)contents, len); - g_free (contents); - - rv = gck_mock_C_GetFunctionList (&f); - gck_assert_cmprv (rv, ==, CKR_OK); - memcpy (&test->funcs, f, sizeof (test->funcs)); - - /* Open a session */ - rv = (test->funcs.C_Initialize) (NULL); - gck_assert_cmprv (rv, ==, CKR_OK); - - g_assert (!modules); - module = gck_module_new (&test->funcs); - modules = g_list_prepend (modules, module); - gcr_pkcs11_set_modules (modules); - gck_list_unref_free (modules); - - uris[0] = GCK_MOCK_SLOT_ONE_URI; - uris[1] = NULL; - - gcr_pkcs11_set_trust_store_uri (GCK_MOCK_SLOT_ONE_URI); - gcr_pkcs11_set_trust_lookup_uris (uris); -} - -static void -teardown (Test *test, gconstpointer unused) -{ - CK_RV rv; - - g_object_unref (test->certificate); - - rv = (test->funcs.C_Finalize) (NULL); - gck_assert_cmprv (rv, ==, CKR_OK); -} - -static void -test_is_pinned_none (Test *test, gconstpointer unused) -{ - GError *error = NULL; - gboolean trust; - - trust = gcr_trust_is_certificate_pinned (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, &error); - g_assert_cmpint (trust, ==, FALSE); - g_assert (error == NULL); -} - -static void -test_add_and_is_pinned (Test *test, gconstpointer unused) -{ - GError *error = NULL; - gboolean trust; - gboolean ret; - - trust = gcr_trust_is_certificate_pinned (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, &error); - g_assert_cmpint (trust, ==, FALSE); - g_assert (error == NULL); - - ret = gcr_trust_add_pinned_certificate (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, &error); - g_assert (ret == TRUE); - g_assert (error == NULL); - - trust = gcr_trust_is_certificate_pinned (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, &error); - g_assert_cmpint (trust, ==, TRUE); - g_assert (error == NULL); -} - -static void -test_add_certificate_pinned_fail (Test *test, gconstpointer unused) -{ - GError *error = NULL; - gboolean ret; - - /* Make this function fail */ - test->funcs.C_CreateObject = gck_mock_fail_C_CreateObject; - - ret = gcr_trust_add_pinned_certificate (test->certificate, GCR_PURPOSE_CLIENT_AUTH, "peer", NULL, &error); - g_assert (ret == FALSE); - g_assert_error (error, GCK_ERROR, CKR_FUNCTION_FAILED); - g_clear_error (&error); -} - -static void -test_add_and_remov_pinned (Test *test, gconstpointer unused) -{ - GError *error = NULL; - gboolean trust; - gboolean ret; - - ret = gcr_trust_add_pinned_certificate (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, &error); - g_assert (ret == TRUE); - g_assert (error == NULL); - - trust = gcr_trust_is_certificate_pinned (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, &error); - g_assert_cmpint (trust, ==, TRUE); - g_assert (error == NULL); - - ret = gcr_trust_remove_pinned_certificate (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, &error); - g_assert (ret == TRUE); - g_assert (error == NULL); - - trust = gcr_trust_is_certificate_pinned (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, &error); - g_assert_cmpint (trust, ==, FALSE); - g_assert (error == NULL); -} - -static void -fetch_async_result (GObject *source, GAsyncResult *result, gpointer user_data) -{ - *((GAsyncResult**)user_data) = result; - g_object_ref (result); - egg_test_wait_stop (); -} - -static void -test_add_and_is_pinned_async (Test *test, gconstpointer unused) -{ - GAsyncResult *result = NULL; - GError *error = NULL; - gboolean trust; - gboolean ret; - - gcr_trust_is_certificate_pinned_async (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, fetch_async_result, &result); - egg_test_wait_until (500); - g_assert (result); - trust = gcr_trust_is_certificate_pinned_finish (result, &error); - g_assert (trust == FALSE); - g_assert (error == NULL); - g_object_unref (result); - result = NULL; - - gcr_trust_add_pinned_certificate_async (test->certificate, GCR_PURPOSE_EMAIL, "host", - NULL, fetch_async_result, &result); - egg_test_wait_until (500); - g_assert (result); - ret = gcr_trust_add_pinned_certificate_finish (result, &error); - g_assert (ret == TRUE); - g_assert (error == NULL); - g_object_unref (result); - result = NULL; - - gcr_trust_is_certificate_pinned_async (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, fetch_async_result, &result); - egg_test_wait_until (500); - g_assert (result); - trust = gcr_trust_is_certificate_pinned_finish (result, &error); - g_assert (trust == TRUE); - g_assert (error == NULL); - g_object_unref (result); - result = NULL; -} - -static void -test_add_and_remov_pinned_async (Test *test, gconstpointer unused) -{ - GAsyncResult *result = NULL; - GError *error = NULL; - gboolean trust; - gboolean ret; - - gcr_trust_add_pinned_certificate_async (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, fetch_async_result, &result); - egg_test_wait_until (500); - g_assert (result); - ret = gcr_trust_add_pinned_certificate_finish (result, &error); - g_assert (ret == TRUE); - g_assert (error == NULL); - g_object_unref (result); - result = NULL; - - gcr_trust_is_certificate_pinned_async (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, fetch_async_result, &result); - egg_test_wait_until (500); - g_assert (result); - trust = gcr_trust_is_certificate_pinned_finish (result, &error); - g_assert (trust == TRUE); - g_assert (error == NULL); - g_object_unref (result); - result = NULL; - - gcr_trust_remove_pinned_certificate_async (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, fetch_async_result, &result); - egg_test_wait_until (500); - g_assert (result); - ret = gcr_trust_remove_pinned_certificate_finish (result, &error); - g_assert (ret == TRUE); - g_assert (error == NULL); - g_object_unref (result); - result = NULL; - - gcr_trust_is_certificate_pinned_async (test->certificate, GCR_PURPOSE_EMAIL, "host", NULL, fetch_async_result, &result); - egg_test_wait_until (500); - g_assert (result); - trust = gcr_trust_is_certificate_pinned_finish (result, &error); - g_assert (trust == FALSE); - g_assert (error == NULL); - g_object_unref (result); - result = NULL; -} - -static void -test_is_certificate_anchored_not (Test *test, gconstpointer unused) -{ - GError *error = NULL; - gboolean ret; - - ret = gcr_trust_is_certificate_anchored (test->certificate, GCR_PURPOSE_CLIENT_AUTH, NULL, &error); - g_assert (ret == FALSE); - g_assert (error == NULL); -} - -static void -test_is_certificate_anchored_yes (Test *test, gconstpointer unused) -{ - GError *error = NULL; - GckAttributes *attrs; - gconstpointer der; - gsize n_der; - gboolean ret; - - /* Create a certificate root trust */ - attrs = gck_attributes_new (); - der = gcr_certificate_get_der_data (test->certificate, &n_der); - gck_attributes_add_data (attrs, CKA_X_CERTIFICATE_VALUE, der, n_der); - gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_X_TRUST_ASSERTION); - gck_attributes_add_boolean (attrs, CKA_TOKEN, TRUE); - gck_attributes_add_string (attrs, CKA_X_PURPOSE, GCR_PURPOSE_CLIENT_AUTH); - gck_attributes_add_ulong (attrs, CKA_X_ASSERTION_TYPE, CKT_X_ANCHORED_CERTIFICATE); - gck_mock_module_take_object (attrs); - - ret = gcr_trust_is_certificate_anchored (test->certificate, GCR_PURPOSE_CLIENT_AUTH, NULL, &error); - g_assert (ret == TRUE); - g_assert (error == NULL); -} - -static void -test_is_certificate_anchored_async (Test *test, gconstpointer unused) -{ - GAsyncResult *result = NULL; - GError *error = NULL; - gboolean ret; - - gcr_trust_is_certificate_anchored_async (test->certificate, GCR_PURPOSE_CLIENT_AUTH, NULL, fetch_async_result, &result); - egg_test_wait_until (500); - g_assert (result); - - ret = gcr_trust_is_certificate_anchored_finish (result, &error); - g_assert (ret == FALSE); - g_assert (error == NULL); - - g_object_unref (result); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - g_set_prgname ("test-trust"); - - g_test_add ("/gcr/trust/is_pinned_none", Test, NULL, setup, test_is_pinned_none, teardown); - g_test_add ("/gcr/trust/add_and_is_pinned", Test, NULL, setup, test_add_and_is_pinned, teardown); - g_test_add ("/gcr/trust/add_certificate_pinned_fail", Test, NULL, setup, test_add_certificate_pinned_fail, teardown); - g_test_add ("/gcr/trust/add_and_remov_pinned", Test, NULL, setup, test_add_and_remov_pinned, teardown); - g_test_add ("/gcr/trust/add_and_is_pinned_async", Test, NULL, setup, test_add_and_is_pinned_async, teardown); - g_test_add ("/gcr/trust/add_and_remov_pinned_async", Test, NULL, setup, test_add_and_remov_pinned_async, teardown); - g_test_add ("/gcr/trust/is_certificate_anchored_not", Test, NULL, setup, test_is_certificate_anchored_not, teardown); - g_test_add ("/gcr/trust/is_certificate_anchored_yes", Test, NULL, setup, test_is_certificate_anchored_yes, teardown); - g_test_add ("/gcr/trust/is_certificate_anchored_async", Test, NULL, setup, test_is_certificate_anchored_async, teardown); - - return egg_tests_run_in_thread_with_loop (); -} diff --git a/gcr/tests/test-util.c b/gcr/tests/test-util.c deleted file mode 100644 index 96819ac6..00000000 --- a/gcr/tests/test-util.c +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ -/* - Copyright (C) 2011 Collabora Ltd. - - The Gnome Keyring Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The Gnome Keyring Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the Gnome Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. - - Author: Stef Walter <stefw@collabora.co.uk> -*/ - -#include "config.h" - -#include "gcr/gcr-base.h" -#include "gcr/gcr-util.h" - -#include <errno.h> - -static void -on_line_parsed_match_template (const gchar *line, gpointer user_data) -{ - const gchar ***matching = user_data; - - g_assert (matching); - g_assert (*matching); - - /* Must be another line to match */ - g_assert ((*matching)[0]); - - /* Match this line against expected, and increment to next */ - g_assert_cmpstr ((*matching)[0], ==, line); - (*matching)++; -} - -static void -test_parse_lines (void) -{ - GString *string = g_string_new ("first line\nsecond line\n\nlast line"); - const gchar *matches[] = { "first line", "second line", "", NULL }; - const gchar **matching = matches; - - _gcr_util_parse_lines (string, FALSE, on_line_parsed_match_template, &matching); - - /* All lines should have matched */ - g_assert (*matching == NULL); - - /* The last line should still be here */ - g_assert_cmpstr (string->str, ==, "last line"); - g_string_free (string, TRUE); -} - -static void -test_parse_lines_and_last (void) -{ - GString *string = g_string_new ("first line\nsecond line\n\nlast line"); - const gchar *matches[] = { "first line", "second line", "", "last line", NULL }; - const gchar **matching = matches; - - _gcr_util_parse_lines (string, FALSE, on_line_parsed_match_template, &matching); - _gcr_util_parse_lines (string, TRUE, on_line_parsed_match_template, &matching); - - /* All lines should have matched */ - g_assert (*matching == NULL); - - /* No more data */ - g_assert_cmpstr (string->str, ==, ""); - g_assert_cmpuint (string->len, ==, 0); - g_string_free (string, TRUE); -} - -static void -test_parse_lines_dos (void) -{ - GString *string = g_string_new ("first line\r\nsecond line\r\n\r\nlast line"); - const gchar *matches[] = { "first line", "second line", "", "last line", NULL }; - const gchar **matching = matches; - - _gcr_util_parse_lines (string, FALSE, on_line_parsed_match_template, &matching); - _gcr_util_parse_lines (string, TRUE, on_line_parsed_match_template, &matching); - - /* All lines should have matched */ - g_assert (*matching == NULL); - - /* No more data */ - g_assert_cmpstr (string->str, ==, ""); - g_assert_cmpuint (string->len, ==, 0); - g_string_free (string, TRUE); -} - -int -main (int argc, char **argv) -{ - g_type_init (); - g_test_init (&argc, &argv, NULL); - - g_test_add_func ("/gcr/util/test_parse_lines", test_parse_lines); - g_test_add_func ("/gcr/util/test_parse_lines_and_last", test_parse_lines_and_last); - g_test_add_func ("/gcr/util/test_parse_lines_dos", test_parse_lines_dos); - - return g_test_run (); -} |