Merge branch 'gnupg-process'
[platform/upstream/gcr.git] / gcr / gcr-gnupg-process.c
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 };
54
55 enum {
56         FD_INPUT,
57         FD_OUTPUT,
58         FD_ERROR,
59         FD_STATUS,
60         FD_ATTRIBUTE,
61         NUM_FDS
62 };
63
64 enum {
65         OUTPUT_DATA,
66         ERROR_LINE,
67         STATUS_RECORD,
68         ATTRIBUTE_DATA,
69         NUM_SIGNALS
70 };
71
72 static gint signals[NUM_SIGNALS] = { 0, };
73
74 typedef struct _GnupgSource {
75         GSource source;
76         GPollFD polls[NUM_FDS];         /* The various fd's we're listening to */
77
78         GcrGnupgProcess *process;       /* Pointer back to the process object */
79
80         GString *error_buf;
81         GString *status_buf;
82
83         GPid child_pid;
84         guint child_sig;
85
86         GCancellable *cancellable;
87         guint cancel_sig;
88 } GnupgSource;
89
90 struct _GcrGnupgProcessPrivate {
91         gchar *directory;
92         gchar *executable;
93
94         gboolean running;
95         gboolean complete;
96         GError *error;
97
98         guint source_sig;
99
100         GAsyncReadyCallback async_callback;
101         gpointer user_data;
102 };
103
104 /* Forward declarations */
105 static void _gcr_gnupg_process_init_async (GAsyncResultIface *iface);
106
107 G_DEFINE_TYPE_WITH_CODE (GcrGnupgProcess, _gcr_gnupg_process, G_TYPE_OBJECT,
108                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, _gcr_gnupg_process_init_async));
109
110 static void
111 _gcr_gnupg_process_init (GcrGnupgProcess *self)
112 {
113         self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_GNUPG_PROCESS,
114                                                 GcrGnupgProcessPrivate);
115 }
116
117 static void
118 _gcr_gnupg_process_constructed (GObject *obj)
119 {
120         GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
121
122         if (G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->constructed)
123                 G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->constructed (obj);
124
125         if (!self->pv->executable)
126                 self->pv->executable = g_strdup (GPG_EXECUTABLE);
127 }
128
129 static void
130 _gcr_gnupg_process_get_property (GObject *obj, guint prop_id, GValue *value,
131                                  GParamSpec *pspec)
132 {
133         GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
134
135         switch (prop_id) {
136         case PROP_DIRECTORY:
137                 g_value_set_string (value, self->pv->directory);
138                 break;
139         case PROP_EXECUTABLE:
140                 g_value_set_string (value, self->pv->executable);
141                 break;
142         default:
143                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
144                 break;
145         }
146 }
147
148 static void
149 _gcr_gnupg_process_set_property (GObject *obj, guint prop_id, const GValue *value,
150                                  GParamSpec *pspec)
151 {
152         GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
153
154         switch (prop_id) {
155         case PROP_DIRECTORY:
156                 g_return_if_fail (!self->pv->directory);
157                 self->pv->directory = g_value_dup_string (value);
158                 break;
159         case PROP_EXECUTABLE:
160                 g_return_if_fail (!self->pv->executable);
161                 self->pv->executable = g_value_dup_string (value);
162                 break;
163         default:
164                 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
165                 break;
166         }
167 }
168
169 static void
170 _gcr_gnupg_process_finalize (GObject *obj)
171 {
172         GcrGnupgProcess *self = GCR_GNUPG_PROCESS (obj);
173
174         g_assert (!self->pv->running);
175         g_free (self->pv->directory);
176         g_free (self->pv->executable);
177         g_clear_error (&self->pv->error);
178
179         G_OBJECT_CLASS (_gcr_gnupg_process_parent_class)->finalize (obj);
180 }
181
182 static void
183 _gcr_gnupg_process_class_init (GcrGnupgProcessClass *klass)
184 {
185         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
186
187         gobject_class->constructed = _gcr_gnupg_process_constructed;
188         gobject_class->get_property = _gcr_gnupg_process_get_property;
189         gobject_class->set_property = _gcr_gnupg_process_set_property;
190         gobject_class->finalize = _gcr_gnupg_process_finalize;
191
192         /**
193          * GcrGnupgProcess:directory:
194          *
195          * Directory to run as gnupg home directory, or %NULL for default
196          * ~/.gnupg/ directory.
197          */
198         g_object_class_install_property (gobject_class, PROP_DIRECTORY,
199                    g_param_spec_string ("directory", "Directory", "Gnupg Directory",
200                                         NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
201
202         /**
203          * GcrGnupgProcess:executable:
204          *
205          * Path to the gnupg executable, or %NULL for default.
206          */
207         g_object_class_install_property (gobject_class, PROP_EXECUTABLE,
208                    g_param_spec_string ("executable", "Executable", "Gnupg Executable",
209                                         GPG_EXECUTABLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
210
211         /**
212          * GcrGnupgProcess::output-data:
213          * @data: a #GByteArray of output data.
214          *
215          * Signal emitted when normal output data is available from the gnupg
216          * process. The data does not necessarily come on line boundaries, and
217          * won't be null-terminated.
218          */
219         signals[OUTPUT_DATA] = g_signal_new ("output-data", GCR_TYPE_GNUPG_PROCESS,
220                    G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, output_data),
221                    NULL, NULL, _gcr_marshal_VOID__BOXED,
222                    G_TYPE_NONE, 1, G_TYPE_BYTE_ARRAY);
223
224         /**
225          * GcrGnupgProcess::error-line:
226          * @line: a line of error output.
227          *
228          * Signal emitted when a line of error output is available from the
229          * gnupg process.
230          */
231         signals[ERROR_LINE] = g_signal_new ("error-line", GCR_TYPE_GNUPG_PROCESS,
232                    G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, error_line),
233                    NULL, NULL, _gcr_marshal_VOID__STRING,
234                    G_TYPE_NONE, 1, G_TYPE_STRING);
235
236         /**
237          * GcrGnupgProcess::status-record:
238          * @record: a status record.
239          *
240          * Signal emitted when a status record is available from the gnupg process.
241          */
242         signals[STATUS_RECORD] = g_signal_new ("status-record", GCR_TYPE_GNUPG_PROCESS,
243                    G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, status_record),
244                    NULL, NULL, _gcr_marshal_VOID__BOXED,
245                    G_TYPE_NONE, 1, GCR_TYPE_RECORD);
246
247         /**
248          * GcrGnupgProcess::attribute-data:
249          * @data: a #GByteArray of attribute data.
250          *
251          * Signal emitted when attribute data is available from the gnupg
252          * process.
253          */
254         signals[ATTRIBUTE_DATA] = g_signal_new ("attribute-data", GCR_TYPE_GNUPG_PROCESS,
255                    G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GcrGnupgProcessClass, attribute_data),
256                    NULL, NULL, _gcr_marshal_VOID__BOXED,
257                    G_TYPE_NONE, 1, G_TYPE_BYTE_ARRAY);
258
259         g_type_class_add_private (gobject_class, sizeof (GcrGnupgProcessPrivate));
260 }
261
262 static gpointer
263 _gcr_gnupg_process_get_user_data (GAsyncResult *result)
264 {
265         g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (result), NULL);
266         return GCR_GNUPG_PROCESS (result)->pv->user_data;
267 }
268
269 static GObject*
270 _gcr_gnupg_process_get_source_object (GAsyncResult *result)
271 {
272         g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (result), NULL);
273         return G_OBJECT (result);
274 }
275
276 static void
277 _gcr_gnupg_process_init_async (GAsyncResultIface *iface)
278 {
279         iface->get_source_object = _gcr_gnupg_process_get_source_object;
280         iface->get_user_data = _gcr_gnupg_process_get_user_data;
281 }
282
283 /**
284  * _gcr_gnupg_process_new:
285  * @directory: (allow-none): The gnupg home directory
286  * @executable: (allow-none): The gpg executable
287  *
288  * Create a new GcrGnupgProcess.
289  *
290  * The gnupg home directory is where the keyring files live. If directory is
291  * %NULL then the default gnupg home directory is used.
292  *
293  * The executable will default to the compiled in path if a %NULL executable
294  * argument is used.
295  *
296  * Returns: (transfer full): A newly allocated process.
297  */
298 GcrGnupgProcess*
299 _gcr_gnupg_process_new (const gchar *directory, const gchar *executable)
300 {
301         return g_object_new (GCR_TYPE_GNUPG_PROCESS,
302                              "directory", directory,
303                              "executable", executable,
304                              NULL);
305 }
306
307 static void
308 run_async_ready_callback (GcrGnupgProcess *self)
309 {
310         GAsyncReadyCallback callback;
311         gpointer user_data;
312
313         _gcr_debug ("running async callback");
314
315         /* Remove these before completing */
316         callback = self->pv->async_callback;
317         user_data = self->pv->user_data;
318         self->pv->async_callback = NULL;
319         self->pv->user_data = NULL;
320
321         if (callback != NULL)
322                 (callback) (G_OBJECT (self), G_ASYNC_RESULT (self), user_data);
323 }
324
325 static gboolean
326 on_run_async_ready_callback_later (gpointer user_data)
327 {
328         run_async_ready_callback (GCR_GNUPG_PROCESS (user_data));
329         return FALSE; /* Don't run this callback again */
330 }
331
332 static void
333 run_async_ready_callback_later (GcrGnupgProcess *self)
334 {
335         _gcr_debug ("running async callback later");
336         g_idle_add_full (G_PRIORITY_DEFAULT, on_run_async_ready_callback_later,
337                          g_object_ref (self), g_object_unref);
338 }
339
340 static void
341 complete_run_process (GcrGnupgProcess *self)
342 {
343         g_return_if_fail (self->pv->running);
344         g_return_if_fail (!self->pv->complete);
345
346         self->pv->running = FALSE;
347         self->pv->complete = TRUE;
348
349         if (self->pv->source_sig) {
350                 g_source_remove (self->pv->source_sig);
351                 self->pv->source_sig = 0;
352         }
353
354         if (self->pv->error == NULL) {
355                 _gcr_debug ("completed process");
356         } else {
357                 _gcr_debug ("completed process with error: %s",
358                             self->pv->error->message);
359         }
360 }
361
362 static gboolean
363 complete_if_source_is_done (GnupgSource *gnupg_source)
364 {
365         gint i;
366
367         for (i = 0; i < NUM_FDS; ++i) {
368                 if (gnupg_source->polls[i].fd >= 0)
369                         return FALSE;
370         }
371
372         if (gnupg_source->child_pid)
373                 return FALSE;
374
375         _gcr_debug ("all fds closed and process exited, completing");
376
377         complete_run_process (gnupg_source->process);
378         run_async_ready_callback (gnupg_source->process);
379
380         /* All done, the source can go away now */
381         g_source_unref ((GSource*)gnupg_source);
382         return TRUE;
383 }
384
385 static void
386 close_fd (int *fd)
387 {
388         g_assert (fd);
389         if (*fd >= 0) {
390                 _gcr_debug ("closing fd: %d", *fd);
391                 close (*fd);
392         }
393         *fd = -1;
394 }
395
396 static void
397 close_poll (GSource *source, GPollFD *poll)
398 {
399         g_source_remove_poll (source, poll);
400         close_fd (&poll->fd);
401         poll->revents = 0;
402 }
403
404 static gboolean
405 unused_callback (gpointer data)
406 {
407         /* Never called */
408         g_assert_not_reached ();
409         return FALSE;
410 }
411
412 static gboolean
413 on_gnupg_source_prepare (GSource *source, gint *timeout_)
414 {
415         GnupgSource *gnupg_source = (GnupgSource*)source;
416         gint i;
417
418         for (i = 0; i < NUM_FDS; ++i) {
419                 if (gnupg_source->polls[i].fd >= 0)
420                         return FALSE;
421         }
422
423         /* If none of the FDs are valid, then process immediately */
424         return TRUE;
425 }
426
427 static gboolean
428 on_gnupg_source_check (GSource *source)
429 {
430         GnupgSource *gnupg_source = (GnupgSource*)source;
431         gint i;
432
433         for (i = 0; i < NUM_FDS; ++i) {
434                 if (gnupg_source->polls[i].fd >= 0 && gnupg_source->polls[i].revents != 0)
435                         return TRUE;
436         }
437         return FALSE;
438 }
439
440 static void
441 on_gnupg_source_finalize (GSource *source)
442 {
443         GnupgSource *gnupg_source = (GnupgSource*)source;
444         gint i;
445
446         if (gnupg_source->cancel_sig)
447                 g_signal_handler_disconnect (gnupg_source->cancellable, gnupg_source->cancel_sig);
448         if (gnupg_source->cancellable)
449                 g_object_unref (gnupg_source->cancellable);
450
451         for (i = 0; i < NUM_FDS; ++i)
452                 close_fd (&gnupg_source->polls[i].fd);
453
454         g_object_unref (gnupg_source->process);
455         g_string_free (gnupg_source->error_buf, TRUE);
456         g_string_free (gnupg_source->status_buf, TRUE);
457
458         g_assert (!gnupg_source->child_pid);
459         g_assert (!gnupg_source->child_sig);
460 }
461
462 static gboolean
463 read_output (int fd, GByteArray *buffer)
464 {
465         guchar block[1024];
466         gssize result;
467
468         g_return_val_if_fail (fd >= 0, FALSE);
469
470         do {
471                 result = read (fd, block, sizeof (block));
472                 if (result < 0) {
473                         if (errno == EINTR || errno == EAGAIN)
474                                 continue;
475                         return FALSE;
476                 } else {
477                         g_byte_array_append (buffer, block, result);
478                 }
479         } while (result == sizeof (block));
480
481         return TRUE;
482 }
483
484 static void
485 emit_status_for_each_line (const gchar *line, gpointer user_data)
486 {
487         GcrRecord *record;
488
489         if (g_str_has_prefix (line, "[GNUPG:] ")) {
490                 _gcr_debug ("received status line: %s", line);
491                 line += 9;
492         } else {
493                 g_message ("gnupg status record was not prefixed appropriately: %s", line);
494                 return;
495         }
496
497         record = _gcr_record_parse_spaces (line, -1);
498         if (!record) {
499                 g_message ("couldn't parse status record: %s", line);
500                 return;
501         }
502
503         g_signal_emit (GCR_GNUPG_PROCESS (user_data), signals[STATUS_RECORD], 0, record);
504         _gcr_record_free (record);
505 }
506
507 static void
508 emit_error_for_each_line (const gchar *line, gpointer user_data)
509 {
510         _gcr_debug ("received error line: %s", line);
511         g_signal_emit (GCR_GNUPG_PROCESS (user_data), signals[ERROR_LINE], 0, line);
512 }
513
514 static gboolean
515 on_gnupg_source_dispatch (GSource *source, GSourceFunc unused, gpointer user_data)
516 {
517         GnupgSource *gnupg_source = (GnupgSource*)source;
518         GByteArray *buffer;
519         GPollFD *poll;
520
521         /* Standard input, no support yet */
522         poll = &gnupg_source->polls[FD_INPUT];
523         if (poll->fd >= 0 && poll->revents != 0) {
524                 close_poll (source, poll);
525         }
526
527         /* Status output */
528         poll = &gnupg_source->polls[FD_STATUS];
529         if (poll->fd >= 0) {
530                 if (poll->revents & G_IO_IN) {
531                         buffer = g_byte_array_new ();
532                         if (!read_output (poll->fd, buffer)) {
533                                 g_warning ("couldn't read status data from gnupg process");
534                         } else {
535                                 g_string_append_len (gnupg_source->status_buf, (gchar*)buffer->data, buffer->len);
536                                 _gcr_util_parse_lines (gnupg_source->status_buf, buffer->len == 0,
537                                                        emit_status_for_each_line, gnupg_source->process);
538                         }
539                         g_byte_array_unref (buffer);
540                 }
541                 if (poll->revents & G_IO_HUP)
542                         close_poll (source, poll);
543                 poll->revents = 0;
544         }
545
546         /* Attribute output */
547         poll = &gnupg_source->polls[FD_ATTRIBUTE];
548         if (poll->fd >= 0) {
549                 if (poll->revents & G_IO_IN) {
550                         buffer = g_byte_array_new ();
551                         if (!read_output (poll->fd, buffer)) {
552                                 g_warning ("couldn't read attribute data from gnupg process");
553                         } else if (buffer->len > 0) {
554                                 _gcr_debug ("received %d bytes of attribute data", (gint)buffer->len);
555                                 g_signal_emit (gnupg_source->process, signals[ATTRIBUTE_DATA], 0, buffer);
556                         }
557                         g_byte_array_unref (buffer);
558                 }
559                 if (poll->revents & G_IO_HUP)
560                         close_poll (source, poll);
561                 poll->revents = 0;
562         }
563
564         /* Standard output */
565         poll = &gnupg_source->polls[FD_OUTPUT];
566         if (poll->fd >= 0) {
567                 if (poll->revents & G_IO_IN) {
568                         buffer = g_byte_array_new ();
569                         if (!read_output (poll->fd, buffer)) {
570                                 g_warning ("couldn't read output data from gnupg process");
571                         } else if (buffer->len > 0) {
572                                 _gcr_debug ("received %d bytes of output data", (gint)buffer->len);
573                                 g_signal_emit (gnupg_source->process, signals[OUTPUT_DATA], 0, buffer);
574                         }
575                         g_byte_array_unref (buffer);
576                 }
577                 if (poll->revents & G_IO_HUP)
578                         close_poll (source, poll);
579                 poll->revents = 0;
580         }
581
582         /* Standard error */
583         poll = &gnupg_source->polls[FD_ERROR];
584         if (poll->fd >= 0) {
585                 if (poll->revents & G_IO_IN) {
586                         buffer = g_byte_array_new ();
587                         if (!read_output (poll->fd, buffer)) {
588                                 g_warning ("couldn't read error data from gnupg process");
589                         } else {
590                                 g_string_append_len (gnupg_source->error_buf, (gchar*)buffer->data, buffer->len);
591                                 _gcr_util_parse_lines (gnupg_source->error_buf, (poll->revents & G_IO_HUP) ? TRUE : FALSE,
592                                                        emit_error_for_each_line, gnupg_source->process);
593                         }
594                         g_byte_array_unref (buffer);
595                 }
596                 if (poll->revents & G_IO_HUP)
597                         close_poll (source, poll);
598                 poll->revents = 0;
599         }
600
601         if (complete_if_source_is_done (gnupg_source))
602                 return FALSE; /* Disconnect this source */
603
604         return TRUE;
605 }
606
607 static GSourceFuncs gnupg_source_funcs = {
608         on_gnupg_source_prepare,
609         on_gnupg_source_check,
610         on_gnupg_source_dispatch,
611         on_gnupg_source_finalize,
612 };
613
614 static void
615 on_gnupg_process_child_exited (GPid pid, gint status, gpointer user_data)
616 {
617         GnupgSource *gnupg_source = user_data;
618         GcrGnupgProcess *self = gnupg_source->process;
619         GError *error = NULL;
620         gint code;
621
622         _gcr_debug ("process exited: %d", (int)pid);
623
624         g_spawn_close_pid (gnupg_source->child_pid);
625         gnupg_source->child_pid = 0;
626         gnupg_source->child_sig = 0;
627
628         if (WIFEXITED (status)) {
629                 code = WEXITSTATUS (status);
630                 if (code != 0) {
631                         error = g_error_new (G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
632                                              _("Gnupg process exited with code: %d"), code);
633                 }
634         } else if (WIFSIGNALED (status)) {
635                 code = WTERMSIG (status);
636                 /* Ignore cases where we've signaled the process because we were cancelled */
637                 if (!g_error_matches (self->pv->error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
638                         error = g_error_new (G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED,
639                                              _("Gnupg process was terminated with signal: %d"), code);
640         }
641
642         /* Take this as the async result error */
643         if (error && !self->pv->error) {
644                 _gcr_debug ("%s", error->message);
645                 self->pv->error = error;
646
647         /* Already have an error, just print out message */
648         } else if (error) {
649                 g_warning ("%s", error->message);
650                 g_error_free (error);
651         }
652
653         complete_if_source_is_done (gnupg_source);
654 }
655
656 static void
657 on_gnupg_process_child_setup (gpointer user_data)
658 {
659         int *child_fds = user_data;
660         long val;
661         guint i;
662
663         /*
664          * Clear close-on-exec flag for these file descriptors, so that
665          * gnupg can write to them
666          */
667
668         for (i = 0; i < NUM_FDS; i++) {
669                 if (child_fds[i] >= 0) {
670                         val = fcntl (child_fds[i], F_GETFD);
671                         fcntl (child_fds[i], F_SETFD, val & ~FD_CLOEXEC);
672                 }
673         }
674 }
675
676 static void
677 on_cancellable_cancelled (GCancellable *cancellable, gpointer user_data)
678 {
679         GnupgSource *gnupg_source = user_data;
680
681         g_assert (gnupg_source->process);
682
683         _gcr_debug ("process cancelled");
684
685         /* Try and kill the child process */
686         if (gnupg_source->child_pid) {
687                 _gcr_debug ("sending term signal to process: %d",
688                             (int)gnupg_source->child_pid);
689                 kill (gnupg_source->child_pid, SIGTERM);
690         }
691
692         /* Set an error, which is respected when this actually completes. */
693         if (gnupg_source->process->pv->error == NULL)
694                 gnupg_source->process->pv->error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
695                                                                         _("The operation was cancelled"));
696
697         complete_if_source_is_done (gnupg_source);
698 }
699
700 /**
701  * _gcr_gnupg_process_run_async:
702  * @self: The process
703  * @argv: (array zero-terminated=1): The arguments for the process, not including executable, terminated with %NULL.
704  * @envp: (allow-none) (array zero-terminated=1): The environment for new process, terminated with %NULL.
705  * @flags: Flags for starting the process.
706  * @cancellable: (allow-none): Cancellation object
707  * @callback: Will be called when operation completes.
708  * @user_data: (closure): Data passed to callback.
709  *
710  * Run the gpg process. Only one 'run' operation can run per GcrGnupgProcess
711  * object. The GcrGnupgProcess:output_data and GcrGnupgProcess:error_line
712  * signals will be emitted when data is received from the gpg process.
713  *
714  * Unless the %GCR_GNUPG_PROCESS_RESPECT_LOCALE flag is specified, the process
715  * will be run in the 'C' locale. If the %GCR_GNUPG_PROCESS_WITH_STATUS or
716  * %GCR_GNUPG_PROCESS_WITH_ATTRIBUTES flags are set, then the gpg process
717  * will be status and attribute output respectively. The
718  * GcrGnupgProcess:status_record and GcrGnupgProcess:attribute_data signals
719  * will provide this data.
720  */
721 void
722 _gcr_gnupg_process_run_async (GcrGnupgProcess *self, const gchar **argv, const gchar **envp,
723                               GcrGnupgProcessFlags flags, GCancellable *cancellable,
724                               GAsyncReadyCallback callback, gpointer user_data)
725 {
726         GError *error = NULL;
727         GPtrArray *args;
728         GPtrArray *envs;
729         int child_fds[NUM_FDS];
730         int status_fds[2] = { -1, -1 };
731         int attribute_fds[2] = { -1, -1 };
732         int output_fd = -1;
733         int error_fd = -1;
734         GnupgSource *gnupg_source;
735         GSource *source;
736         GPid pid;
737         guint i;
738
739         g_return_if_fail (GCR_IS_GNUPG_PROCESS (self));
740         g_return_if_fail (argv);
741         g_return_if_fail (callback);
742         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
743
744         g_return_if_fail (self->pv->running == FALSE);
745         g_return_if_fail (self->pv->complete == FALSE);
746         g_return_if_fail (self->pv->executable);
747
748         self->pv->async_callback = callback;
749         self->pv->user_data = user_data;
750
751         for (i = 0; i < NUM_FDS; i++)
752                 child_fds[i] = -1;
753
754         /* The command needs to be updated with these status and attribute fds */
755         args = g_ptr_array_new_with_free_func (g_free);
756         g_ptr_array_add (args, g_strdup (self->pv->executable));
757
758         /* Spawn/child will close all other attributes, besides thesthose in child_fds */
759         child_fds[FD_OUTPUT] = 1;
760         child_fds[FD_ERROR] = 2;
761
762         if (flags & GCR_GNUPG_PROCESS_WITH_STATUS) {
763                 if (pipe (status_fds) < 0)
764                         g_return_if_reached ();
765                 child_fds[FD_STATUS] = status_fds[1];
766                 g_ptr_array_add (args, g_strdup ("--status-fd"));
767                 g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_STATUS]));
768         }
769         if (flags & GCR_GNUPG_PROCESS_WITH_ATTRIBUTES) {
770                 if (pipe (attribute_fds) < 0)
771                         g_return_if_reached ();
772                 child_fds[FD_ATTRIBUTE] = attribute_fds[1];
773                 g_ptr_array_add (args, g_strdup ("--attribute-fd"));
774                 g_ptr_array_add (args, g_strdup_printf ("%d", child_fds[FD_ATTRIBUTE]));
775         }
776
777         if (self->pv->directory) {
778                 g_ptr_array_add (args, g_strdup ("--homedir"));
779                 g_ptr_array_add (args, g_strdup (self->pv->directory));
780         }
781
782         /* All the remaining arguments */
783         for (i = 0; argv[i] != NULL; i++)
784                 g_ptr_array_add (args, g_strdup (argv[i]));
785         g_ptr_array_add (args, NULL);
786
787         envs = g_ptr_array_new ();
788         for (i = 0; envp && envp[i] != NULL; i++) {
789                 if (flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE ||
790                     !g_str_has_prefix (envp[i], "LOCALE="))
791                         g_ptr_array_add (envs, (gpointer)envp[i]);
792         }
793         if (!(flags & GCR_GNUPG_PROCESS_RESPECT_LOCALE))
794                 g_ptr_array_add (envs, (gpointer)"LOCALE=C");
795         g_ptr_array_add (envs, NULL);
796
797         if (_gcr_debugging) {
798                 gchar *command = g_strjoinv (" ", (gchar**)args->pdata);
799                 gchar *environ = g_strjoinv (", ", (gchar**)envs->pdata);
800                 _gcr_debug ("running command: %s", command);
801                 _gcr_debug ("process environment: %s", environ);
802                 g_free (command);
803                 g_free (environ);
804         }
805
806         g_spawn_async_with_pipes (self->pv->directory, (gchar**)args->pdata,
807                                   (gchar**)envs->pdata, G_SPAWN_DO_NOT_REAP_CHILD,
808                                   on_gnupg_process_child_setup,
809                                   child_fds, &pid, NULL, &output_fd, &error_fd, &error);
810
811         g_ptr_array_free (args, TRUE);
812         g_ptr_array_free (envs, TRUE);
813
814         /* Close 'wrong' ends of extra file descriptors */
815         close_fd (&(status_fds[1]));
816         close_fd (&(attribute_fds[1]));
817
818         self->pv->complete = FALSE;
819         self->pv->running = TRUE;
820
821         if (error) {
822                 close_fd (&(status_fds[0]));
823                 close_fd (&(attribute_fds[0]));
824                 g_assert (!self->pv->error);
825                 self->pv->error = error;
826                 complete_run_process (self);
827                 run_async_ready_callback_later (self);
828                 return;
829         }
830
831         _gcr_debug ("process started: %d", (int)pid);
832
833         source = g_source_new (&gnupg_source_funcs, sizeof (GnupgSource));
834
835         /* Initialize the source */
836         gnupg_source = (GnupgSource*)source;
837         for (i = 0; i < NUM_FDS; i++)
838                 gnupg_source->polls[i].fd = -1;
839         gnupg_source->error_buf = g_string_sized_new (128);
840         gnupg_source->status_buf = g_string_sized_new (128);
841         gnupg_source->process = g_object_ref (self);
842         gnupg_source->child_pid = pid;
843
844         gnupg_source->polls[FD_OUTPUT].fd = output_fd;
845         if (output_fd >= 0) {
846                 gnupg_source->polls[FD_OUTPUT].events = G_IO_HUP | G_IO_IN;
847                 g_source_add_poll (source, &gnupg_source->polls[FD_OUTPUT]);
848         }
849         gnupg_source->polls[FD_ERROR].fd = error_fd;
850         if (error_fd >= 0) {
851                 gnupg_source->polls[FD_ERROR].events = G_IO_HUP | G_IO_IN;
852                 g_source_add_poll (source, &gnupg_source->polls[FD_ERROR]);
853         }
854         gnupg_source->polls[FD_STATUS].fd = status_fds[0];
855         if (status_fds[0] >= 0) {
856                 gnupg_source->polls[FD_STATUS].events = G_IO_HUP | G_IO_IN;
857                 g_source_add_poll (source, &gnupg_source->polls[FD_STATUS]);
858         }
859         gnupg_source->polls[FD_ATTRIBUTE].fd = attribute_fds[0];
860         if (attribute_fds[0] >= 0) {
861                 gnupg_source->polls[FD_ATTRIBUTE].events = G_IO_HUP | G_IO_IN;
862                 g_source_add_poll (source, &gnupg_source->polls[FD_ATTRIBUTE]);
863         }
864
865         if (cancellable) {
866                 gnupg_source->cancellable = g_object_ref (cancellable);
867                 gnupg_source->cancel_sig = g_cancellable_connect (cancellable,
868                                                                   G_CALLBACK (on_cancellable_cancelled),
869                                                                   g_source_ref (source),
870                                                                   (GDestroyNotify)g_source_unref);
871         }
872
873         g_assert (!self->pv->source_sig);
874         g_source_set_callback (source, unused_callback, NULL, NULL);
875         self->pv->source_sig = g_source_attach (source, g_main_context_default ());
876
877         /* This assumes the outstanding reference to source */
878         g_assert (!gnupg_source->child_sig);
879         gnupg_source->child_sig = g_child_watch_add_full (G_PRIORITY_DEFAULT, pid,
880                                                           on_gnupg_process_child_exited,
881                                                           g_source_ref (source),
882                                                           (GDestroyNotify)g_source_unref);
883
884         /* source is unreffed in complete_if_source_is_done() */
885 }
886
887 /**
888  * _gcr_gnupg_process_run_finish:
889  * @self: The process
890  * @result: The result passed to the callback
891  * @error: Location to raise an error on failure.
892  *
893  * Get the result of running a gnupg process.
894  *
895  * Return value: Whether the Gnupg process was run or not.
896  */
897 gboolean
898 _gcr_gnupg_process_run_finish (GcrGnupgProcess *self, GAsyncResult *result,
899                                GError **error)
900 {
901         g_return_val_if_fail (GCR_IS_GNUPG_PROCESS (self), FALSE);
902         g_return_val_if_fail (!error || !*error, FALSE);
903         g_return_val_if_fail (G_ASYNC_RESULT (self) == result, FALSE);
904         g_return_val_if_fail (self->pv->complete, FALSE);
905
906         /* This allows the process to run again... */
907         self->pv->complete = FALSE;
908
909         g_assert (!self->pv->running);
910         g_assert (!self->pv->async_callback);
911         g_assert (!self->pv->user_data);
912         g_assert (!self->pv->source_sig);
913
914         if (self->pv->error) {
915                 g_propagate_error (error, self->pv->error);
916                 self->pv->error = NULL;
917                 return FALSE;
918         }
919
920         return TRUE;
921 }