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., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
19 *
20 * Author: Alexander Larsson <alexl@redhat.com>
21 */
22
23#include "config.h"
24
25#include <string.h>
26
27#include "gmountoperation.h"
28#include "gioenumtypes.h"
29#include "gio-marshal.h"
30#include "glibintl.h"
31
32#include "gioalias.h"
33
34/**
35 * SECTION:gmountoperation
36 * @short_description: Authentication methods for mountable locations
37 * @include: gio/gio.h
38 *
39 * #GMountOperation provides a mechanism for authenticating mountable
40 * operations, such as loop mounting files, hard drive partitions or
41 * server locations.
42 *
43 * Mounting operations are handed a #GMountOperation that then can use
44 * if they require any privileges or authentication for their volumes
45 * to be mounted (e.g. a hard disk partition or an encrypted filesystem),
46 * or if they are implementing a remote server protocol which requires
47 * user credentials such as FTP or WebDAV.
48 *
49 * Users should instantiate a subclass of this that implements all
50 * the various callbacks to show the required dialogs, such as
51 * #GtkMountOperation.
52 **/
53
54G_DEFINE_TYPE (GMountOperation, g_mount_operation, G_TYPE_OBJECT);
55
56enum {
57  ASK_PASSWORD,
58  ASK_QUESTION,
59  REPLY,
60  ABORTED,
61  LAST_SIGNAL
62};
63
64static guint signals[LAST_SIGNAL] = { 0 };
65
66struct _GMountOperationPrivate {
67  char *password;
68  char *user;
69  char *domain;
70  gboolean anonymous;
71  GPasswordSave password_save;
72  int choice;
73};
74
75enum {
76  PROP_0,
77  PROP_USERNAME,
78  PROP_PASSWORD,
79  PROP_ANONYMOUS,
80  PROP_DOMAIN,
81  PROP_PASSWORD_SAVE,
82  PROP_CHOICE
83};
84
85static void
86g_mount_operation_set_property (GObject      *object,
87                                guint         prop_id,
88                                const GValue *value,
89                                GParamSpec   *pspec)
90{
91  GMountOperation *operation;
92
93  operation = G_MOUNT_OPERATION (object);
94
95  switch (prop_id)
96    {
97    case PROP_USERNAME:
98      g_mount_operation_set_username (operation,
99                                      g_value_get_string (value));
100      break;
101
102    case PROP_PASSWORD:
103      g_mount_operation_set_password (operation,
104                                      g_value_get_string (value));
105      break;
106
107    case PROP_ANONYMOUS:
108      g_mount_operation_set_anonymous (operation,
109                                       g_value_get_boolean (value));
110      break;
111
112    case PROP_DOMAIN:
113      g_mount_operation_set_domain (operation,
114                                    g_value_get_string (value));
115      break;
116
117    case PROP_PASSWORD_SAVE:
118      g_mount_operation_set_password_save (operation,
119                                           g_value_get_enum (value));
120      break;
121
122    case PROP_CHOICE:
123      g_mount_operation_set_choice (operation,
124                                    g_value_get_int (value));
125      break;
126
127    default:
128      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
129      break;
130    }
131}
132
133
134static void
135g_mount_operation_get_property (GObject    *object,
136                                guint       prop_id,
137                                GValue     *value,
138                                GParamSpec *pspec)
139{
140  GMountOperation *operation;
141  GMountOperationPrivate *priv;
142
143  operation = G_MOUNT_OPERATION (object);
144  priv = operation->priv;
145
146  switch (prop_id)
147    {
148    case PROP_USERNAME:
149      g_value_set_string (value, priv->user);
150      break;
151
152    case PROP_PASSWORD:
153      g_value_set_string (value, priv->password);
154      break;
155
156    case PROP_ANONYMOUS:
157      g_value_set_boolean (value, priv->anonymous);
158      break;
159
160    case PROP_DOMAIN:
161      g_value_set_string (value, priv->domain);
162      break;
163
164    case PROP_PASSWORD_SAVE:
165      g_value_set_enum (value, priv->password_save);
166      break;
167
168    case PROP_CHOICE:
169      g_value_set_int (value, priv->choice);
170      break;
171
172    default:
173      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174      break;
175    }
176}
177
178
179static void
180g_mount_operation_finalize (GObject *object)
181{
182  GMountOperation *operation;
183  GMountOperationPrivate *priv;
184
185  operation = G_MOUNT_OPERATION (object);
186
187  priv = operation->priv;
188
189  g_free (priv->password);
190  g_free (priv->user);
191  g_free (priv->domain);
192
193  G_OBJECT_CLASS (g_mount_operation_parent_class)->finalize (object);
194}
195
196static gboolean
197reply_non_handled_in_idle (gpointer data)
198{
199  GMountOperation *op = data;
200
201  g_mount_operation_reply (op, G_MOUNT_OPERATION_UNHANDLED);
202  return FALSE;
203}
204
205static void
206ask_password (GMountOperation *op,
207	      const char      *message,
208	      const char      *default_user,
209	      const char      *default_domain,
210	      GAskPasswordFlags flags)
211{
212  g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
213		   reply_non_handled_in_idle,
214		   g_object_ref (op),
215		   g_object_unref);
216}
217
218static void
219ask_question (GMountOperation *op,
220	      const char      *message,
221	      const char      *choices[])
222{
223  g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
224		   reply_non_handled_in_idle,
225		   g_object_ref (op),
226		   g_object_unref);
227}
228
229static void
230g_mount_operation_class_init (GMountOperationClass *klass)
231{
232  GObjectClass *object_class;
233
234  g_type_class_add_private (klass, sizeof (GMountOperationPrivate));
235
236  object_class = G_OBJECT_CLASS (klass);
237  object_class->finalize = g_mount_operation_finalize;
238  object_class->get_property = g_mount_operation_get_property;
239  object_class->set_property = g_mount_operation_set_property;
240
241  klass->ask_password = ask_password;
242  klass->ask_question = ask_question;
243
244  /**
245   * GMountOperation::ask-password:
246   * @op: a #GMountOperation requesting a password.
247   * @message: string containing a message to display to the user.
248   * @default_user: string containing the default user name.
249   * @default_domain: string containing the default domain.
250   * @flags: a set of #GAskPasswordFlags.
251   *
252   * Emitted when a mount operation asks the user for a password.
253   *
254   * If the message contains a line break, the first line should be
255   * presented as a heading. For example, it may be used as the
256   * primary text in a #GtkMessageDialog.
257   */
258  signals[ASK_PASSWORD] =
259    g_signal_new (I_("ask-password"),
260		  G_TYPE_FROM_CLASS (object_class),
261		  G_SIGNAL_RUN_LAST,
262		  G_STRUCT_OFFSET (GMountOperationClass, ask_password),
263		  NULL, NULL,
264		  _gio_marshal_VOID__STRING_STRING_STRING_FLAGS,
265		  G_TYPE_NONE, 4,
266		  G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_ASK_PASSWORD_FLAGS);
267
268  /**
269   * GMountOperation::ask-question:
270   * @op: a #GMountOperation asking a question.
271   * @message: string containing a message to display to the user.
272   * @choices: an array of strings for each possible choice.
273   *
274   * Emitted when asking the user a question and gives a list of
275   * choices for the user to choose from.
276   *
277   * If the message contains a line break, the first line should be
278   * presented as a heading. For example, it may be used as the
279   * primary text in a #GtkMessageDialog.
280   */
281  signals[ASK_QUESTION] =
282    g_signal_new (I_("ask-question"),
283		  G_TYPE_FROM_CLASS (object_class),
284		  G_SIGNAL_RUN_LAST,
285		  G_STRUCT_OFFSET (GMountOperationClass, ask_question),
286		  NULL, NULL,
287		  _gio_marshal_VOID__STRING_BOXED,
288		  G_TYPE_NONE, 2,
289		  G_TYPE_STRING, G_TYPE_STRV);
290
291  /**
292   * GMountOperation::reply:
293   * @op: a #GMountOperation.
294   * @result: a #GMountOperationResult indicating how the request was handled
295   *
296   * Emitted when the user has replied to the mount operation.
297   */
298  signals[REPLY] =
299    g_signal_new (I_("reply"),
300		  G_TYPE_FROM_CLASS (object_class),
301		  G_SIGNAL_RUN_LAST,
302		  G_STRUCT_OFFSET (GMountOperationClass, reply),
303		  NULL, NULL,
304		  g_cclosure_marshal_VOID__ENUM,
305		  G_TYPE_NONE, 1,
306		  G_TYPE_MOUNT_OPERATION_RESULT);
307
308  /**
309   * GMountOperation::aborted:
310   *
311   * Emitted by the backend when e.g. a device becomes unavailable
312   * while a mount operation is in progress.
313   *
314   * Implementations of GMountOperation should handle this signal
315   * by dismissing open password dialogs.
316   *
317   * Since: 2.20
318   */
319  signals[ABORTED] =
320    g_signal_new (I_("aborted"),
321		  G_TYPE_FROM_CLASS (object_class),
322		  G_SIGNAL_RUN_LAST,
323		  G_STRUCT_OFFSET (GMountOperationClass, aborted),
324		  NULL, NULL,
325		  g_cclosure_marshal_VOID__VOID,
326		  G_TYPE_NONE, 0);
327
328  /**
329   * GMountOperation:username:
330   *
331   * The user name that is used for authentication when carrying out
332   * the mount operation.
333   */
334  g_object_class_install_property (object_class,
335                                   PROP_USERNAME,
336                                   g_param_spec_string ("username",
337                                                        P_("Username"),
338                                                        P_("The user name"),
339                                                        NULL,
340                                                        G_PARAM_READWRITE|
341                                                        G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
342
343  /**
344   * GMountOperation:password:
345   *
346   * The password that is used for authentication when carrying out
347   * the mount operation.
348   */
349  g_object_class_install_property (object_class,
350                                   PROP_PASSWORD,
351                                   g_param_spec_string ("password",
352                                                        P_("Password"),
353                                                        P_("The password"),
354                                                        NULL,
355                                                        G_PARAM_READWRITE|
356                                                        G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
357
358  /**
359   * GMountOperation:anonymous:
360   *
361   * Whether to use an anonymous user when authenticating.
362   */
363  g_object_class_install_property (object_class,
364                                   PROP_ANONYMOUS,
365                                   g_param_spec_boolean ("anonymous",
366                                                         P_("Anonymous"),
367                                                         P_("Whether to use an anonymous user"),
368                                                         FALSE,
369                                                         G_PARAM_READWRITE|
370                                                         G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
371
372  /**
373   * GMountOperation:domain:
374   *
375   * The domain to use for the mount operation.
376   */
377  g_object_class_install_property (object_class,
378                                   PROP_DOMAIN,
379                                   g_param_spec_string ("domain",
380                                                        P_("Domain"),
381                                                        P_("The domain of the mount operation"),
382                                                        NULL,
383                                                        G_PARAM_READWRITE|
384                                                        G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
385
386  /**
387   * GMountOperation:password-save:
388   *
389   * Determines if and how the password information should be saved.
390   */
391  g_object_class_install_property (object_class,
392                                   PROP_PASSWORD_SAVE,
393                                   g_param_spec_enum ("password-save",
394                                                      P_("Password save"),
395                                                      P_("How passwords should be saved"),
396                                                      G_TYPE_PASSWORD_SAVE,
397                                                      G_PASSWORD_SAVE_NEVER,
398                                                      G_PARAM_READWRITE|
399                                                      G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
400
401  /**
402   * GMountOperation:choice:
403   *
404   * The index of the user's choice when a question is asked during the
405   * mount operation. See the #GMountOperation::ask-question signal.
406   */
407  g_object_class_install_property (object_class,
408                                   PROP_CHOICE,
409                                   g_param_spec_int ("choice",
410                                                     P_("Choice"),
411                                                     P_("The users choice"),
412                                                     0, G_MAXINT, 0,
413                                                     G_PARAM_READWRITE|
414                                                     G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
415}
416
417static void
418g_mount_operation_init (GMountOperation *operation)
419{
420  operation->priv = G_TYPE_INSTANCE_GET_PRIVATE (operation,
421						 G_TYPE_MOUNT_OPERATION,
422						 GMountOperationPrivate);
423}
424
425/**
426 * g_mount_operation_new:
427 *
428 * Creates a new mount operation.
429 *
430 * Returns: a #GMountOperation.
431 **/
432GMountOperation *
433g_mount_operation_new (void)
434{
435  return g_object_new (G_TYPE_MOUNT_OPERATION, NULL);
436}
437
438/**
439 * g_mount_operation_get_username
440 * @op: a #GMountOperation.
441 *
442 * Get the user name from the mount operation.
443 *
444 * Returns: a string containing the user name.
445 **/
446const char *
447g_mount_operation_get_username (GMountOperation *op)
448{
449  g_return_val_if_fail (G_IS_MOUNT_OPERATION (op), NULL);
450  return op->priv->user;
451}
452
453/**
454 * g_mount_operation_set_username:
455 * @op: a #GMountOperation.
456 * @username: input username.
457 *
458 * Sets the user name within @op to @username.
459 **/
460void
461g_mount_operation_set_username (GMountOperation *op,
462				const char      *username)
463{
464  g_return_if_fail (G_IS_MOUNT_OPERATION (op));
465  g_free (op->priv->user);
466  op->priv->user = g_strdup (username);
467  g_object_notify (G_OBJECT (op), "username");
468}
469
470/**
471 * g_mount_operation_get_password:
472 * @op: a #GMountOperation.
473 *
474 * Gets a password from the mount operation.
475 *
476 * Returns: a string containing the password within @op.
477 **/
478const char *
479g_mount_operation_get_password (GMountOperation *op)
480{
481  g_return_val_if_fail (G_IS_MOUNT_OPERATION (op), NULL);
482  return op->priv->password;
483}
484
485/**
486 * g_mount_operation_set_password:
487 * @op: a #GMountOperation.
488 * @password: password to set.
489 *
490 * Sets the mount operation's password to @password.
491 *
492 **/
493void
494g_mount_operation_set_password (GMountOperation *op,
495				const char      *password)
496{
497  g_return_if_fail (G_IS_MOUNT_OPERATION (op));
498  g_free (op->priv->password);
499  op->priv->password = g_strdup (password);
500  g_object_notify (G_OBJECT (op), "password");
501}
502
503/**
504 * g_mount_operation_get_anonymous:
505 * @op: a #GMountOperation.
506 *
507 * Check to see whether the mount operation is being used
508 * for an anonymous user.
509 *
510 * Returns: %TRUE if mount operation is anonymous.
511 **/
512gboolean
513g_mount_operation_get_anonymous (GMountOperation *op)
514{
515  g_return_val_if_fail (G_IS_MOUNT_OPERATION (op), FALSE);
516  return op->priv->anonymous;
517}
518
519/**
520 * g_mount_operation_set_anonymous:
521 * @op: a #GMountOperation.
522 * @anonymous: boolean value.
523 *
524 * Sets the mount operation to use an anonymous user if @anonymous is %TRUE.
525 **/
526void
527g_mount_operation_set_anonymous (GMountOperation *op,
528				 gboolean         anonymous)
529{
530  GMountOperationPrivate *priv;
531  g_return_if_fail (G_IS_MOUNT_OPERATION (op));
532  priv = op->priv;
533
534  if (priv->anonymous != anonymous)
535    {
536      priv->anonymous = anonymous;
537      g_object_notify (G_OBJECT (op), "anonymous");
538    }
539}
540
541/**
542 * g_mount_operation_get_domain:
543 * @op: a #GMountOperation.
544 *
545 * Gets the domain of the mount operation.
546 *
547 * Returns: a string set to the domain.
548 **/
549const char *
550g_mount_operation_get_domain (GMountOperation *op)
551{
552  g_return_val_if_fail (G_IS_MOUNT_OPERATION (op), NULL);
553  return op->priv->domain;
554}
555
556/**
557 * g_mount_operation_set_domain:
558 * @op: a #GMountOperation.
559 * @domain: the domain to set.
560 *
561 * Sets the mount operation's domain.
562 **/
563void
564g_mount_operation_set_domain (GMountOperation *op,
565			      const char      *domain)
566{
567  g_return_if_fail (G_IS_MOUNT_OPERATION (op));
568  g_free (op->priv->domain);
569  op->priv->domain = g_strdup (domain);
570  g_object_notify (G_OBJECT (op), "domain");
571}
572
573/**
574 * g_mount_operation_get_password_save:
575 * @op: a #GMountOperation.
576 *
577 * Gets the state of saving passwords for the mount operation.
578 *
579 * Returns: a #GPasswordSave flag.
580 **/
581
582GPasswordSave
583g_mount_operation_get_password_save (GMountOperation *op)
584{
585  g_return_val_if_fail (G_IS_MOUNT_OPERATION (op), G_PASSWORD_SAVE_NEVER);
586  return op->priv->password_save;
587}
588
589/**
590 * g_mount_operation_set_password_save:
591 * @op: a #GMountOperation.
592 * @save: a set of #GPasswordSave flags.
593 *
594 * Sets the state of saving passwords for the mount operation.
595 *
596 **/
597void
598g_mount_operation_set_password_save (GMountOperation *op,
599				     GPasswordSave    save)
600{
601  GMountOperationPrivate *priv;
602  g_return_if_fail (G_IS_MOUNT_OPERATION (op));
603  priv = op->priv;
604
605  if (priv->password_save != save)
606    {
607      priv->password_save = save;
608      g_object_notify (G_OBJECT (op), "password-save");
609    }
610}
611
612/**
613 * g_mount_operation_get_choice:
614 * @op: a #GMountOperation.
615 *
616 * Gets a choice from the mount operation.
617 *
618 * Returns: an integer containing an index of the user's choice from
619 * the choice's list, or %0.
620 **/
621int
622g_mount_operation_get_choice (GMountOperation *op)
623{
624  g_return_val_if_fail (G_IS_MOUNT_OPERATION (op), 0);
625  return op->priv->choice;
626}
627
628/**
629 * g_mount_operation_set_choice:
630 * @op: a #GMountOperation.
631 * @choice: an integer.
632 *
633 * Sets a default choice for the mount operation.
634 **/
635void
636g_mount_operation_set_choice (GMountOperation *op,
637			      int              choice)
638{
639  GMountOperationPrivate *priv;
640  g_return_if_fail (G_IS_MOUNT_OPERATION (op));
641  priv = op->priv;
642  if (priv->choice != choice)
643    {
644      priv->choice = choice;
645      g_object_notify (G_OBJECT (op), "choice");
646    }
647}
648
649/**
650 * g_mount_operation_reply:
651 * @op: a #GMountOperation
652 * @result: a #GMountOperationResult
653 *
654 * Emits the #GMountOperation::reply signal.
655 **/
656void
657g_mount_operation_reply (GMountOperation *op,
658			 GMountOperationResult result)
659{
660  g_return_if_fail (G_IS_MOUNT_OPERATION (op));
661  g_signal_emit (op, signals[REPLY], 0, result);
662}
663
664#define __G_MOUNT_OPERATION_C__
665#include "gioaliasdef.c"
666