~ubuntu-branches/ubuntu/trusty/gcr/trusty-proposed

« back to all changes in this revision

Viewing changes to gcr/gcr-gnupg-process.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach
  • Date: 2012-05-03 10:18:39 UTC
  • Revision ID: package-import@ubuntu.com-20120503101839-wuvloldm7gmdsnij
Tags: upstream-3.4.1
ImportĀ upstreamĀ versionĀ 3.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * gnome-keyring
 
3
 *
 
4
 * Copyright (C) 2011 Collabora Ltd.
 
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, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
19
 * 02111-1307, USA.
 
20
 *
 
21
 * Author: Stef Walter <stefw@collabora.co.uk>
 
22
 */
 
23
 
 
24
#include "config.h"
 
25
 
 
26
#define DEBUG_FLAG GCR_DEBUG_GNUPG
 
27
#include "gcr-debug.h"
 
28
#include "gcr-gnupg-process.h"
 
29
#include "gcr-marshal.h"
 
30
#include "gcr-util.h"
 
31
 
 
32
#include <glib/gi18n-lib.h>
 
33
 
 
34
#include <sys/wait.h>
 
35
#include <fcntl.h>
 
36
#include <errno.h>
 
37
#include <string.h>
 
38
 
 
39
/**
 
40
 * GcrGnupgProcessFlags:
 
41
 * @GCR_GNUPG_PROCESS_NONE: No flags
 
42
 * @GCR_GNUPG_PROCESS_RESPECT_LOCALE: Respect the user's locale when running gnupg.
 
43
 * @GCR_GNUPG_PROCESS_WITH_STATUS: Ask the process to send status records.
 
44
 * @GCR_GNUPG_PROCESS_WITH_ATTRIBUTES: Ask the process to output attribute data.
 
45
 *
 
46
 * Flags for running a gnupg process.
 
47
 */
 
48
 
 
49
enum {
 
50
        PROP_0,
 
51
        PROP_DIRECTORY,
 
52
        PROP_EXECUTABLE,
 
53
        PROP_INPUT_STREAM,
 
54
        PROP_OUTPUT_STREAM,
 
55
        PROP_ATTRIBUTE_STREAM
 
56
};
 
57
 
 
58
enum {
 
59
        FD_INPUT,
 
60
        FD_OUTPUT,
 
61
        FD_ERROR,
 
62
        FD_STATUS,
 
63
        FD_ATTRIBUTE,
 
64
        NUM_FDS
 
65
};
 
66
 
 
67
enum {
 
68
        ERROR_LINE,
 
69
        STATUS_RECORD,
 
70
        NUM_SIGNALS
 
71
};
 
72
 
 
73
static gint signals[NUM_SIGNALS] = { 0, };
 
74
 
 
75
typedef struct _GnupgSource {
 
76
        GSource source;
 
77
        GPollFD polls[NUM_FDS];         /* The various fd's we're listening to */
 
78
 
 
79
        GcrGnupgProcess *process;       /* Pointer back to the process object */
 
80
 
 
81
        GByteArray *input_buf;
 
82
        GString *error_buf;
 
83
        GString *status_buf;
 
84
 
 
85
        GPid child_pid;
 
86
        guint child_sig;
 
87
 
 
88
        GCancellable *cancellable;
 
89
        guint cancel_sig;
 
90
} GnupgSource;
 
91
 
 
92
struct _GcrGnupgProcessPrivate {
 
93
        gchar *directory;
 
94
        gchar *executable;
 
95
 
 
96
        GInputStream *input;
 
97
        GOutputStream *output;
 
98
        GOutputStream *attributes;
 
99
 
 
100
        gboolean running;
 
101
        gboolean complete;
 
102
        GError *error;
 
103
        guint source_sig;
 
104
 
 
105
        GAsyncReadyCallback async_callback;
 
106
        gpointer user_data;
 
107
};
 
108
 
 
109
/* Forward declarations */
 
110
static void _gcr_gnupg_process_init_async (GAsyncResultIface *iface);
 
111
 
 
112
G_DEFINE_TYPE_WITH_CODE (GcrGnupgProcess, _gcr_gnupg_process, G_TYPE_OBJECT,
 
113
                         G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, _gcr_gnupg_process_init_async));
 
114
 
 
115
static void
 
116
_gcr_gnupg_process_init (GcrGnupgProcess *self)
 
117
{
 
118
        self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_GNUPG_PROCESS,
 
119
                                                GcrGnupgProcessPrivate);
 
120
}
 
121
 
 
122
static void
 
123
_gcr_gnupg_process_constructed (GObject *obj)
 
124
{
 
125
        GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
 
126
 
 
127
        if (G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->constructed)
 
128
                G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->constructed (obj);
 
129
 
 
130
        if (!self->pv->executable)
 
131
                self->pv->executable = g_strdup (GPG_EXECUTABLE);
 
132
}
 
133
 
 
134
static void
 
135
_gcr_gnupg_process_get_property (GObject *obj, guint prop_id, GValue *value,
 
136
                                 GParamSpec *pspec)
 
137
{
 
138
        GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
 
139
 
 
140
        switch (prop_id) {
 
141
        case PROP_DIRECTORY:
 
142
                g_value_set_string (value, self->pv->directory);
 
143
                break;
 
144
        case PROP_EXECUTABLE:
 
145
                g_value_set_string (value, self->pv->executable);
 
146
                break;
 
147
        case PROP_INPUT_STREAM:
 
148
                g_value_set_object (value, _gcr_gnupg_process_get_input_stream (self));
 
149
                break;
 
150
        case PROP_OUTPUT_STREAM:
 
151
                g_value_set_object (value, _gcr_gnupg_process_get_output_stream (self));
 
152
                break;
 
153
        case PROP_ATTRIBUTE_STREAM:
 
154
                g_value_set_object (value, _gcr_gnupg_process_get_attribute_stream (self));
 
155
                break;
 
156
        default:
 
157
                G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 
158
                break;
 
159
        }
 
160
}
 
161
 
 
162
static void
 
163
_gcr_gnupg_process_set_property (GObject *obj, guint prop_id, const GValue *value,
 
164
                                 GParamSpec *pspec)
 
165
{
 
166
        GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
 
167
 
 
168
        switch (prop_id) {
 
169
        case PROP_DIRECTORY:
 
170
                g_return_if_fail (!self->pv->directory);
 
171
                self->pv->directory = g_value_dup_string (value);
 
172
                break;
 
173
        case PROP_EXECUTABLE:
 
174
                g_return_if_fail (!self->pv->executable);
 
175
                self->pv->executable = g_value_dup_string (value);
 
176
                break;
 
177
        case PROP_INPUT_STREAM:
 
178
                _gcr_gnupg_process_set_input_stream (self, g_value_get_object (value));
 
179
                break;
 
180
        case PROP_OUTPUT_STREAM:
 
181
                _gcr_gnupg_process_set_output_stream (self, g_value_get_object (value));
 
182
                break;
 
183
        case PROP_ATTRIBUTE_STREAM:
 
184
                _gcr_gnupg_process_set_attribute_stream (self, g_value_get_object (value));
 
185
                break;
 
186
        default:
 
187
                G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 
188
                break;
 
189
        }
 
190
}
 
191
 
 
192
static void
 
193
_gcr_gnupg_process_dispose (GObject *obj)
 
194
{
 
195
        GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
 
196
 
 
197
        g_clear_object (&self->pv->input);
 
198
        g_clear_object (&self->pv->output);
 
199
        g_clear_object (&self->pv->attributes);
 
200
 
 
201
        G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->dispose (obj);
 
202
}
 
203
 
 
204
static void
 
205
_gcr_gnupg_process_finalize (GObject *obj)
 
206
{
 
207
        GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
 
208
 
 
209
        g_assert (self->pv->source_sig == 0);
 
210
        g_assert (!self->pv->running);
 
211
        g_free (self->pv->directory);
 
212
        g_free (self->pv->executable);
 
213
        g_clear_error (&self->pv->error);
 
214
 
 
215
        G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->finalize (obj);
 
216
}
 
217
 
 
218
static void
 
219
_gcr_gnupg_process_class_init (GcrGnupgProcessClass *klass)
 
220
{
 
221
        GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
222
 
 
223
        gobject_class->constructed = _gcr_gnupg_process_constructed;
 
224
        gobject_class->get_property = _gcr_gnupg_process_get_property;
 
225
        gobject_class->set_property = _gcr_gnupg_process_set_property;
 
226
        gobject_class->dispose = _gcr_gnupg_process_dispose;
 
227
        gobject_class->finalize = _gcr_gnupg_process_finalize;
 
228
 
 
229
        /**
 
230
         * GcrGnupgProcess:directory:
 
231
         *
 
232
         * Directory to run as gnupg home directory, or %NULL for default
 
233
         * ~/.gnupg/ directory.
 
234
         */
 
235
        g_object_class_install_property (gobject_class, PROP_DIRECTORY,
 
236
                   g_param_spec_string ("directory", "Directory", "Gnupg Directory",
 
237
                                        NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
238
 
 
239
        /**
 
240
         * GcrGnupgProcess:executable:
 
241
         *
 
242
         * Path to the gnupg executable, or %NULL for default.
 
243
         */
 
244
        g_object_class_install_property (gobject_class, PROP_EXECUTABLE,
 
245
                   g_param_spec_string ("executable", "Executable", "Gnupg Executable",
 
246
                                        GPG_EXECUTABLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
247
 
 
248
        /**
 
249
         * GcrGnupgProcess:input-stream:
 
250
         *
 
251
         * Input for gnupg, or %NULL for no input.
 
252
         */
 
253
        g_object_class_install_property (gobject_class, PROP_INPUT_STREAM,
 
254
                   g_param_spec_object ("input-stream", "Input Stream", "Input Stream",
 
255
                                        G_TYPE_INPUT_STREAM, G_PARAM_READWRITE));
 
256
 
 
257
        /**
 
258
         * GcrGnupgProcess:output-stream:
 
259
         *
 
260
         * Output from gnupg, or %NULL for ignored output.
 
261
         */
 
262
        g_object_class_install_property (gobject_class, PROP_OUTPUT_STREAM,
 
263
                   g_param_spec_object ("output-stream", "Output Stream", "Output Stream",
 
264
                                        G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE));
 
265
 
 
266
        /**
 
267
         * GcrGnupgProcess:attribute-stream:
 
268
         *
 
269
         * Output of attribute data from gnupg, or %NULL for ignored attributes.
 
270
         */
 
271
        g_object_class_install_property (gobject_class, PROP_ATTRIBUTE_STREAM,
 
272
                   g_param_spec_object ("attribute-stream", "Attribute Stream", "Attribute Stream",
 
273
                                        G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE));
 
274
 
 
275
        /**
 
276
         * GcrGnupgProcess::error-line:
 
277
         * @line: a line of error output.
 
278
         *
 
279
         * Signal emitted when a line of error output is available from the
 
280
         * gnupg process.
 
281
         */
 
282
        signals[ERROR_LINE] = g_signal_new ("error-line", GCR_TYPE_GNUPG_PROCESS,
 
283
                   G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, error_line),
 
284
                   NULL, NULL, _gcr_marshal_VOID__STRING,
 
285
                   G_TYPE_NONE, 1, G_TYPE_STRING);
 
286
 
 
287
        /**
 
288
         * GcrGnupgProcess::status-record:
 
289
         * @record: a status record.
 
290
         *
 
291
         * Signal emitted when a status record is available from the gnupg process.
 
292
         */
 
293
        signals[STATUS_RECORD] = g_signal_new ("status-record", GCR_TYPE_GNUPG_PROCESS,
 
294
                   G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, status_record),
 
295
                   NULL, NULL, _gcr_marshal_VOID__BOXED,
 
296
                   G_TYPE_NONE, 1, GCR_TYPE_RECORD);
 
297
 
 
298
        g_type_class_add_private (gobject_class, sizeof (GcrGnupgProcessPrivate));
 
299
}
 
300
 
 
301
static gpointer
 
302
_gcr_gnupg_process_get_user_data (GAsyncResult *result)
 
303
{
 
304
        g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (result), NULL);
 
305
        return GCR_GNUPG_PROCESS (result)->pv->user_data;
 
306
}
 
307
 
 
308
static GObject*
 
309
_gcr_gnupg_process_get_source_object (GAsyncResult *result)
 
310
{
 
311
        g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (result), NULL);
 
312
        return g_object_ref (result);
 
313
}
 
314
 
 
315
static void
 
316
_gcr_gnupg_process_init_async (GAsyncResultIface *iface)
 
317
{
 
318
        iface->get_source_object = _gcr_gnupg_process_get_source_object;
 
319
        iface->get_user_data = _gcr_gnupg_process_get_user_data;
 
320
}
 
321
 
 
322
/**
 
323
 * _gcr_gnupg_process_new:
 
324
 * @directory: (allow-none): The gnupg home directory
 
325
 * @executable: (allow-none): The gpg executable
 
326
 *
 
327
 * Create a new GcrGnupgProcess.
 
328
 *
 
329
 * The gnupg home directory is where the keyring files live. If directory is
 
330
 * %NULL then the default gnupg home directory is used.
 
331
 *
 
332
 * The executable will default to the compiled in path if a %NULL executable
 
333
 * argument is used.
 
334
 *
 
335
 * Returns: (transfer full): A newly allocated process.
 
336
 */
 
337
GcrGnupgProcess*
 
338
_gcr_gnupg_process_new (const gchar *directory, const gchar *executable)
 
339
{
 
340
        return g_object_new (GCR_TYPE_GNUPG_PROCESS,
 
341
                             "directory", directory,
 
342
                             "executable", executable,
 
343
                             NULL);
 
344
}
 
345
 
 
346
const gchar *
 
347
_gcr_gnupg_process_get_directory (GcrGnupgProcess *self)
 
348
{
 
349
        g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL);
 
350
        return self->pv->directory;
 
351
}
 
352
 
 
353
GInputStream *
 
354
_gcr_gnupg_process_get_input_stream (GcrGnupgProcess *self)
 
355
{
 
356
        g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL);
 
357
        return self->pv->input;
 
358
}
 
359
 
 
360
void
 
361
_gcr_gnupg_process_set_input_stream (GcrGnupgProcess *self,
 
362
                                     GInputStream *input)
 
363
{
 
364
        g_return_if_fail (GCR_GNUPG_PROCESS (self));
 
365
        g_return_if_fail (input == NULL || G_INPUT_STREAM (input));
 
366
 
 
367
        if (input)
 
368
                g_object_ref (input);
 
369
        if (self->pv->input)
 
370
                g_object_unref (self->pv->input);
 
371
        self->pv->input = input;
 
372
        g_object_notify (G_OBJECT (self), "input-stream");
 
373
}
 
374
 
 
375
GOutputStream *
 
376
_gcr_gnupg_process_get_output_stream (GcrGnupgProcess *self)
 
377
{
 
378
        g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL);
 
379
        return self->pv->output;
 
380
}
 
381
 
 
382
void
 
383
_gcr_gnupg_process_set_output_stream (GcrGnupgProcess *self,
 
384
                                      GOutputStream *output)
 
385
{
 
386
        g_return_if_fail (GCR_GNUPG_PROCESS (self));
 
387
        g_return_if_fail (output == NULL || G_OUTPUT_STREAM (output));
 
388
 
 
389
        if (output)
 
390
                g_object_ref (output);
 
391
        if (self->pv->output)
 
392
                g_object_unref (self->pv->output);
 
393
        self->pv->output = output;
 
394
        g_object_notify (G_OBJECT (self), "output-stream");
 
395
}
 
396
 
 
397
GOutputStream *
 
398
_gcr_gnupg_process_get_attribute_stream (GcrGnupgProcess *self)
 
399
{
 
400
        g_return_val_if_fail (GCR_GNUPG_PROCESS (self), NULL);
 
401
        return self->pv->attributes;
 
402
}
 
403
 
 
404
void
 
405
_gcr_gnupg_process_set_attribute_stream (GcrGnupgProcess *self,
 
406
                                         GOutputStream *output)
 
407
{
 
408
        g_return_if_fail (GCR_GNUPG_PROCESS (self));
 
409
        g_return_if_fail (output == NULL || G_OUTPUT_STREAM (output));
 
410
 
 
411
        if (output)
 
412
                g_object_ref (output);
 
413
        if (self->pv->attributes)
 
414
                g_object_unref (self->pv->attributes);
 
415
        self->pv->attributes = output;
 
416
        g_object_notify (G_OBJECT (self), "attribute-stream");
 
417
}
 
418
 
 
419
static void
 
420
run_async_ready_callback (GcrGnupgProcess *self)
 
421
{
 
422
        GAsyncReadyCallback callback;
 
423
        gpointer user_data;
 
424
 
 
425
        _gcr_debug ("running async callback");
 
426
 
 
427
        /* Remove these before completing */
 
428
        callback = self->pv->async_callback;
 
429
        user_data = self->pv->user_data;
 
430
        self->pv->async_callback = NULL;
 
431
        self->pv->user_data = NULL;
 
432
 
 
433
        if (callback != NULL)
 
434
                (callback) (G_OBJECT (self), G_ASYNC_RESULT (self), user_data);
 
435
}
 
436
 
 
437
static gboolean
 
438
on_run_async_ready_callback_later (gpointer user_data)
 
439
{
 
440
        run_async_ready_callback (GCR_GNUPG_PROCESS (user_data));
 
441
        return FALSE; /* Don't run this callback again */
 
442
}
 
443
 
 
444
static void
 
445
run_async_ready_callback_later (GcrGnupgProcess *self)
 
446
{
 
447
        _gcr_debug ("running async callback later");
 
448
        g_idle_add_full (G_PRIORITY_DEFAULT, on_run_async_ready_callback_later,
 
449
                         g_object_ref (self), g_object_unref);
 
450
}
 
451
 
 
452
static void
 
453
complete_run_process (GcrGnupgProcess *self)
 
454
{
 
455
        g_return_if_fail (self->pv->running);
 
456
        g_return_if_fail (!self->pv->complete);
 
457
 
 
458
        self->pv->running = FALSE;
 
459
        self->pv->complete = TRUE;
 
460
 
 
461
        if (self->pv->error == NULL) {
 
462
                _gcr_debug ("completed process");
 
463
        } else {
 
464
                _gcr_debug ("completed process with error: %s",
 
465
                            self->pv->error->message);
 
466
        }
 
467
}
 
468
 
 
469
static void
 
470
complete_source_is_done (GnupgSource *gnupg_source)
 
471
{
 
472
        GcrGnupgProcess *self = gnupg_source->process;
 
473
 
 
474
        _gcr_debug ("all fds closed and process exited, completing");
 
475
 
 
476
        g_assert (gnupg_source->child_sig == 0);
 
477
 
 
478
        if (gnupg_source->cancel_sig) {
 
479
                g_signal_handler_disconnect (gnupg_source->cancellable, gnupg_source->cancel_sig);
 
480
                gnupg_source->cancel_sig = 0;
 
481
        }
 
482
 
 
483
        g_clear_object (&gnupg_source->cancellable);
 
484
 
 
485
        complete_run_process (self);
 
486
        run_async_ready_callback (self);
 
487
 
 
488
        /* All done, the source can go away now */
 
489
        g_source_unref ((GSource*)gnupg_source);
 
490
}
 
491
 
 
492
static void
 
493
close_fd (int *fd)
 
494
{
 
495
        g_assert (fd);
 
496
        if (*fd >= 0) {
 
497
                _gcr_debug ("closing fd: %d", *fd);
 
498
                close (*fd);
 
499
        }
 
500
        *fd = -1;
 
501
}
 
502
 
 
503
static void
 
504
close_poll (GSource *source, GPollFD *poll)
 
505
{
 
506
        g_source_remove_poll (source, poll);
 
507
        close_fd (&poll->fd);
 
508
        poll->revents = 0;
 
509
}
 
510
 
 
511
static gboolean
 
512
unused_callback (gpointer data)
 
513
{
 
514
        /* Never called */
 
515
        g_assert_not_reached ();
 
516
        return FALSE;
 
517
}
 
518
 
 
519
static gboolean
 
520
on_gnupg_source_prepare (GSource *source, gint *timeout_)
 
521
{
 
522
        GnupgSource *gnupg_source = (GnupgSource*)source;
 
523
        gint i;
 
524
 
 
525
        for (i = 0; i < NUM_FDS; ++i) {
 
526
                if (gnupg_source->polls[i].fd >= 0)
 
527
                        return FALSE;
 
528
        }
 
529
 
 
530
        /* If none of the FDs are valid, then process immediately */
 
531
        return TRUE;
 
532
}
 
533
 
 
534
static gboolean
 
535
on_gnupg_source_check (GSource *source)
 
536
{
 
537
        GnupgSource *gnupg_source = (GnupgSource*)source;
 
538
        gint i;
 
539
 
 
540
        for (i = 0; i < NUM_FDS; ++i) {
 
541
                if (gnupg_source->polls[i].fd >= 0 && gnupg_source->polls[i].revents != 0)
 
542
                        return TRUE;
 
543
        }
 
544
        return FALSE;
 
545
}
 
546
 
 
547
static void
 
548
on_gnupg_source_finalize (GSource *source)
 
549
{
 
550
        GnupgSource *gnupg_source = (GnupgSource*)source;
 
551
        gint i;
 
552
 
 
553
        g_assert (gnupg_source->cancellable == NULL);
 
554
        g_assert (gnupg_source->cancel_sig == 0);
 
555
 
 
556
        for (i = 0; i < NUM_FDS; ++i)
 
557
                close_fd (&gnupg_source->polls[i].fd);
 
558
 
 
559
        g_object_unref (gnupg_source->process);
 
560
        if (gnupg_source->input_buf)
 
561
                g_byte_array_free (gnupg_source->input_buf, TRUE);
 
562
        g_string_free (gnupg_source->error_buf, TRUE);
 
563
        g_string_free (gnupg_source->status_buf, TRUE);
 
564
 
 
565
        g_assert (!gnupg_source->child_pid);
 
566
        g_assert (!gnupg_source->child_sig);
 
567
}
 
568
 
 
569
static gboolean
 
570
read_output (int fd, GByteArray *buffer)
 
571
{
 
572
        guchar block[1024];
 
573
        gssize result;
 
574
 
 
575
        g_return_val_if_fail (fd >= 0, FALSE);
 
576
 
 
577
        do {
 
578
                result = read (fd, block, sizeof (block));
 
579
                if (result < 0) {
 
580
                        if (errno == EINTR || errno == EAGAIN)
 
581
                                continue;
 
582
                        return FALSE;
 
583
                } else {
 
584
                        g_byte_array_append (buffer, block, result);
 
585
                }
 
586
        } while (result == sizeof (block));
 
587
 
 
588
        return TRUE;
 
589
}
 
590
 
 
591
static gboolean
 
592
write_input (int fd, GByteArray *buffer)
 
593
{
 
594
        gssize result;
 
595
 
 
596
        g_return_val_if_fail (fd >= 0, FALSE);
 
597
 
 
598
        for (;;) {
 
599
                result = write (fd, buffer->data, buffer->len);
 
600
                if (result < 0) {
 
601
                        if (errno == EINTR || errno == EAGAIN)
 
602
                                continue;
 
603
                        return FALSE;
 
604
                } else {
 
605
                        g_byte_array_remove_range (buffer, 0, result);
 
606
                        return TRUE;
 
607
                }
 
608
        }
 
609
}
 
610
 
 
611
static void
 
612
emit_status_for_each_line (const gchar *line, gpointer user_data)
 
613
{
 
614
        GcrRecord *record;
 
615
 
 
616
        if (g_str_has_prefix (line, "[GNUPG:] ")) {
 
617
                _gcr_debug ("received status line: %s", line);
 
618
                line += 9;
 
619
        } else {
 
620
                g_message ("gnupg status record was not prefixed appropriately: %s", line);
 
621
                return;
 
622
        }
 
623
 
 
624
        record = _gcr_record_parse_spaces (line, -1);
 
625
        if (!record) {
 
626
                g_message ("couldn't parse status record: %s", line);
 
627
                return;
 
628
        }
 
629
 
 
630
        g_signal_emit (GCR_GNUPG_PROCESS (user_data), signals[STATUS_RECORD], 0, record);
 
631
        _gcr_record_free (record);
 
632
}
 
633
 
 
634
static void
 
635
emit_error_for_each_line (const gchar *line, gpointer user_data)
 
636
{
 
637
        _gcr_debug ("received error line: %s", line);
 
638
        g_signal_emit (GCR_GNUPG_PROCESS (user_data), signals[ERROR_LINE], 0, line);
 
639
}
 
640
 
 
641
static gboolean
 
642
on_gnupg_source_input (GcrGnupgProcess *self,
 
643
                       GnupgSource *gnupg_source,
 
644
                       gint fd)
 
645
{
 
646
        gssize read;
 
647
 
 
648
        if (gnupg_source->input_buf == NULL ||
 
649
            gnupg_source->input_buf->len == 0) {
 
650
                if (self->pv->input == NULL)
 
651
                        return FALSE;
 
652
                if (!gnupg_source->input_buf)
 
653
                        gnupg_source->input_buf = g_byte_array_new ();
 
654
                g_byte_array_set_size (gnupg_source->input_buf, 4096);
 
655
                read = g_input_stream_read (self->pv->input,
 
656
                                            gnupg_source->input_buf->data,
 
657
                                            gnupg_source->input_buf->len,
 
658
                                            gnupg_source->cancellable, NULL);
 
659
                g_byte_array_set_size (gnupg_source->input_buf, read < 0 ? 0 : read);
 
660
                if (read < 0)
 
661
                        return FALSE;
 
662
                if (read == 0)
 
663
                        return FALSE;
 
664
        }
 
665
 
 
666
        if (!write_input (fd, gnupg_source->input_buf)) {
 
667
                g_warning ("couldn't write output data to gnupg process");
 
668
                return FALSE;
 
669
        }
 
670
 
 
671
        return TRUE;
 
672
}
 
673
 
 
674
static gboolean
 
675
on_gnupg_source_status (GcrGnupgProcess *self,
 
676
                        GnupgSource *gnupg_source,
 
677
                        gint fd)
 
678
{
 
679
        GByteArray *buffer = g_byte_array_new ();
 
680
        gboolean result = TRUE;
 
681
 
 
682
        if (!read_output (fd, buffer)) {
 
683
                g_warning ("couldn't read status data from gnupg process");
 
684
                result = FALSE;
 
685
        } else {
 
686
                g_string_append_len (gnupg_source->status_buf, (gchar*)buffer->data, buffer->len);
 
687
                _gcr_util_parse_lines (gnupg_source->status_buf, buffer->len == 0,
 
688
                                       emit_status_for_each_line, self);
 
689
        }
 
690
 
 
691
        g_byte_array_unref (buffer);
 
692
        return result;
 
693
}
 
694
 
 
695
static gboolean
 
696
on_gnupg_source_attribute (GcrGnupgProcess *self,
 
697
                           GnupgSource *gnupg_source,
 
698
                           gint fd)
 
699
{
 
700
        GByteArray *buffer = g_byte_array_new ();
 
701
        gboolean result = TRUE;
 
702
 
 
703
        if (!read_output (fd, buffer)) {
 
704
                g_warning ("couldn't read attribute data from gnupg process");
 
705
                result = FALSE;
 
706
        } else if (buffer->len > 0) {
 
707
                _gcr_debug ("received %d bytes of attribute data", (gint)buffer->len);
 
708
                if (self->pv->attributes != NULL)
 
709
                        g_output_stream_write_all (self->pv->attributes, buffer->data,
 
710
                                                   buffer->len, NULL,
 
711
                                                   gnupg_source->cancellable, NULL);
 
712
        }
 
713
 
 
714
        g_byte_array_unref (buffer);
 
715
        return result;
 
716
}
 
717
 
 
718
static gboolean
 
719
on_gnupg_source_output (GcrGnupgProcess *self,
 
720
                        GnupgSource *gnupg_source,
 
721
                        gint fd)
 
722
{
 
723
        GByteArray *buffer = g_byte_array_new ();
 
724
        gboolean result = TRUE;
 
725
 
 
726
        if (!read_output (fd, buffer)) {
 
727
                g_warning ("couldn't read output data from gnupg process");
 
728
                result = FALSE;
 
729
        } else if (buffer->len > 0) {
 
730
                _gcr_debug ("received %d bytes of output data", (gint)buffer->len);
 
731
                if (self->pv->output != NULL)
 
732
                        g_output_stream_write_all (self->pv->output, buffer->data, buffer->len,
 
733
                                                   NULL, gnupg_source->cancellable, NULL);
 
734
        }
 
735
 
 
736
        g_byte_array_unref (buffer);
 
737
        return result;
 
738
}
 
739
 
 
740
static gboolean
 
741
on_gnupg_source_error (GcrGnupgProcess *self,
 
742
                       GnupgSource *gnupg_source,
 
743
                       gint fd,
 
744
                       gboolean last)
 
745
{
 
746
        GByteArray *buffer = g_byte_array_new ();
 
747
        gboolean result = TRUE;
 
748
 
 
749
        if (!read_output (fd, buffer)) {
 
750
                g_warning ("couldn't read error data from gnupg process");
 
751
                result = FALSE;
 
752
        } else {
 
753
                g_string_append_len (gnupg_source->error_buf, (gchar*)buffer->data, buffer->len);
 
754
                _gcr_util_parse_lines (gnupg_source->error_buf, last,
 
755
                                       emit_error_for_each_line, gnupg_source->process);
 
756
        }
 
757
 
 
758
        g_byte_array_unref (buffer);
 
759
        return result;
 
760
}
 
761
 
 
762
static gboolean
 
763
on_gnupg_source_dispatch (GSource *source, GSourceFunc unused, gpointer user_data)
 
764
{
 
765
        GnupgSource *gnupg_source = (GnupgSource*)source;
 
766
        GcrGnupgProcess *self = gnupg_source->process;
 
767
        GPollFD *poll;
 
768
        guint i;
 
769
 
 
770
        /* Standard input, no support yet */
 
771
        poll = &gnupg_source->polls[FD_INPUT];
 
772
        if (poll->fd >= 0) {
 
773
                if (poll->revents & G_IO_OUT)
 
774
                        if (!on_gnupg_source_input (self, gnupg_source, poll->fd))
 
775
                                poll->revents |= G_IO_HUP;
 
776
                if (poll->revents & G_IO_HUP)
 
777
                        close_poll (source, poll);
 
778
                poll->revents = 0;
 
779
        }
 
780
 
 
781
        /* Status output */
 
782
        poll = &gnupg_source->polls[FD_STATUS];
 
783
        if (poll->fd >= 0) {
 
784
                if (poll->revents & G_IO_IN)
 
785
                        if (!on_gnupg_source_status (self, gnupg_source, poll->fd))
 
786
                                poll->revents |= G_IO_HUP;
 
787
                if (poll->revents & G_IO_HUP)
 
788
                        close_poll (source, poll);
 
789
                poll->revents = 0;
 
790
        }
 
791
 
 
792
        /* Attribute output */
 
793
        poll = &gnupg_source->polls[FD_ATTRIBUTE];
 
794
        if (poll->fd >= 0) {
 
795
                if (poll->revents & G_IO_IN)
 
796
                        if (!on_gnupg_source_attribute (self, gnupg_source, poll->fd))
 
797
                                poll->revents |= G_IO_HUP;
 
798
                if (poll->revents & G_IO_HUP)
 
799
                        close_poll (source, poll);
 
800
                poll->revents = 0;
 
801
        }
 
802
 
 
803
        /* Standard output */
 
804
        poll = &gnupg_source->polls[FD_OUTPUT];
 
805
        if (poll->fd >= 0) {
 
806
                if (poll->revents & G_IO_IN)
 
807
                        if (!on_gnupg_source_output (self, gnupg_source, poll->fd))
 
808
                                poll->revents |= G_IO_HUP;
 
809
                if (poll->revents & G_IO_HUP)
 
810
                        close_poll (source, poll);
 
811
                poll->revents = 0;
 
812
        }
 
813
 
 
814
        /* Standard error */
 
815
        poll = &gnupg_source->polls[FD_ERROR];
 
816
        if (poll->fd >= 0) {
 
817
                if (poll->revents & G_IO_IN)
 
818
                        if (!on_gnupg_source_error (self, gnupg_source, poll->fd,
 
819
                                                    (poll->revents & G_IO_HUP) ? TRUE : FALSE))
 
820
                                poll->revents |= G_IO_HUP;
 
821
                if (poll->revents & G_IO_HUP)
 
822
                        close_poll (source, poll);
 
823
                poll->revents = 0;
 
824
        }
 
825
 
 
826
        for (i = 0; i < NUM_FDS; ++i) {
 
827
                if (gnupg_source->polls[i].fd >= 0)
 
828
                        return TRUE;
 
829
        }
 
830
 
 
831
        /* Because we return below */
 
832
        self->pv->source_sig = 0;
 
833
 
 
834
        if (!gnupg_source->child_pid)
 
835
                complete_source_is_done (gnupg_source);
 
836
 
 
837
        return FALSE; /* Disconnect this source */
 
838
}
 
839
 
 
840
static GSourceFuncs gnupg_source_funcs = {
 
841
        on_gnupg_source_prepare,
 
842
        on_gnupg_source_check,
 
843
        on_gnupg_source_dispatch,
 
844
        on_gnupg_source_finalize,
 
845
};
 
846
 
 
847
static void
 
848
on_gnupg_process_child_exited (GPid pid, gint status, gpointer user_data)
 
849
{
 
850
        GnupgSource *gnupg_source = user_data;
 
851
        GcrGnupgProcess *self = gnupg_source->process;
 
852
        GError *error = NULL;
 
853
        gint code;
 
854
        guint i;
 
855
 
 
856
        _gcr_debug ("process exited: %d", (int)pid);
 
857
 
 
858
        g_spawn_close_pid (gnupg_source->child_pid);
 
859
        gnupg_source->child_pid = 0;
 
860
        gnupg_source->child_sig = 0;
 
861
 
 
862
        if (WIFEXITED (status)) {
 
863
                code = WEXITSTATUS (status);
 
864
                if (code != 0) {
 
865
                        error = g_error_new (G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
 
866
                                             _("Gnupg process exited with code: %d"), code);
 
867
                }
 
868
        } else if (WIFSIGNALED (status)) {
 
869
                code = WTERMSIG (status);
 
870
                /* Ignore cases where we've signaled the process because we were cancelled */
 
871
                if (!g_error_matches (self->pv->error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 
872
                        error = g_error_new (G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
 
873
                                             _("Gnupg process was terminated with signal: %d"), code);
 
874
        }
 
875
 
 
876
        /* Take this as the async result error */
 
877
        if (error && !self->pv->error) {
 
878
                _gcr_debug ("%s", error->message);
 
879
                self->pv->error = error;
 
880
 
 
881
        /* Already have an error, just print out message */
 
882
        } else if (error) {
 
883
                g_warning ("%s", error->message);
 
884
                g_error_free (error);
 
885
        }
 
886
 
 
887
        for (i = 0; i < NUM_FDS; ++i) {
 
888
                if (gnupg_source->polls[i].fd >= 0)
 
889
                        return;
 
890
        }
 
891
 
 
892
        complete_source_is_done (gnupg_source);
 
893
}
 
894
 
 
895
static void
 
896
on_gnupg_process_child_setup (gpointer user_data)
 
897
{
 
898
        int *child_fds = user_data;
 
899
        long val;
 
900
        guint i;
 
901
 
 
902
        /*
 
903
         * Clear close-on-exec flag for these file descriptors, so that
 
904
         * gnupg can write to them
 
905
         */
 
906
 
 
907
        for (i = 0; i < NUM_FDS; i++) {
 
908
                if (child_fds[i] >= 0) {
 
909
                        val = fcntl (child_fds[i], F_GETFD);
 
910
                        fcntl (child_fds[i], F_SETFD, val & ~FD_CLOEXEC);
 
911
                }
 
912
        }
 
913
}
 
914
 
 
915
static void
 
916
on_cancellable_cancelled (GCancellable *cancellable, gpointer user_data)
 
917
{
 
918
        GnupgSource *gnupg_source = user_data;
 
919
 
 
920
        g_assert (gnupg_source->process);
 
921
 
 
922
        _gcr_debug ("process cancelled");
 
923
 
 
924
        /* Set an error, which is respected when this actually completes. */
 
925
        if (gnupg_source->process->pv->error == NULL)
 
926
                gnupg_source->process->pv->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
 
927
                                                                        _("The operation was cancelled"));
 
928
 
 
929
        /* Try and kill the child process */
 
930
        if (gnupg_source->child_pid) {
 
931
                _gcr_debug ("sending term signal to process: %d",
 
932
                            (int)gnupg_source->child_pid);
 
933
                kill (gnupg_source->child_pid, SIGTERM);
 
934
        }
 
935
}
 
936
 
 
937
/**
 
938
 * _gcr_gnupg_process_run_async:
 
939
 * @self: The process
 
940
 * @argv: (array zero-terminated=1): The arguments for the process, not including executable, terminated with %NULL.
 
941
 * @envp: (allow-none) (array zero-terminated=1): The environment for new process, terminated with %NULL.
 
942
 * @flags: Flags for starting the process.
 
943
 * @cancellable: (allow-none): Cancellation object
 
944
 * @callback: Will be called when operation completes.
 
945
 * @user_data: (closure): Data passed to callback.
 
946
 *
 
947
 * Run the gpg process. Only one 'run' operation can run per GcrGnupgProcess
 
948
 * object. The GcrGnupgProcess:output_data and GcrGnupgProcess:error_line
 
949
 * signals will be emitted when data is received from the gpg process.
 
950
 *
 
951
 * Unless the %GCR_GNUPG_PROCESS_RESPECT_LOCALE flag is specified, the process
 
952
 * will be run in the 'C' locale. If the %GCR_GNUPG_PROCESS_WITH_STATUS or
 
953
 * %GCR_GNUPG_PROCESS_WITH_ATTRIBUTES flags are set, then the gpg process
 
954
 * will be status and attribute output respectively. The
 
955
 * GcrGnupgProcess:status_record and GcrGnupgProcess:attribute_data signals
 
956
 * will provide this data.
 
957
 */
 
958
void
 
959
_gcr_gnupg_process_run_async (GcrGnupgProcess *self, const gchar **argv, const gchar **envp,
 
960
                              GcrGnupgProcessFlags flags, GCancellable *cancellable,
 
961
                              GAsyncReadyCallback callback, gpointer user_data)
 
962
{
 
963
        GError *error = NULL;
 
964
        GPtrArray *args;
 
965
        GPtrArray *envs;
 
966
        int child_fds[NUM_FDS];
 
967
        int status_fds[2] = { -1, -1 };
 
968
        int attribute_fds[2] = { -1, -1 };
 
969
        int output_fd = -1;
 
970
        int error_fd = -1;
 
971
        int input_fd = -1;
 
972
        GnupgSource *gnupg_source;
 
973
        GSource *source;
 
974
        GPid pid;
 
975
        guint i;
 
976
 
 
977
        g_return_if_fail (GCR_IS_GNUPG_PROCESS (self));
 
978
        g_return_if_fail (argv);
 
979
        g_return_if_fail (callback);
 
980
        g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
981
 
 
982
        g_return_if_fail (self->pv->running == FALSE);
 
983
        g_return_if_fail (self->pv->complete == FALSE);
 
984
        g_return_if_fail (self->pv->executable);
 
985
 
 
986
        self->pv->async_callback = callback;
 
987
        self->pv->user_data = user_data;
 
988
 
 
989
        for (i = 0; i < NUM_FDS; i++)
 
990
                child_fds[i] = -1;
 
991
 
 
992
        /* The command needs to be updated with these status and attribute fds */
 
993
        args = g_ptr_array_new_with_free_func (g_free);
 
994
        g_ptr_array_add (args, g_strdup (self->pv->executable));
 
995
 
 
996
        /* Spawn/child will close all other attributes, besides thesthose in child_fds */
 
997
        child_fds[FD_INPUT] = 0;
 
998
        child_fds[FD_OUTPUT] = 1;
 
999
        child_fds[FD_ERROR] = 2;
 
1000
 
 
1001
        if (flags & GCR_GNUPG_PROCESS_WITH_STATUS) {
 
1002
                if (pipe (status_fds) < 0)
 
1003
                        g_return_if_reached ();
 
1004
                child_fds[FD_STATUS] = status_fds[1];
 
1005
                g_ptr_array_add (args, g_strdup ("--status-fd"));
 
1006
                g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_STATUS]));
 
1007
        }
 
1008
        if (flags & GCR_GNUPG_PROCESS_WITH_ATTRIBUTES) {
 
1009
                if (pipe (attribute_fds) < 0)
 
1010
                        g_return_if_reached ();
 
1011
                child_fds[FD_ATTRIBUTE] = attribute_fds[1];
 
1012
                g_ptr_array_add (args, g_strdup ("--attribute-fd"));
 
1013
                g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_ATTRIBUTE]));
 
1014
        }
 
1015
 
 
1016
        if (self->pv->directory) {
 
1017
                g_ptr_array_add (args, g_strdup ("--homedir"));
 
1018
                g_ptr_array_add (args, g_strdup (self->pv->directory));
 
1019
        }
 
1020
 
 
1021
        /* All the remaining arguments */
 
1022
        for (i = 0; argv[i] != NULL; i++)
 
1023
                g_ptr_array_add (args, g_strdup (argv[i]));
 
1024
        g_ptr_array_add (args, NULL);
 
1025
 
 
1026
        envs = g_ptr_array_new ();
 
1027
        for (i = 0; envp && envp[i] != NULL; i++) {
 
1028
                if (flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE ||
 
1029
                    !g_str_has_prefix (envp[i], "LOCALE="))
 
1030
                        g_ptr_array_add (envs, (gpointer)envp[i]);
 
1031
        }
 
1032
        if (!(flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE))
 
1033
                g_ptr_array_add (envs, (gpointer)"LOCALE=C");
 
1034
        g_ptr_array_add (envs, NULL);
 
1035
 
 
1036
        if (_gcr_debugging) {
 
1037
                gchar *command = g_strjoinv (" ", (gchar**)args->pdata);
 
1038
                gchar *environ = g_strjoinv (", ", (gchar**)envs->pdata);
 
1039
                _gcr_debug ("running command: %s", command);
 
1040
                _gcr_debug ("process environment: %s", environ);
 
1041
                g_free (command);
 
1042
                g_free (environ);
 
1043
        }
 
1044
 
 
1045
        g_spawn_async_with_pipes (self->pv->directory, (gchar**)args->pdata,
 
1046
                                  (gchar**)envs->pdata, G_SPAWN_DO_NOT_REAP_CHILD,
 
1047
                                  on_gnupg_process_child_setup, child_fds,
 
1048
                                  &pid, &input_fd, &output_fd, &error_fd, &error);
 
1049
 
 
1050
        g_ptr_array_free (args, TRUE);
 
1051
        g_ptr_array_free (envs, TRUE);
 
1052
 
 
1053
        /* Close 'wrong' ends of extra file descriptors */
 
1054
        close_fd (&(status_fds[1]));
 
1055
        close_fd (&(attribute_fds[1]));
 
1056
 
 
1057
        self->pv->complete = FALSE;
 
1058
        self->pv->running = TRUE;
 
1059
 
 
1060
        if (error) {
 
1061
                close_fd (&(status_fds[0]));
 
1062
                close_fd (&(attribute_fds[0]));
 
1063
                g_assert (!self->pv->error);
 
1064
                self->pv->error = error;
 
1065
                complete_run_process (self);
 
1066
                run_async_ready_callback_later (self);
 
1067
                return;
 
1068
        }
 
1069
 
 
1070
        _gcr_debug ("process started: %d", (int)pid);
 
1071
 
 
1072
        source = g_source_new (&gnupg_source_funcs, sizeof (GnupgSource));
 
1073
 
 
1074
        /* Initialize the source */
 
1075
        gnupg_source = (GnupgSource*)source;
 
1076
        for (i = 0; i < NUM_FDS; i++)
 
1077
                gnupg_source->polls[i].fd = -1;
 
1078
        gnupg_source->error_buf = g_string_sized_new (128);
 
1079
        gnupg_source->status_buf = g_string_sized_new (128);
 
1080
        gnupg_source->process = g_object_ref (self);
 
1081
        gnupg_source->child_pid = pid;
 
1082
 
 
1083
        gnupg_source->polls[FD_INPUT].fd = input_fd;
 
1084
        if (input_fd >= 0) {
 
1085
                gnupg_source->polls[FD_INPUT].events = G_IO_HUP | G_IO_OUT;
 
1086
                g_source_add_poll (source, &gnupg_source->polls[FD_INPUT]);
 
1087
        }
 
1088
        gnupg_source->polls[FD_OUTPUT].fd = output_fd;
 
1089
        if (output_fd >= 0) {
 
1090
                gnupg_source->polls[FD_OUTPUT].events = G_IO_HUP | G_IO_IN;
 
1091
                g_source_add_poll (source, &gnupg_source->polls[FD_OUTPUT]);
 
1092
        }
 
1093
        gnupg_source->polls[FD_ERROR].fd = error_fd;
 
1094
        if (error_fd >= 0) {
 
1095
                gnupg_source->polls[FD_ERROR].events = G_IO_HUP | G_IO_IN;
 
1096
                g_source_add_poll (source, &gnupg_source->polls[FD_ERROR]);
 
1097
        }
 
1098
        gnupg_source->polls[FD_STATUS].fd = status_fds[0];
 
1099
        if (status_fds[0] >= 0) {
 
1100
                gnupg_source->polls[FD_STATUS].events = G_IO_HUP | G_IO_IN;
 
1101
                g_source_add_poll (source, &gnupg_source->polls[FD_STATUS]);
 
1102
        }
 
1103
        gnupg_source->polls[FD_ATTRIBUTE].fd = attribute_fds[0];
 
1104
        if (attribute_fds[0] >= 0) {
 
1105
                gnupg_source->polls[FD_ATTRIBUTE].events = G_IO_HUP | G_IO_IN;
 
1106
                g_source_add_poll (source, &gnupg_source->polls[FD_ATTRIBUTE]);
 
1107
        }
 
1108
 
 
1109
        if (cancellable) {
 
1110
                gnupg_source->cancellable = g_object_ref (cancellable);
 
1111
                gnupg_source->cancel_sig = g_cancellable_connect (cancellable,
 
1112
                                                                  G_CALLBACK (on_cancellable_cancelled),
 
1113
                                                                  g_source_ref (source),
 
1114
                                                                  (GDestroyNotify)g_source_unref);
 
1115
        }
 
1116
 
 
1117
        g_assert (self->pv->source_sig == 0);
 
1118
        g_source_set_callback (source, unused_callback, NULL, NULL);
 
1119
        self->pv->source_sig = g_source_attach (source, g_main_context_default ());
 
1120
 
 
1121
        /* This assumes the outstanding reference to source */
 
1122
        g_assert (gnupg_source->child_sig == 0);
 
1123
        gnupg_source->child_sig = g_child_watch_add_full (G_PRIORITY_DEFAULT, pid,
 
1124
                                                          on_gnupg_process_child_exited,
 
1125
                                                          g_source_ref (source),
 
1126
                                                          (GDestroyNotify)g_source_unref);
 
1127
 
 
1128
        /* source is unreffed in complete_if_source_is_done() */
 
1129
}
 
1130
 
 
1131
/**
 
1132
 * _gcr_gnupg_process_run_finish:
 
1133
 * @self: The process
 
1134
 * @result: The result passed to the callback
 
1135
 * @error: Location to raise an error on failure.
 
1136
 *
 
1137
 * Get the result of running a gnupg process.
 
1138
 *
 
1139
 * Return value: Whether the Gnupg process was run or not.
 
1140
 */
 
1141
gboolean
 
1142
_gcr_gnupg_process_run_finish (GcrGnupgProcess *self, GAsyncResult *result,
 
1143
                               GError **error)
 
1144
{
 
1145
        g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (self), FALSE);
 
1146
        g_return_val_if_fail (!error || !*error, FALSE);
 
1147
        g_return_val_if_fail (G_ASYNC_RESULT (self) == result, FALSE);
 
1148
        g_return_val_if_fail (self->pv->complete, FALSE);
 
1149
 
 
1150
        /* This allows the process to run again... */
 
1151
        self->pv->complete = FALSE;
 
1152
 
 
1153
        g_assert (!self->pv->running);
 
1154
        g_assert (!self->pv->async_callback);
 
1155
        g_assert (!self->pv->user_data);
 
1156
 
 
1157
        if (self->pv->error) {
 
1158
                g_propagate_error (error, self->pv->error);
 
1159
                self->pv->error = NULL;
 
1160
                return FALSE;
 
1161
        }
 
1162
 
 
1163
        return TRUE;
 
1164
}