4
* Copyright (C) 2006 Stefan Walter
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
* See the GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the
17
* Free Software Foundation, Inc.,
18
* 59 Temple Place, Suite 330,
19
* Boston, MA 02111-1307, USA.
24
#include "seahorse-util.h"
26
#include "pgp/seahorse-gpgmex.h"
27
#include "pgp/seahorse-pgp-operation.h"
28
#include "pgp/seahorse-pgp-source.h"
30
#define DEBUG_OPERATION_ENABLE 0
32
#ifndef DEBUG_OPERATION_ENABLE
34
#define DEBUG_OPERATION_ENABLE 1
36
#define DEBUG_OPERATION_ENABLE 0
40
#if DEBUG_OPERATION_ENABLE
41
#define DEBUG_OPERATION(x) g_printerr x
43
#define DEBUG_OPERATION(x)
46
/* -----------------------------------------------------------------------------
50
typedef struct _WatchData {
51
SeahorsePGPOperation *op; /* The operation we're working with */
52
gint stag; /* IO watch source tag */
53
gboolean registered; /* Whether this watch is currently registered */
55
/* GPGME watch info */
63
/* Macros "borrowed" from GDK */
64
#define READ_CONDITION (G_IO_IN | G_IO_HUP | G_IO_ERR)
65
#define WRITE_CONDITION (G_IO_OUT | G_IO_ERR)
67
typedef struct _SeahorsePGPOperationPrivate {
68
gpgme_ctx_t gctx; /* The context we watch for the async op to complete */
69
gchar *message; /* A progress message to display (or NULL for GPGME messages) */
70
struct gpgme_io_cbs io_cbs; /* The GPGME IO callback vtable */
71
GList *watches; /* Watches GPGME asked us to track */
72
gboolean busy; /* If the context is currently executing something */
73
guint def_total; /* Default total */
74
} SeahorsePGPOperationPrivate;
88
static guint signals[LAST_SIGNAL] = { 0 };
90
#define SEAHORSE_PGP_OPERATION_GET_PRIVATE(obj) \
91
(G_TYPE_INSTANCE_GET_PRIVATE ((obj), SEAHORSE_TYPE_PGP_OPERATION, SeahorsePGPOperationPrivate))
93
/* TODO: This is just nasty. Gotta get rid of these weird macros */
94
IMPLEMENT_OPERATION_PROPS(PGP, pgp)
96
g_object_class_install_property (gobject_class, PROP_GCTX,
97
g_param_spec_pointer ("gctx", "GPGME Context", "GPGME Context that this operation is watching.",
100
g_object_class_install_property (gobject_class, PROP_MESSAGE,
101
g_param_spec_string ("message", "Progress Message", "Progress message that overrides whatever GPGME gives us",
102
NULL, G_PARAM_READABLE | G_PARAM_WRITABLE));
104
g_object_class_install_property (gobject_class, PROP_DEF_TOTAL,
105
g_param_spec_uint ("default-total", "Default Total", "Default total to use instead of GPGME's progress total.",
106
0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_WRITABLE));
108
signals[RESULTS] = g_signal_new ("results", SEAHORSE_TYPE_PGP_OPERATION,
109
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (SeahorsePGPOperationClass, results),
110
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
112
g_type_class_add_private (gobject_class, sizeof (SeahorsePGPOperationPrivate));
114
END_IMPLEMENT_OPERATION_PROPS
117
/* -----------------------------------------------------------------------------
121
/* Called when there's data for GPG on a file descriptor */
123
io_callback (GIOChannel *source, GIOCondition condition, WatchData *watch)
125
DEBUG_OPERATION (("PGPOP: io for GPGME on %d\n", watch->fd));
126
(watch->fnc) (watch->fnc_data, g_io_channel_unix_get_fd (source));
130
/* Register a GPGME callback with GLib. */
132
register_watch (WatchData *watch)
136
if (watch->registered)
139
DEBUG_OPERATION (("PGPOP: registering watch %d\n", watch->fd));
141
channel = g_io_channel_unix_new (watch->fd);
142
watch->stag = g_io_add_watch_full (channel, G_PRIORITY_DEFAULT,
143
watch->dir ? READ_CONDITION : WRITE_CONDITION,
144
(GIOFunc)io_callback, watch, NULL);
145
watch->registered = TRUE;
146
g_io_channel_unref (channel);
149
/* Unregister GPGME callback with GLib. */
151
unregister_watch (WatchData *watch)
153
if (!watch->registered)
156
DEBUG_OPERATION (("PGPOP: unregistering watch %d\n", watch->fd));
158
g_source_remove (watch->stag);
160
watch->registered = FALSE;
163
/* -----------------------------------------------------------------------------
167
/* Called by GPGME when a change of progress state */
169
progress_cb (void *data, const char *what, int type,
170
int current, int total)
172
SeahorsePGPOperation *pop = SEAHORSE_PGP_OPERATION (data);
173
SeahorsePGPOperationPrivate *pv = SEAHORSE_PGP_OPERATION_GET_PRIVATE (pop);
175
DEBUG_OPERATION (("PGPOP: got progress: %s %d/%d\n", what, current, total));
178
total = pv->def_total;
180
if (seahorse_operation_is_running (SEAHORSE_OPERATION (pop)))
181
seahorse_operation_mark_progress_full (SEAHORSE_OPERATION (pop),
182
pv->message ? pv->message : what,
186
/* Register a callback. */
188
register_cb (void *data, int fd, int dir, gpgme_io_cb_t fnc, void *fnc_data,
191
SeahorsePGPOperation *pop = SEAHORSE_PGP_OPERATION (data);
192
SeahorsePGPOperationPrivate *pv = SEAHORSE_PGP_OPERATION_GET_PRIVATE (pop);
195
DEBUG_OPERATION (("PGPOP: request to register watch %d\n", fd));
197
watch = g_new0 (WatchData, 1);
198
watch->registered = FALSE;
202
watch->fnc_data = fnc_data;
206
* If the context is busy, we already have a START event, and can
207
* register watches freely.
210
register_watch (watch);
212
pv->watches = g_list_append (pv->watches, watch);
218
/* Remove a callback. */
220
remove_cb (void *tag)
222
SeahorsePGPOperationPrivate *pv;
223
WatchData *watch = (WatchData*)tag;
225
pv = SEAHORSE_PGP_OPERATION_GET_PRIVATE (watch->op);
227
DEBUG_OPERATION (("PGPOP: request to remove watch %d\n", watch->fd));
229
pv->watches = g_list_remove (pv->watches, watch);
230
unregister_watch (watch);
234
/* The event callback. */
236
event_cb (void *data, gpgme_event_io_t type, void *type_data)
238
SeahorsePGPOperation *pop = SEAHORSE_PGP_OPERATION (data);
239
SeahorsePGPOperationPrivate *pv = SEAHORSE_PGP_OPERATION_GET_PRIVATE (pop);
241
GError *error = NULL;
246
/* Called when the GPGME context starts an operation */
247
case GPGME_EVENT_START:
250
DEBUG_OPERATION (("PGPOP: start event\n"));
252
/* Since we weren't supposed to register these before, do it now */
253
for (list = pv->watches; list; list = g_list_next (list))
254
register_watch ((WatchData*)(list->data));
256
/* And tell everyone we've begun */
257
if (!seahorse_operation_is_running (SEAHORSE_OPERATION (pop)))
258
seahorse_operation_mark_start (SEAHORSE_OPERATION (pop));
260
/* Listens for progress updates from GPG */
261
gpgme_set_progress_cb (pop->gctx, progress_cb, pop);
265
/* Called when the GPGME context is finished with an op */
266
case GPGME_EVENT_DONE:
268
gerr = (gpgme_error_t*)type_data;
270
DEBUG_OPERATION (("PGPOP: done event (err: %d)\n", *gerr));
272
/* Make sure we have no extra watches left over */
273
for (list = pv->watches; list; list = g_list_next (list))
274
unregister_watch ((WatchData*)(list->data));
276
gpgme_set_progress_cb (pop->gctx, NULL, NULL);
278
/* And try to figure out a good response */
279
if (seahorse_operation_is_running (SEAHORSE_OPERATION (pop))) {
282
if (gpgme_err_code (*gerr) == GPG_ERR_CANCELED) {
283
seahorse_operation_mark_done (SEAHORSE_OPERATION (pop), TRUE, NULL);
287
/* Reference guard (marking an op as complete unrefs it) */
292
seahorse_gpgme_to_error (*gerr, &error);
294
/* No error, results available */
296
g_signal_emit (pop, signals[RESULTS], 0);
298
/* The above event may have started the action again so double check */
299
if (!pv->busy && seahorse_operation_is_running (SEAHORSE_OPERATION (pop)))
300
seahorse_operation_mark_done (SEAHORSE_OPERATION (pop), FALSE, error);
302
/* End reference guard */
303
g_object_unref (pop);
308
case GPGME_EVENT_NEXT_KEY:
309
case GPGME_EVENT_NEXT_TRUSTITEM:
311
/* Ignore unsupported event types */
316
/* -----------------------------------------------------------------------------
321
seahorse_pgp_operation_init (SeahorsePGPOperation *pop)
323
SeahorsePGPOperationPrivate *pv = SEAHORSE_PGP_OPERATION_GET_PRIVATE (pop);
325
pop->gctx = seahorse_pgp_source_new_context ();
326
g_return_if_fail (pop->gctx != NULL);
330
/* Setup with the context */
331
pv->io_cbs.add = register_cb;
332
pv->io_cbs.add_priv = pop;
333
pv->io_cbs.remove = remove_cb;
334
pv->io_cbs.event = event_cb;
335
pv->io_cbs.event_priv = pop;
337
gpgme_set_io_cbs (pop->gctx, &(pv->io_cbs));
341
seahorse_pgp_operation_set_property (GObject *gobject, guint prop_id,
342
const GValue *value, GParamSpec *pspec)
344
SeahorsePGPOperation *pop = SEAHORSE_PGP_OPERATION (gobject);
345
SeahorsePGPOperationPrivate *pv = SEAHORSE_PGP_OPERATION_GET_PRIVATE (pop);
349
g_free (pv->message);
350
pv->message = g_strdup (g_value_get_string (value));
353
pv->def_total = g_value_get_uint (value);
359
seahorse_pgp_operation_get_property (GObject *gobject, guint prop_id,
360
GValue *value, GParamSpec *pspec)
362
SeahorsePGPOperation *pop = SEAHORSE_PGP_OPERATION (gobject);
363
SeahorsePGPOperationPrivate *pv = SEAHORSE_PGP_OPERATION_GET_PRIVATE (pop);
367
g_value_set_pointer (value, pop->gctx);
370
g_value_set_string (value, pv->message);
373
g_value_set_uint (value, pv->def_total);
378
seahorse_pgp_operation_dispose (GObject *gobject)
381
G_OBJECT_CLASS (pgp_operation_parent_class)->dispose (gobject);
385
seahorse_pgp_operation_finalize (GObject *gobject)
387
SeahorsePGPOperation *pop = SEAHORSE_PGP_OPERATION (gobject);
388
SeahorsePGPOperationPrivate *pv = SEAHORSE_PGP_OPERATION_GET_PRIVATE (pop);
392
g_critical ("NASTY BUG. Disposing of a SeahorsePGPOperation while GPGME is "
393
"still performing an operation. SeahorseOperation should ref"
394
"itself while active");
397
/* Make sure we have no extra watches left over */
398
for (list = pv->watches; list; list = g_list_next (list)) {
399
unregister_watch ((WatchData*)(list->data));
403
g_list_free (pv->watches);
407
gpgme_release (pop->gctx);
410
g_free (pv->message);
413
G_OBJECT_CLASS (pgp_operation_parent_class)->finalize (gobject);
417
seahorse_pgp_operation_cancel (SeahorseOperation *operation)
419
SeahorsePGPOperation *pop = SEAHORSE_PGP_OPERATION (operation);
420
SeahorsePGPOperationPrivate *pv = SEAHORSE_PGP_OPERATION_GET_PRIVATE (pop);
422
g_return_if_fail (seahorse_operation_is_running (operation));
423
g_return_if_fail (pop->gctx != NULL);
425
/* This should call in through event_cb and cancel us */
427
gpgme_cancel (pop->gctx);
430
/* -----------------------------------------------------------------------------
434
SeahorsePGPOperation*
435
seahorse_pgp_operation_new (const gchar *message)
437
return g_object_new (SEAHORSE_TYPE_PGP_OPERATION, "message", message, NULL);
441
seahorse_pgp_operation_mark_failed (SeahorsePGPOperation *pop, gpgme_error_t gerr)
443
SeahorseOperation *op = SEAHORSE_OPERATION (pop);
446
if (!seahorse_operation_is_running (op))
447
seahorse_operation_mark_start (op);
449
seahorse_gpgme_to_error (gerr, &err);
450
seahorse_operation_mark_done (op, FALSE, err);