Index: thunar-volman/tvm-prompt.c =================================================================== --- thunar-volman/tvm-prompt.c (revision 4898) +++ thunar-volman/tvm-prompt.c (working copy) @@ -170,4 +170,178 @@ return response; } +static void +tvm_prompt_update_text (GtkEditable *editable, + gchar *new_text, + gint new_text_len, + gint *position, + gpointer data) +{ + gchar **response = (gchar **)data; + if (response == NULL) + return; + g_free(*response); + *response = gtk_editable_get_chars(editable, 0, -1); +} +typedef struct _TvmDialogValidate { + GtkWidget *dialog; + gint response; +} TvmDialogValidate; + +void +tvm_prompt_validate_text (GtkEntry *entry, + gpointer data) +{ + TvmDialogValidate *validate_data = (TvmDialogValidate *)data; + gtk_dialog_response(GTK_DIALOG(validate_data->dialog), validate_data->response); +} + +/** + * tvm_prompt_text: + * @context : a #LibHalContext. + * @udi : the UDI of the device being added, which is watched for removal. + * @icon : the icon or %NULL. + * @title : the prompt title. + * @response_text : the response text. + * @visible : whether text typed should be visible. + * @default_response : Which response to return on Enter. + * @primary_text : the primary prompt text. + * @secondary_text : the secondary prompt text. + * @first_button_text : the first button text. + * @... : %NULL-terminated list of button text, response id pairs. + * + * Return value: the selected response. + **/ +gint +tvm_prompt_text (LibHalContext *context, + const gchar *udi, + const gchar *icon, + const gchar *title, + gchar **response_text, + gboolean visible, + gint default_response, + const gchar *primary_text, + const gchar *secondary_text, + const gchar *first_button_text, + ...) +{ + GtkWidget *dialog; + GtkWidget *image; + GtkWidget *label; + GtkWidget *hbox; + GtkWidget *vbox; + GtkWidget *entry; + DBusError derror; + va_list args; + gint response; + TvmDialogValidate validate_data; + + g_return_val_if_fail (exo_hal_udi_validate (udi, -1, NULL), GTK_RESPONSE_CANCEL); + g_return_val_if_fail (context != NULL, GTK_RESPONSE_CANCEL); + + /* allocate a new dialog */ + dialog = gtk_dialog_new (); + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + g_object_set_data_full (G_OBJECT (dialog), "udi", g_strdup (udi), g_free); + gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), 6); + gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 12); + + /* setup the specified title */ + if (G_LIKELY (title != NULL)) + gtk_window_set_title (GTK_WINDOW (dialog), title); + + /* setup the specified buttons */ + if (G_LIKELY (first_button_text != NULL)) + { + va_start (args, first_button_text); + for (response = va_arg (args, gint); first_button_text != NULL; ) + { + /* insert the button */ + gtk_dialog_add_button (GTK_DIALOG (dialog), first_button_text, response); + first_button_text = va_arg (args, const gchar *); + if (G_UNLIKELY (first_button_text == NULL)) + break; + response = va_arg (args, gint); + } + va_end (args); + } + + /* setup the hbox */ + hbox = gtk_hbox_new (FALSE, 12); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 12); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox, TRUE, TRUE, 0); + gtk_widget_show (hbox); + + /* setup the specified icon */ + if (G_LIKELY (icon != NULL)) + { + /* setup an image for the icon */ + image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_DIALOG); + gtk_misc_set_alignment (GTK_MISC (image), 0.0f, 0.0f); + gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); + gtk_widget_show (image); + } + + /* setup the vbox */ + vbox = gtk_vbox_new (FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + gtk_widget_show (vbox); + + /* setup the primary text */ + label = gtk_label_new (primary_text); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f); + gtk_label_set_attributes (GTK_LABEL (label), tvm_pango_attr_list_big_bold ()); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + + /* setup the secondary text */ + if (G_LIKELY (secondary_text != NULL)) + { + label = gtk_label_new (secondary_text); + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_misc_set_alignment (GTK_MISC (label), 0.0f, 0.5f); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + gtk_widget_show (label); + } + + entry = gtk_entry_new(); + gtk_entry_set_visibility(GTK_ENTRY(entry), visible); + gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); + gtk_widget_show (entry); + + /* initialize D-Bus error */ + dbus_error_init (&derror); + + /* setup HAL to watch the UDI for removal */ + libhal_ctx_set_user_data (context, dialog); + libhal_ctx_set_device_removed (context, hal_device_removed); + libhal_device_property_watch_all (context, &derror); + + /* setup handler for the entered text */ + if (response_text) + *response_text = NULL; + g_signal_connect_after(G_OBJECT(entry), "insert-text", + G_CALLBACK(tvm_prompt_update_text), + (gpointer) response_text); + validate_data.dialog = dialog; + validate_data.response = default_response; + g_signal_connect(G_OBJECT(entry), "activate", + G_CALLBACK(tvm_prompt_validate_text), + (gpointer) &validate_data); + + /* run the dialog */ + response = gtk_dialog_run (GTK_DIALOG (dialog)); + + /* cleanup */ + libhal_ctx_set_device_removed (context, NULL); + libhal_ctx_set_user_data (context, NULL); + gtk_widget_destroy (dialog); + dbus_error_free (&derror); + + return response; +} + + Index: thunar-volman/tvm-prompt.h =================================================================== --- thunar-volman/tvm-prompt.h (revision 4898) +++ thunar-volman/tvm-prompt.h (working copy) @@ -46,6 +46,18 @@ const gchar *first_button_text, ...) G_GNUC_INTERNAL G_GNUC_NULL_TERMINATED; +gint tvm_prompt_text (LibHalContext *context, + const gchar *udi, + const gchar *icon, + const gchar *title, + gchar **response_text, + gboolean visible, + gint default_response, + const gchar *primary_text, + const gchar *secondary_text, + const gchar *first_button_text, + ...) G_GNUC_INTERNAL G_GNUC_NULL_TERMINATED; + G_END_DECLS; #endif /* !__TVM_PROMPT_H__ */ Index: thunar-volman/tvm-block-device.c =================================================================== --- thunar-volman/tvm-block-device.c (revision 4898) +++ thunar-volman/tvm-block-device.c (working copy) @@ -39,6 +39,8 @@ #include #endif +#include + #include #include @@ -580,8 +582,108 @@ return result; } +static gboolean +tvm_install_crypto_volume (const gchar *udi, + LibHalVolume *volume, + const gchar *password, + gboolean *pass_error) +{ + gboolean r = FALSE; + DBusMessage *msg = NULL, *reply = NULL; + DBusError err; + DBusConnection *dbus_connection = NULL; + *pass_error = FALSE; + msg = dbus_message_new_method_call ("org.freedesktop.Hal", udi, + "org.freedesktop.Hal.Device.Volume.Crypto", + "Setup"); + if (msg == NULL) { + g_warning ("Could not create dbus message for %s", udi); + goto out; + } + if (!dbus_message_append_args (msg, + DBUS_TYPE_STRING, &password, + DBUS_TYPE_INVALID)) { + g_warning ("Could not append args to dbus message for %s", udi); + goto out; + } + + dbus_error_init (&err); + dbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &err); + if (!dbus_connection) { + if (dbus_error_is_set (&err)) + g_message ("Dbus connection failed for %s: %s : %s\n", udi, err.name, err.message); + goto out; + } + if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, msg, 20000, &err)) || + dbus_error_is_set (&err)) { + g_message ("Setup failed for %s: %s : %s\n", udi, err.name, err.message); + if (strcmp (err.name, "org.freedesktop.Hal.Device.Volume.Crypto.SetupPasswordError") == 0) { + *pass_error = TRUE; + } + dbus_error_free (&err); + goto out; + } + + + r = TRUE; + +out: + if (msg != NULL) + dbus_message_unref (msg); + if (reply != NULL) + dbus_message_unref (reply); + + return r; +} + +static gboolean +tvm_setup_crypto_volume (LibHalContext *context, + const gchar *udi) +{ + gchar *password = NULL; + gboolean pass_error = TRUE, success = FALSE; + gint num_tries = 0; + gchar *plain_udi = NULL; + LibHalVolume *volume = NULL; + + volume = libhal_volume_from_udi (context, udi); + g_return_val_if_fail(volume != NULL, FALSE); + plain_udi = libhal_volume_crypto_get_clear_volume_udi (context, volume); + if (plain_udi != NULL) { + printf("cryptodev already setup\n"); + g_free(plain_udi); + libhal_volume_free(volume); + return FALSE; + } + + for (num_tries = 0; pass_error == TRUE && num_tries < 3; num_tries++) { + gint response,len; + response = tvm_prompt_text (context, udi, "gtk-dialog-authentication", _("Encrypted volume"), + &password, FALSE, + TVM_RESPONSE_BROWSE, + _("This volume is encrypted."), + _("Please enter your password to decrypt and mount the volume."), + _("Ig_nore"), GTK_RESPONSE_CANCEL, + _("_Mount"), TVM_RESPONSE_BROWSE, + NULL); + if (response == GTK_RESPONSE_CANCEL) { + success = TRUE; + goto bail; + } + success = tvm_install_crypto_volume(udi, volume, password, &pass_error); +bail: + len = strlen(password); + memset(password, 0, len); + g_debug("zeroed password %p", password); + g_free(password); + if (success) + break; + } + return FALSE; +} + /** * tvm_block_device_added: * @preferences : a #TvmPreferences. @@ -752,6 +854,14 @@ /* make sure the volume has a mountable filesystem */ fsusage = libhal_device_get_property_string (context, udi, "volume.fsusage", NULL); has_filesystem = (G_LIKELY (fsusage && strcmp (fsusage, "filesystem") == 0)); + if (!has_filesystem) { + gboolean has_crypto = (G_LIKELY (fsusage && strcmp (fsusage, "crypto") == 0)); + if (has_crypto) { + libhal_free_string (fsusage); + tvm_setup_crypto_volume(context, udi); + return FALSE; + } + } libhal_free_string (fsusage); if (G_UNLIKELY (!has_filesystem)) return FALSE;