1 /*
2  * gnome-keyring
3  *
4  * Copyright (C) 2010 Stefan Walter
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "config.h"
21 
22 #include "gcr-deprecated.h"
23 #include "gcr-renderer.h"
24 
25 #include "gcr-certificate-renderer.h"
26 #include "gcr-certificate-request-renderer.h"
27 #include "gcr-gnupg-renderer.h"
28 #include "gcr-key-renderer.h"
29 
30 #include "gck/gck.h"
31 
32 #include <gtk/gtk.h>
33 
34 /**
35  * SECTION:gcr-renderer
36  * @title: GcrRenderer
37  * @short_description: An interface implemented by renderers.
38  *
39  * A #GcrRenderer is an interface that's implemented by renderers which wish
40  * to render data to a #GcrViewer.
41  *
42  * The interaction between #GcrRenderer and #GcrViewer is not stable yet, and
43  * so new renderers cannot be implemented outside the Gcr library at this time.
44  *
45  * To lookup a renderer for a given set of attributes, use the gcr_renderer_create()
46  * function. This will create and initialize a renderer that's capable of viewing
47  * the data in those attributes.
48  */
49 
50 /**
51  * GcrRenderer:
52  *
53  * A renderer.
54  */
55 
56 /**
57  * GcrRendererIface:
58  * @parent: the parent interface type
59  * @data_changed: signal emitted when data being rendered changes
60  * @render_view: method invoked to render the data into a viewer
61  * @populate_popup: method invoked to populate a popup menu with additional
62  *                  renderer options
63  *
64  * The interface for #GcrRenderer
65  */
66 
67 enum {
68 	DATA_CHANGED,
69 	LAST_SIGNAL
70 };
71 
72 static guint signals[LAST_SIGNAL] = { 0 };
73 
74 typedef struct _GcrRegistered {
75 	GckAttributes *attrs;
76 	GType renderer_type;
77 } GcrRegistered;
78 
79 static GArray *registered_renderers = NULL;
80 static gboolean registered_sorted = FALSE;
81 
82 static void
gcr_renderer_default_init(GcrRendererIface * iface)83 gcr_renderer_default_init (GcrRendererIface *iface)
84 {
85 	static gboolean initialized = FALSE;
86 	if (!initialized) {
87 
88 		/**
89 		 * GcrRenderer:label:
90 		 *
91 		 * The label to display.
92 		 */
93 		g_object_interface_install_property (iface,
94 		         g_param_spec_string ("label", "Label", "The label for the renderer",
95 		                              "",
96 		                              G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
97 
98 		/**
99 		 * GcrRenderer:attributes:
100 		 *
101 		 * The attributes to display.
102 		 */
103 		g_object_interface_install_property (iface,
104 		         g_param_spec_boxed ("attributes", "Attributes", "The data displayed in the renderer",
105 		                             GCK_TYPE_ATTRIBUTES,
106 		                             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
107 
108 		/**
109 		 * GcrRenderer::data-changed:
110 		 *
111 		 * A signal that is emitted by the renderer when it's data
112 		 * changed and should be rerendered.
113 		 */
114 		signals[DATA_CHANGED] = g_signal_new ("data-changed", GCR_TYPE_RENDERER, G_SIGNAL_RUN_LAST,
115 		                                      G_STRUCT_OFFSET (GcrRendererIface, data_changed),
116 		                                      NULL, NULL, NULL, G_TYPE_NONE, 0);
117 
118 		initialized = TRUE;
119 	}
120 }
121 
122 typedef GcrRendererIface GcrRendererInterface;
123 
124 G_DEFINE_INTERFACE (GcrRenderer, gcr_renderer, G_TYPE_OBJECT);
125 
126 /**
127  * gcr_renderer_render_view:
128  * @self: The renderer
129  * @viewer: The viewer to render to.
130  *
131  * Render the contents of the renderer to the given viewer.
132  */
133 void
gcr_renderer_render_view(GcrRenderer * self,GcrViewer * viewer)134 gcr_renderer_render_view (GcrRenderer *self, GcrViewer *viewer)
135 {
136 	g_return_if_fail (GCR_IS_RENDERER (self));
137 	g_return_if_fail (GCR_RENDERER_GET_INTERFACE (self)->render_view);
138 	GCR_RENDERER_GET_INTERFACE (self)->render_view (self, viewer);
139 }
140 
141 /**
142  * gcr_renderer_render:
143  * @self: the renderer
144  * @viewer: the viewer to render to
145  *
146  * Render a renderer to the viewer.
147  *
148  * Deprecated: 3.2: Use gcr_renderer_render_view() instead
149  */
150 void
gcr_renderer_render(GcrRenderer * self,GcrViewer * viewer)151 gcr_renderer_render (GcrRenderer *self,
152                      GcrViewer *viewer)
153 {
154 	gcr_renderer_render_view (self, viewer);
155 }
156 
157 /**
158  * gcr_renderer_popuplate_popup:
159  * @self: The renderer
160  * @viewer: The viewer that is displaying a popup
161  * @menu: The popup menu being displayed
162  *
163  * Called by #GcrViewer when about to display a popup menu for the content
164  * displayed by the renderer. The renderer can add a menu item if desired.
165  */
166 void
gcr_renderer_popuplate_popup(GcrRenderer * self,GcrViewer * viewer,GtkMenu * menu)167 gcr_renderer_popuplate_popup (GcrRenderer *self, GcrViewer *viewer,
168                               GtkMenu *menu)
169 {
170 	g_return_if_fail (GCR_IS_RENDERER (self));
171 	if (GCR_RENDERER_GET_INTERFACE (self)->populate_popup)
172 		GCR_RENDERER_GET_INTERFACE (self)->populate_popup (self, viewer, menu);
173 }
174 
175 /**
176  * gcr_renderer_emit_data_changed:
177  * @self: The renderer
178  *
179  * Emit the #GcrRenderer::data-changed signal on the renderer. This is used by
180  * renderer implementations.
181  */
182 void
gcr_renderer_emit_data_changed(GcrRenderer * self)183 gcr_renderer_emit_data_changed (GcrRenderer *self)
184 {
185 	g_return_if_fail (GCR_IS_RENDERER (self));
186 	g_signal_emit (self, signals[DATA_CHANGED], 0);
187 }
188 
189 /**
190  * gcr_renderer_get_attributes:
191  * @self: The renderer
192  *
193  * Get the PKCS\#11 attributes, if any, set for this renderer to display.
194  *
195  * Returns: (nullable) (transfer none): the attributes, owned by the renderer
196  */
197 GckAttributes *
gcr_renderer_get_attributes(GcrRenderer * self)198 gcr_renderer_get_attributes (GcrRenderer *self)
199 {
200 	GckAttributes *attrs;
201 
202 	g_return_val_if_fail (GCR_IS_RENDERER (self), NULL);
203 
204 	g_object_get (self, "attributes", &attrs, NULL);
205 	if (attrs != NULL)
206 		gck_attributes_unref (attrs);
207 	return attrs;
208 }
209 
210 /**
211  * gcr_renderer_set_attributes:
212  * @self: The renderer
213  * @attrs: (nullable): attributes to set
214  *
215  * Set the PKCS\#11 attributes for this renderer to display.
216  */
217 void
gcr_renderer_set_attributes(GcrRenderer * self,GckAttributes * attrs)218 gcr_renderer_set_attributes (GcrRenderer *self,
219                              GckAttributes *attrs)
220 {
221 	g_return_if_fail (GCR_IS_RENDERER (self));
222 
223 	g_object_set (self, "attributes", attrs, NULL);
224 }
225 
226 static gint
sort_registered_by_n_attrs(gconstpointer a,gconstpointer b)227 sort_registered_by_n_attrs (gconstpointer a, gconstpointer b)
228 {
229 	const GcrRegistered *ra = a;
230 	const GcrRegistered *rb = b;
231 	gulong na, nb;
232 
233 	g_assert (a);
234 	g_assert (b);
235 
236 	na = gck_attributes_count (ra->attrs);
237 	nb = gck_attributes_count (rb->attrs);
238 
239 	/* Note we're sorting in reverse order */
240 	if (na < nb)
241 		return 1;
242 	return (na == nb) ? 0 : -1;
243 }
244 
245 /**
246  * gcr_renderer_create:
247  * @label: (nullable): The label for the renderer
248  * @attrs: The attributes to render
249  *
250  * Create and initialize a renderer for the given attributes and label. These
251  * renderers should have been preregistered via gcr_renderer_register().
252  *
253  * Returns: (transfer full) (nullable): a new renderer, or %NULL if no renderer
254  *          matched the attributes; the render should be released with g_object_unref()
255  */
256 GcrRenderer *
gcr_renderer_create(const gchar * label,GckAttributes * attrs)257 gcr_renderer_create (const gchar *label, GckAttributes *attrs)
258 {
259 	GcrRegistered *registered;
260 	gboolean matched;
261 	gulong n_attrs;
262 	gulong j;
263 	gsize i;
264 
265 	g_return_val_if_fail (attrs, NULL);
266 
267 	gcr_renderer_register_well_known ();
268 
269 	if (!registered_renderers)
270 		return NULL;
271 
272 	if (!registered_sorted) {
273 		g_array_sort (registered_renderers, sort_registered_by_n_attrs);
274 		registered_sorted = TRUE;
275 	}
276 
277 	for (i = 0; i < registered_renderers->len; ++i) {
278 		registered = &(g_array_index (registered_renderers, GcrRegistered, i));
279 		n_attrs = gck_attributes_count (registered->attrs);
280 
281 		matched = TRUE;
282 
283 		for (j = 0; j < n_attrs; ++j) {
284 			if (!gck_attributes_contains (attrs, gck_attributes_at (registered->attrs, j))) {
285 				matched = FALSE;
286 				break;
287 			}
288 		}
289 
290 		if (matched)
291 			return g_object_new (registered->renderer_type, "label", label,
292 			                     "attributes", attrs, NULL);
293 	}
294 
295 	return NULL;
296 }
297 
298 /**
299  * gcr_renderer_register:
300  * @renderer_type: The renderer class type
301  * @attrs: The attributes to match
302  *
303  * Register a renderer to be created when matching attributes are passed to
304  * gcr_renderer_create().
305  */
306 void
gcr_renderer_register(GType renderer_type,GckAttributes * attrs)307 gcr_renderer_register (GType renderer_type, GckAttributes *attrs)
308 {
309 	GcrRegistered registered;
310 
311 	if (!registered_renderers)
312 		registered_renderers = g_array_new (FALSE, FALSE, sizeof (GcrRegistered));
313 
314 	registered.renderer_type = renderer_type;
315 	registered.attrs = gck_attributes_ref_sink (attrs);
316 	g_array_append_val (registered_renderers, registered);
317 	registered_sorted = FALSE;
318 }
319 
320 /**
321  * gcr_renderer_register_well_known:
322  *
323  * Register all the well known renderers for certificates and keys known to the
324  * Gcr library.
325  */
326 void
gcr_renderer_register_well_known(void)327 gcr_renderer_register_well_known (void)
328 {
329 	g_type_class_unref (g_type_class_ref (GCR_TYPE_CERTIFICATE_RENDERER));
330 	g_type_class_unref (g_type_class_ref (GCR_TYPE_CERTIFICATE_REQUEST_RENDERER));
331 	g_type_class_unref (g_type_class_ref (GCR_TYPE_KEY_RENDERER));
332 	g_type_class_unref (g_type_class_ref (GCR_TYPE_GNUPG_RENDERER));
333 }
334