/*
* 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, see <http://www.gnu.org/licenses/>.
*
* Author: Stef Walter <stefw@collabora.co.uk>
*/
#include "config.h"
#include "gcr/gcr-icons.h"
#include "gcr/gcr-gnupg-records.h"
#include "gcr/gcr-openpgp.h"
#include "gcr/gcr-simple-certificate.h"
#include "gcr/gcr-types.h"
#include "gcr-display-view.h"
#include "gcr-gnupg-renderer.h"
#include "gcr-renderer.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 = NULL;
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);
GckBuilder builder = GCK_BUILDER_INIT;
_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 */
gck_builder_add_ulong (&builder, CKA_CLASS, CKO_GCR_GNUPG_RECORDS);
gcr_renderer_register (GCR_TYPE_GNUPG_RENDERER, gck_builder_end (&builder));
}
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 C_("capability", "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 C_("ownertrust", "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 && value[0] != '\0') {
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)
{
const 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");
}