1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22 
23 #include <config.h>
24 
25 #include <gmountsource.h>
26 #include <gio/gio.h>
27 #include <gvfsdbus.h>
28 #include "gvfsdaemonprotocol.h"
29 
30 #include <string.h>
31 
32 struct _GMountSource
33 {
34   GObject parent_instance;
35 
36   char *dbus_id;
37   char *obj_path;
38 };
39 
G_DEFINE_TYPE(GMountSource,g_mount_source,G_TYPE_OBJECT)40 G_DEFINE_TYPE (GMountSource, g_mount_source, G_TYPE_OBJECT)
41 
42 static void
43 g_mount_source_finalize (GObject *object)
44 {
45   GMountSource *source;
46 
47   source = G_MOUNT_SOURCE (object);
48 
49   g_free (source->dbus_id);
50   g_free (source->obj_path);
51 
52   if (G_OBJECT_CLASS (g_mount_source_parent_class)->finalize)
53     (*G_OBJECT_CLASS (g_mount_source_parent_class)->finalize) (object);
54 }
55 
56 static void
g_mount_source_class_init(GMountSourceClass * klass)57 g_mount_source_class_init (GMountSourceClass *klass)
58 {
59   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
60 
61   gobject_class->finalize = g_mount_source_finalize;
62 }
63 
64 static void
g_mount_source_init(GMountSource * mount_source)65 g_mount_source_init (GMountSource *mount_source)
66 {
67 }
68 
69 GMountSource *
g_mount_source_new(const char * dbus_id,const char * obj_path)70 g_mount_source_new (const char *dbus_id,
71 		    const char *obj_path)
72 {
73   GMountSource *source;
74 
75   source = g_object_new (G_TYPE_MOUNT_SOURCE, NULL);
76 
77   source->dbus_id = g_strdup (dbus_id);
78   source->obj_path = g_strdup (obj_path);
79 
80   return source;
81 }
82 
83 GMountSource *
g_mount_source_new_dummy(void)84 g_mount_source_new_dummy (void)
85 {
86   GMountSource *source;
87 
88   source = g_object_new (G_TYPE_MOUNT_SOURCE, NULL);
89 
90   source->dbus_id = g_strdup ("");
91   source->obj_path = g_strdup ("/");
92 
93   return source;
94 }
95 
96 GVariant *
g_mount_source_to_dbus(GMountSource * source)97 g_mount_source_to_dbus (GMountSource *source)
98 {
99   g_assert (source->dbus_id != NULL);
100   g_assert (source->obj_path != NULL);
101 
102   return g_variant_new ("(so)",
103                         source->dbus_id,
104                         source->obj_path);
105 }
106 
107 GMountSource *
g_mount_source_from_dbus(GVariant * value)108 g_mount_source_from_dbus (GVariant *value)
109 {
110   const gchar *obj_path, *dbus_id;
111 
112   g_variant_get (value, "(&s&o)",
113                  &dbus_id,
114                  &obj_path);
115 
116   return g_mount_source_new (dbus_id, obj_path);
117 }
118 
119 const char *
g_mount_source_get_dbus_id(GMountSource * mount_source)120 g_mount_source_get_dbus_id (GMountSource *mount_source)
121 {
122   return mount_source->dbus_id;
123 }
124 
125 const char *
g_mount_source_get_obj_path(GMountSource * mount_source)126 g_mount_source_get_obj_path (GMountSource *mount_source)
127 {
128   return mount_source->obj_path;
129 }
130 
131 typedef struct AskPasswordData AskPasswordData;
132 
133 struct AskPasswordData {
134 
135   /* results: */
136   gboolean       aborted;
137   char          *password;
138   char          *username;
139   char          *domain;
140   GPasswordSave  password_save;
141   gboolean	 anonymous;
142 };
143 
144 typedef struct AskSyncData AskSyncData;
145 
146 struct AskSyncData {
147 
148   /* For sync calls */
149   GMainContext *context;
150   GMainLoop *loop;
151 
152   /* results: */
153   GAsyncResult *result;
154 };
155 
156 static void
ask_password_data_free(gpointer _data)157 ask_password_data_free (gpointer _data)
158 {
159   AskPasswordData *data = (AskPasswordData *) _data;
160   g_free (data->password);
161   g_free (data->username);
162   g_free (data->domain);
163   g_free (data);
164 }
165 
166 static GVfsDBusMountOperation *
create_mount_operation_proxy_sync(GMountSource * source,GError ** error)167 create_mount_operation_proxy_sync (GMountSource        *source,
168                                    GError             **error)
169 {
170   GVfsDBusMountOperation *proxy;
171   GError *local_error;
172 
173   /* If no dbus id specified, reply that we weren't handled */
174   if (source->dbus_id[0] == 0)
175     {
176       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Internal Error");
177       return NULL;
178     }
179 
180   local_error = NULL;
181   /* Synchronously creating a proxy using unique/private d-bus name and not loading properties or connecting signals should not block */
182   proxy = gvfs_dbus_mount_operation_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
183                                                             G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
184                                                             source->dbus_id,
185                                                             source->obj_path,
186                                                             NULL,
187                                                             &local_error);
188   if (proxy == NULL)
189     {
190       g_dbus_error_strip_remote_error (local_error);
191       g_propagate_error (error, local_error);
192     }
193 
194   return proxy;
195 }
196 
197 /* the callback from dbus -> main thread */
198 static void
ask_password_reply(GVfsDBusMountOperation * proxy,GAsyncResult * res,gpointer user_data)199 ask_password_reply (GVfsDBusMountOperation *proxy,
200                     GAsyncResult *res,
201                     gpointer user_data)
202 {
203   GTask *task;
204   AskPasswordData *data;
205   gboolean handled, aborted, anonymous;
206   guint32 password_save;
207   gchar *password, *username, *domain;
208   GError *error;
209 
210   task = G_TASK (user_data);
211   handled = TRUE;
212 
213   error = NULL;
214   if (!gvfs_dbus_mount_operation_call_ask_password_finish (proxy,
215                                                            &handled,
216                                                            &aborted,
217                                                            &password,
218                                                            &username,
219                                                            &domain,
220                                                            &anonymous,
221                                                            &password_save,
222                                                            res,
223                                                            &error))
224     {
225       g_dbus_error_strip_remote_error (error);
226       g_task_return_error (task, error);
227     }
228   else if (handled == FALSE)
229     {
230       g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Internal Error");
231     }
232   else
233     {
234       data = g_new0 (AskPasswordData, 1);
235       data->aborted = aborted;
236 
237       if (!anonymous)
238         {
239           data->password = g_strdup (password);
240           data->username = *username == 0 ? NULL : g_strdup (username);
241           data->domain = *domain == 0 ? NULL : g_strdup (domain);
242         }
243       data->password_save = (GPasswordSave)password_save;
244       data->anonymous = anonymous;
245 
246       g_task_return_pointer (task, data, ask_password_data_free);
247 
248       /* TODO: handle more args */
249       g_free (password);
250       g_free (username);
251       g_free (domain);
252     }
253 
254   g_object_unref (task);
255 }
256 
257 void
g_mount_source_ask_password_async(GMountSource * source,const char * message_string,const char * default_user,const char * default_domain,GAskPasswordFlags flags,GAsyncReadyCallback callback,gpointer user_data)258 g_mount_source_ask_password_async (GMountSource              *source,
259                                    const char                *message_string,
260                                    const char                *default_user,
261                                    const char                *default_domain,
262                                    GAskPasswordFlags          flags,
263                                    GAsyncReadyCallback        callback,
264                                    gpointer                   user_data)
265 {
266   GTask *task;
267   GVfsDBusMountOperation *proxy;
268   GError *error = NULL;
269 
270   task = g_task_new (source, NULL, callback, user_data);
271   g_task_set_source_tag (task, g_mount_source_ask_password_async);
272 
273   proxy = create_mount_operation_proxy_sync (source, &error);
274   if (proxy == NULL)
275     {
276       g_task_return_error (task, error);
277       g_object_unref (task);
278       return;
279     }
280 
281   /* 30 minute timeout */
282   g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (proxy), G_VFS_DBUS_MOUNT_TIMEOUT_MSECS);
283 
284   gvfs_dbus_mount_operation_call_ask_password (proxy,
285                                                message_string ? message_string : "",
286                                                default_user ? default_user : "",
287                                                default_domain ? default_domain : "",
288                                                flags,
289                                                NULL,
290                                                (GAsyncReadyCallback) ask_password_reply,
291                                                task);
292   g_object_unref (proxy);
293 }
294 
295 /**
296  * g_mount_source_ask_password_finish:
297  * @source: the source to query
298  * @result: the async result
299  * @aborted: set to %TRUE if the password dialog was aborted by the user
300  * @password_out: the to the password set by the user or to %NULL if none
301  * @user_out: set to the username set by the user or to %NULL if none
302  * @domain_out: set to the domain set by the user or to %NULL if none
303  * @anonymous_out: set to %TRUE if the user selected anonymous login. This
304  *                 should only happen if G_ASK_PASSWORD_ANONYMOUS_SUPPORTED
305  *                 was supplied whe querying the password.
306  * @password_save_out: set to the save flags to use when saving the password
307  *                     in the keyring.
308  *
309  * Requests the reply parameters from a g_mount_source_ask_password_async()
310  * request. All out parameters can be set to %NULL to ignore them.
311  * <note><para>Please be aware that out parameters other than the password
312  * are set to %NULL if the user don't specify them so make sure to
313  * check them.</para></note>
314  *
315  * Returns: %FALSE if the async reply contained an error.
316  **/
317 gboolean
g_mount_source_ask_password_finish(GMountSource * source,GAsyncResult * result,gboolean * aborted,char ** password_out,char ** user_out,char ** domain_out,gboolean * anonymous_out,GPasswordSave * password_save_out)318 g_mount_source_ask_password_finish (GMountSource  *source,
319                                     GAsyncResult  *result,
320                                     gboolean      *aborted,
321                                     char         **password_out,
322                                     char         **user_out,
323                                     char         **domain_out,
324 				    gboolean	  *anonymous_out,
325 				    GPasswordSave *password_save_out)
326 {
327   AskPasswordData *data, def = { TRUE, };
328 
329   g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
330   g_return_val_if_fail (g_async_result_is_tagged (result, g_mount_source_ask_password_async), FALSE);
331 
332   data = g_task_propagate_pointer (G_TASK (result), NULL);
333   if (data == NULL)
334     data = &def;
335 
336   if (aborted)
337     *aborted = data->aborted;
338 
339   if (password_out)
340     {
341       *password_out = data->password;
342       data->password = NULL;
343     }
344 
345   if (user_out)
346     {
347       *user_out = data->username;
348       data->username = NULL;
349     }
350 
351   if (domain_out)
352     {
353       *domain_out = data->domain;
354       data->domain = NULL;
355     }
356 
357   if (anonymous_out)
358     *anonymous_out = data->anonymous;
359 
360   if (password_save_out)
361     *password_save_out = data->password_save;
362 
363   return data != &def;
364 }
365 
366 
367 static void
ask_reply_sync(GObject * source_object,GAsyncResult * res,gpointer user_data)368 ask_reply_sync  (GObject *source_object,
369 		 GAsyncResult *res,
370 		 gpointer user_data)
371 {
372   AskSyncData *data;
373 
374   data = (AskSyncData *) user_data;
375 
376   data->result = g_object_ref (res);
377 
378   g_main_loop_quit (data->loop);
379 }
380 
381 gboolean
g_mount_source_ask_password(GMountSource * source,const char * message_string,const char * default_user,const char * default_domain,GAskPasswordFlags flags,gboolean * aborted_out,char ** password_out,char ** user_out,char ** domain_out,gboolean * anonymous_out,GPasswordSave * password_save_out)382 g_mount_source_ask_password (GMountSource *source,
383 			     const char *message_string,
384 			     const char *default_user,
385 			     const char *default_domain,
386 			     GAskPasswordFlags flags,
387 			     gboolean *aborted_out,
388 			     char **password_out,
389 			     char **user_out,
390 			     char **domain_out,
391 			     gboolean *anonymous_out,
392 			     GPasswordSave *password_save_out)
393 {
394   gboolean handled;
395   AskSyncData data;
396 
397   data.context = g_main_context_new ();
398   data.loop = g_main_loop_new (data.context, FALSE);
399 
400   g_main_context_push_thread_default (data.context);
401 
402   g_mount_source_ask_password_async (source,
403                                      message_string,
404                                      default_user,
405                                      default_domain,
406                                      flags,
407                                      ask_reply_sync,
408                                      &data);
409 
410   g_main_loop_run (data.loop);
411 
412   handled = g_mount_source_ask_password_finish (source,
413                                                 data.result,
414                                                 aborted_out,
415                                                 password_out,
416                                                 user_out,
417                                                 domain_out,
418 						anonymous_out,
419 						password_save_out);
420 
421   g_main_context_pop_thread_default (data.context);
422   g_main_context_unref (data.context);
423   g_main_loop_unref (data.loop);
424   g_object_unref (data.result);
425 
426   return handled;
427 }
428 
429 static void
op_ask_password_reply(GObject * source_object,GAsyncResult * res,gpointer user_data)430 op_ask_password_reply (GObject *source_object,
431                        GAsyncResult *res,
432                        gpointer user_data)
433 {
434   GMountOperationResult result;
435   GMountOperation *op;
436   GMountSource *source;
437   gboolean handled, aborted;
438   char *username;
439   char *password;
440   char *domain;
441   GPasswordSave password_save;
442 
443   source = G_MOUNT_SOURCE (source_object);
444   op = G_MOUNT_OPERATION (user_data);
445   username = NULL;
446   password = NULL;
447   domain = NULL;
448 
449   handled = g_mount_source_ask_password_finish (source,
450                                                 res,
451                                                 &aborted,
452                                                 &password,
453                                                 &username,
454                                                 &domain,
455 						NULL,
456 						&password_save);
457 
458   if (!handled)
459     result = G_MOUNT_OPERATION_UNHANDLED;
460   else if (aborted)
461     result = G_MOUNT_OPERATION_ABORTED;
462   else
463     {
464       result = G_MOUNT_OPERATION_HANDLED;
465 
466       if (password)
467 	g_mount_operation_set_password (op, password);
468       if (username)
469 	g_mount_operation_set_username (op, username);
470       if (domain)
471 	g_mount_operation_set_domain (op, domain);
472       g_mount_operation_set_password_save (op, password_save);
473     }
474 
475   g_mount_operation_reply (op, result);
476   g_object_unref (op);
477 }
478 
479 static gboolean
op_ask_password(GMountOperation * op,const char * message,const char * default_user,const char * default_domain,GAskPasswordFlags flags,GMountSource * mount_source)480 op_ask_password (GMountOperation *op,
481 		 const char      *message,
482 		 const char      *default_user,
483 		 const char      *default_domain,
484 		 GAskPasswordFlags flags,
485 		 GMountSource *mount_source)
486 {
487   g_mount_source_ask_password_async (mount_source,
488 				     message,
489 				     default_user,
490 				     default_domain,
491                                      flags,
492 				     op_ask_password_reply,
493 				     g_object_ref (op));
494   g_signal_stop_emission_by_name (op, "ask_password");
495   return TRUE;
496 }
497 
498 typedef struct AskQuestionData AskQuestionData;
499 
500 struct AskQuestionData {
501 
502   /* results: */
503   gboolean aborted;
504   guint32  choice;
505 };
506 
507 /* the callback from dbus -> main thread */
508 static void
ask_question_reply(GVfsDBusMountOperation * proxy,GAsyncResult * res,gpointer user_data)509 ask_question_reply (GVfsDBusMountOperation *proxy,
510                     GAsyncResult *res,
511                     gpointer user_data)
512 {
513   GTask *task;
514   AskQuestionData *data;
515   gboolean handled, aborted;
516   guint32 choice;
517   GError *error;
518 
519   task = G_TASK (user_data);
520   handled = TRUE;
521 
522   error = NULL;
523   if (!gvfs_dbus_mount_operation_call_ask_question_finish (proxy,
524                                                            &handled,
525                                                            &aborted,
526                                                            &choice,
527                                                            res,
528                                                            &error))
529     {
530       g_dbus_error_strip_remote_error (error);
531       g_task_return_error (task, error);
532     }
533   else if (handled == FALSE)
534     {
535       g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Internal Error");
536     }
537   else
538     {
539       data = g_new0 (AskQuestionData, 1);
540       data->aborted = aborted;
541       data->choice = choice;
542 
543       g_task_return_pointer (task, data, g_free);
544     }
545 
546   g_object_unref (task);
547 }
548 
549 gboolean
g_mount_source_ask_question(GMountSource * source,const char * message,const char ** choices,gboolean * aborted_out,gint * choice_out)550 g_mount_source_ask_question (GMountSource *source,
551 			     const char   *message,
552 			     const char  **choices,
553 			     gboolean     *aborted_out,
554 			     gint         *choice_out)
555 {
556   gint choice;
557   gboolean handled, aborted;
558   AskSyncData data;
559 
560   data.context = g_main_context_new ();
561   data.loop = g_main_loop_new (data.context, FALSE);
562 
563   g_main_context_push_thread_default (data.context);
564 
565   g_mount_source_ask_question_async (source,
566                                      message,
567 				     choices,
568                                      ask_reply_sync,
569                                      &data);
570 
571   g_main_loop_run (data.loop);
572 
573   handled = g_mount_source_ask_question_finish (source,
574                                                 data.result,
575                                                 &aborted,
576                                                 &choice);
577 
578   g_main_context_pop_thread_default (data.context);
579   g_main_context_unref (data.context);
580   g_main_loop_unref (data.loop);
581   g_object_unref (data.result);
582 
583   if (aborted_out)
584     *aborted_out = aborted;
585 
586   if (choice_out)
587     *choice_out = choice;
588 
589   return handled;
590 }
591 
592 void
g_mount_source_ask_question_async(GMountSource * source,const char * message_string,const char ** choices,GAsyncReadyCallback callback,gpointer user_data)593 g_mount_source_ask_question_async (GMountSource       *source,
594 				   const char         *message_string,
595 				   const char        **choices,
596 				   GAsyncReadyCallback callback,
597 				   gpointer            user_data)
598 {
599   GTask *task;
600   GVfsDBusMountOperation *proxy;
601   GError *error = NULL;
602 
603   task = g_task_new (source, NULL, callback, user_data);
604   g_task_set_source_tag (task, g_mount_source_ask_question_async);
605 
606   proxy = create_mount_operation_proxy_sync (source, &error);
607   if (proxy == NULL)
608     {
609       g_task_return_error (task, error);
610       g_object_unref (task);
611       return;
612     }
613 
614   /* 30 minute timeout */
615   g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (proxy), G_VFS_DBUS_MOUNT_TIMEOUT_MSECS);
616 
617   gvfs_dbus_mount_operation_call_ask_question (proxy,
618                                                message_string ? message_string : "",
619                                                choices,
620                                                NULL,
621                                                (GAsyncReadyCallback) ask_question_reply,
622                                                task);
623   g_object_unref (proxy);
624 }
625 
626 gboolean
g_mount_source_ask_question_finish(GMountSource * source,GAsyncResult * result,gboolean * aborted,gint * choice_out)627 g_mount_source_ask_question_finish (GMountSource *source,
628 				    GAsyncResult *result,
629 				    gboolean     *aborted,
630 				    gint         *choice_out)
631 {
632   AskQuestionData *data, def = { TRUE, };
633 
634   g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
635   g_return_val_if_fail (g_async_result_is_tagged (result, g_mount_source_ask_question_async), FALSE);
636 
637   data = g_task_propagate_pointer (G_TASK (result), NULL);
638   if (data == NULL)
639     data = &def;
640 
641   if (aborted)
642     *aborted = data->aborted;
643 
644   if (choice_out)
645     *choice_out = data->choice;
646 
647   return data != &def;
648 }
649 
650 static void
op_ask_question_reply(GObject * source_object,GAsyncResult * res,gpointer user_data)651 op_ask_question_reply (GObject      *source_object,
652                        GAsyncResult *res,
653                        gpointer      user_data)
654 {
655   GMountOperationResult result;
656   GMountOperation *op;
657   GMountSource *source;
658   gboolean handled, aborted;
659   gint choice;
660 
661   source = G_MOUNT_SOURCE (source_object);
662   op = G_MOUNT_OPERATION (user_data);
663 
664   handled = g_mount_source_ask_question_finish (source,
665                                                 res,
666                                                 &aborted,
667 						&choice);
668 
669   if (!handled)
670     result = G_MOUNT_OPERATION_UNHANDLED;
671   else if (aborted)
672     result = G_MOUNT_OPERATION_ABORTED;
673   else
674     {
675       result = G_MOUNT_OPERATION_HANDLED;
676       g_mount_operation_set_choice (op, choice);
677     }
678 
679   g_mount_operation_reply (op, result);
680   g_object_unref (op);
681 }
682 
683 static gboolean
op_ask_question(GMountOperation * op,const char * message,const char ** choices,GMountSource * mount_source)684 op_ask_question (GMountOperation *op,
685 		 const char      *message,
686 		 const char     **choices,
687 		 GMountSource    *mount_source)
688 {
689   g_mount_source_ask_question_async (mount_source,
690 				     message,
691 				     choices,
692 				     op_ask_question_reply,
693 				     g_object_ref (op));
694   g_signal_stop_emission_by_name (op, "ask_question");
695   return TRUE;
696 }
697 
698 typedef struct ShowProcessesData ShowProcessesData;
699 
700 struct ShowProcessesData {
701 
702   /* results: */
703   gboolean aborted;
704   guint32  choice;
705 };
706 
707 /* the callback from dbus -> main thread */
708 static void
show_processes_reply(GVfsDBusMountOperation * proxy,GAsyncResult * res,gpointer user_data)709 show_processes_reply (GVfsDBusMountOperation *proxy,
710                       GAsyncResult *res,
711                       gpointer user_data)
712 {
713   GTask *task;
714   ShowProcessesData *data;
715   gboolean handled, aborted;
716   guint32 choice;
717   GError *error;
718 
719   task = G_TASK (user_data);
720   handled = TRUE;
721 
722   error = NULL;
723   if (!gvfs_dbus_mount_operation_call_show_processes_finish (proxy,
724                                                              &handled,
725                                                              &aborted,
726                                                              &choice,
727                                                              res,
728                                                              &error))
729     {
730       g_dbus_error_strip_remote_error (error);
731       g_task_return_error (task, error);
732     }
733   else if (handled == FALSE)
734     {
735       g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Internal Error");
736     }
737   else
738     {
739       data = g_new0 (ShowProcessesData, 1);
740       data->aborted = aborted;
741       data->choice = choice;
742 
743       g_task_return_pointer (task, data, g_free);
744     }
745 
746   g_object_unref (task);
747 }
748 
749 void
g_mount_source_show_processes_async(GMountSource * source,const char * message_string,GArray * processes,const char ** choices,GAsyncReadyCallback callback,gpointer user_data)750 g_mount_source_show_processes_async (GMountSource        *source,
751                                      const char          *message_string,
752                                      GArray              *processes,
753                                      const char         **choices,
754                                      GAsyncReadyCallback  callback,
755                                      gpointer             user_data)
756 {
757   GTask *task;
758   GVfsDBusMountOperation *proxy;
759   GVariantBuilder builder;
760   guint i;
761   GError *error = NULL;
762 
763   task = g_task_new (source, NULL, callback, user_data);
764   g_task_set_source_tag (task, g_mount_source_show_processes_async);
765 
766   proxy = create_mount_operation_proxy_sync (source, &error);
767   if (proxy == NULL)
768     {
769       g_task_return_error (task, error);
770       g_object_unref (task);
771       return;
772     }
773 
774   /* 30 minute timeout */
775   g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (proxy), G_VFS_DBUS_MOUNT_TIMEOUT_MSECS);
776 
777   g_variant_builder_init (&builder, G_VARIANT_TYPE ("ai"));
778   for (i = 0; i < processes->len; i++)
779     g_variant_builder_add (&builder, "i",
780                            g_array_index (processes, gint32, i));
781 
782   gvfs_dbus_mount_operation_call_show_processes (proxy,
783                                                  message_string ? message_string : "",
784                                                  choices,
785                                                  g_variant_builder_end (&builder),
786                                                  NULL,
787                                                  (GAsyncReadyCallback) show_processes_reply,
788                                                  task);
789   g_object_unref (proxy);
790 }
791 
792 gboolean
g_mount_source_show_processes_finish(GMountSource * source,GAsyncResult * result,gboolean * aborted,gint * choice_out)793 g_mount_source_show_processes_finish (GMountSource *source,
794                                       GAsyncResult *result,
795                                       gboolean     *aborted,
796                                       gint         *choice_out)
797 {
798   ShowProcessesData *data, def = { TRUE, };
799 
800   g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
801   g_return_val_if_fail (g_async_result_is_tagged (result, g_mount_source_show_processes_async), FALSE);
802 
803   data = g_task_propagate_pointer (G_TASK (result), NULL);
804   if (data == NULL)
805     data = &def;
806 
807   if (aborted)
808     *aborted = data->aborted;
809 
810   if (choice_out)
811     *choice_out = data->choice;
812 
813   return data != &def;
814 }
815 
816 gboolean
g_mount_source_show_processes(GMountSource * source,const char * message,GArray * processes,const char ** choices,gboolean * aborted_out,gint * choice_out)817 g_mount_source_show_processes (GMountSource *source,
818                                const char   *message,
819                                GArray       *processes,
820                                const char  **choices,
821                                gboolean     *aborted_out,
822                                gint         *choice_out)
823 {
824   gint choice;
825   gboolean handled, aborted;
826   AskSyncData data;
827 
828   data.context = g_main_context_new ();
829   data.loop = g_main_loop_new (data.context, FALSE);
830 
831   g_main_context_push_thread_default (data.context);
832 
833   g_mount_source_show_processes_async (source,
834                                        message,
835                                        processes,
836                                        choices,
837                                        ask_reply_sync,
838                                        &data);
839 
840   g_main_loop_run (data.loop);
841 
842   handled = g_mount_source_show_processes_finish (source,
843                                                   data.result,
844                                                   &aborted,
845                                                   &choice);
846 
847   g_main_context_pop_thread_default (data.context);
848   g_main_context_unref (data.context);
849   g_main_loop_unref (data.loop);
850   g_object_unref (data.result);
851 
852   if (aborted_out)
853     *aborted_out = aborted;
854 
855   if (choice_out)
856     *choice_out = choice;
857 
858   return handled;
859 }
860 
861 static void
op_show_processes_reply(GObject * source_object,GAsyncResult * res,gpointer user_data)862 op_show_processes_reply (GObject      *source_object,
863                          GAsyncResult *res,
864                          gpointer      user_data)
865 {
866   GMountOperationResult result;
867   GMountOperation *op;
868   GMountSource *source;
869   gboolean handled, aborted;
870   gint choice;
871 
872   source = G_MOUNT_SOURCE (source_object);
873   op = G_MOUNT_OPERATION (user_data);
874 
875   handled = g_mount_source_show_processes_finish (source,
876                                                   res,
877                                                   &aborted,
878                                                   &choice);
879 
880   if (!handled)
881     result = G_MOUNT_OPERATION_UNHANDLED;
882   else if (aborted)
883     result = G_MOUNT_OPERATION_ABORTED;
884   else
885     {
886       result = G_MOUNT_OPERATION_HANDLED;
887       g_mount_operation_set_choice (op, choice);
888     }
889 
890   g_mount_operation_reply (op, result);
891   g_object_unref (op);
892 }
893 
894 static gboolean
op_show_processes(GMountOperation * op,const char * message,GArray * processes,const char ** choices,GMountSource * mount_source)895 op_show_processes (GMountOperation *op,
896                    const char      *message,
897                    GArray          *processes,
898                    const char     **choices,
899                    GMountSource    *mount_source)
900 {
901   g_mount_source_show_processes_async (mount_source,
902                                        message,
903                                        processes,
904                                        choices,
905                                        op_show_processes_reply,
906                                        g_object_ref (op));
907   g_signal_stop_emission_by_name (op, "show_processes");
908   return TRUE;
909 }
910 
911 static void
show_unmount_progress_reply(GVfsDBusMountOperation * proxy,GAsyncResult * res,gpointer user_data)912 show_unmount_progress_reply (GVfsDBusMountOperation *proxy,
913                              GAsyncResult *res,
914                              gpointer user_data)
915 {
916   GError *error;
917 
918   error = NULL;
919   if (!gvfs_dbus_mount_operation_call_show_unmount_progress_finish (proxy, res, &error))
920     {
921       g_warning ("ShowUnmountProgress request failed: %s", error->message);
922       g_error_free (error);
923     }
924 }
925 
926 void
g_mount_source_show_unmount_progress(GMountSource * source,const char * message_string,gint64 time_left,gint64 bytes_left)927 g_mount_source_show_unmount_progress (GMountSource *source,
928                                       const char   *message_string,
929                                       gint64      time_left,
930                                       gint64      bytes_left)
931 {
932   GVfsDBusMountOperation *proxy;
933 
934   /* If no dbus id specified, warn and return */
935   if (source->dbus_id[0] == 0)
936     {
937       g_warning ("No dbus id specified in the mount source, "
938                  "ignoring show-unmount-progress request");
939       return;
940     }
941 
942   proxy = create_mount_operation_proxy_sync (source, NULL);
943   if (proxy == NULL)
944     return;
945 
946   /* 30 minute timeout */
947   g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (proxy), G_VFS_DBUS_MOUNT_TIMEOUT_MSECS);
948 
949   gvfs_dbus_mount_operation_call_show_unmount_progress (proxy,
950                                                         message_string ? message_string : "",
951                                                         time_left,
952                                                         bytes_left,
953                                                         NULL,
954                                                         (GAsyncReadyCallback) show_unmount_progress_reply,
955                                                         NULL);
956   g_object_unref (proxy);
957 }
958 
959 static void
op_show_unmount_progress(GMountOperation * op,const char * message,gint64 time_left,gint64 bytes_left,GMountSource * mount_source)960 op_show_unmount_progress (GMountOperation *op,
961                           const char      *message,
962                           gint64           time_left,
963                           gint64           bytes_left,
964                           GMountSource    *mount_source)
965 {
966   g_mount_source_show_unmount_progress (mount_source,
967                                         message,
968                                         time_left,
969                                         bytes_left);
970   g_signal_stop_emission_by_name (op, "show_unmount_progress");
971 }
972 
973 static void
abort_reply(GVfsDBusMountOperation * proxy,GAsyncResult * res,gpointer user_data)974 abort_reply (GVfsDBusMountOperation *proxy,
975              GAsyncResult *res,
976              gpointer user_data)
977 {
978   gvfs_dbus_mount_operation_call_aborted_finish (proxy, res, NULL);
979 }
980 
981 gboolean
g_mount_source_abort(GMountSource * source)982 g_mount_source_abort (GMountSource *source)
983 {
984   GVfsDBusMountOperation *proxy;
985 
986   proxy = create_mount_operation_proxy_sync (source, NULL);
987   if (proxy == NULL)
988     return FALSE;
989 
990   gvfs_dbus_mount_operation_call_aborted (proxy, NULL,
991                                           (GAsyncReadyCallback) abort_reply, NULL);
992 
993   g_object_unref (proxy);
994   return TRUE;
995 }
996 
997 static void
op_aborted(GMountOperation * op,GMountSource * source)998 op_aborted (GMountOperation *op,
999 	    GMountSource    *source)
1000 {
1001   g_mount_source_abort (source);
1002 }
1003 
1004 gboolean
g_mount_source_is_dummy(GMountSource * source)1005 g_mount_source_is_dummy (GMountSource *source)
1006 {
1007   g_return_val_if_fail (G_IS_MOUNT_SOURCE (source), TRUE);
1008   return source->dbus_id[0] == 0;
1009 }
1010 
1011 
1012 GMountOperation *
g_mount_source_get_operation(GMountSource * mount_source)1013 g_mount_source_get_operation (GMountSource *mount_source)
1014 {
1015   GMountOperation *op;
1016 
1017   op = g_mount_operation_new ();
1018   g_object_set_data_full (G_OBJECT (op), "source",
1019 			  g_object_ref (mount_source),
1020 			  g_object_unref);
1021 
1022   g_signal_connect (op, "ask_password", (GCallback)op_ask_password, mount_source);
1023   g_signal_connect (op, "ask_question", (GCallback)op_ask_question, mount_source);
1024   g_signal_connect (op, "show_processes", (GCallback)op_show_processes, mount_source);
1025   g_signal_connect (op, "show_unmount_progress", (GCallback)op_show_unmount_progress, mount_source);
1026   g_signal_connect (op, "aborted", (GCallback)op_aborted, mount_source);
1027 
1028   return op;
1029 }
1030