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