Blame SOURCES/compress-dialog-Add-support-for-encrypted-.zip.patch

f41b08
From 98c79d46ab05bd86fc1309d9ae560edc19f62071 Mon Sep 17 00:00:00 2001
f41b08
From: Ondrej Holy <oholy@redhat.com>
f41b08
Date: Fri, 30 Jul 2021 10:52:55 +0200
f41b08
Subject: [PATCH] compress-dialog: Add support for encrypted .zip
f41b08
f41b08
Currently, it is not possible to create encrypted archives over
f41b08
Nautilus. Let's add support for encrypted .zip files to not have
f41b08
to install a dedicated archive manager.
f41b08
f41b08
Fixes: https://gitlab.gnome.org/GNOME/nautilus/-/issues/822
f41b08
---
f41b08
 data/org.gnome.nautilus.gschema.xml          |   1 +
f41b08
 meson.build                                  |   2 +-
f41b08
 src/nautilus-compress-dialog-controller.c    | 136 +++++++++++++++++++
f41b08
 src/nautilus-compress-dialog-controller.h    |   1 +
f41b08
 src/nautilus-file-operations.c               |   8 +-
f41b08
 src/nautilus-file-operations.h               |   1 +
f41b08
 src/nautilus-file-undo-operations.c          |   7 +-
f41b08
 src/nautilus-file-undo-operations.h          |   3 +-
f41b08
 src/nautilus-files-view.c                    |  10 ++
f41b08
 src/nautilus-global-preferences.h            |   3 +-
f41b08
 src/resources/css/nautilus.css               |   9 ++
f41b08
 src/resources/ui/nautilus-compress-dialog.ui |  57 ++++++++
f41b08
 12 files changed, 233 insertions(+), 5 deletions(-)
f41b08
f41b08
diff --git a/data/org.gnome.nautilus.gschema.xml b/data/org.gnome.nautilus.gschema.xml
f41b08
index 3f89466de..7585be8cd 100644
f41b08
--- a/data/org.gnome.nautilus.gschema.xml
f41b08
+++ b/data/org.gnome.nautilus.gschema.xml
f41b08
@@ -65,6 +65,7 @@
f41b08
     <value value="0" nick="zip"/>
f41b08
     <value value="1" nick="tar.xz"/>
f41b08
     <value value="2" nick="7z"/>
f41b08
+    <value value="3" nick="encrypted_zip"/>
f41b08
   </enum>
f41b08
 
f41b08
   <schema path="/org/gnome/nautilus/" id="org.gnome.nautilus" gettext-domain="nautilus">
f41b08
diff --git a/meson.build b/meson.build
f41b08
index d5316475d..446b25614 100644
f41b08
--- a/meson.build
f41b08
+++ b/meson.build
f41b08
@@ -117,7 +117,7 @@ gio = dependency('gio-2.0', version: glib_ver)
f41b08
 gio_unix = dependency('gio-unix-2.0', version: glib_ver)
f41b08
 glib = dependency('glib-2.0', version: glib_ver)
f41b08
 gmodule = dependency('gmodule-no-export-2.0', version: glib_ver)
f41b08
-gnome_autoar = dependency('gnome-autoar-0', version: '>= 0.3.0')
f41b08
+gnome_autoar = dependency('gnome-autoar-0', version: '>= 0.4.0')
f41b08
 gnome_desktop = dependency('gnome-desktop-3.0', version: '>= 3.0.0')
f41b08
 gtk = dependency('gtk+-3.0', version: '>= 3.22.27')
f41b08
 libhandy = dependency('libhandy-1', version: '>= 1.1.90')
f41b08
diff --git a/src/nautilus-compress-dialog-controller.c b/src/nautilus-compress-dialog-controller.c
f41b08
index 154573c0f..e1ba5a803 100644
f41b08
--- a/src/nautilus-compress-dialog-controller.c
f41b08
+++ b/src/nautilus-compress-dialog-controller.c
f41b08
@@ -32,17 +32,24 @@ struct _NautilusCompressDialogController
f41b08
     NautilusFileNameWidgetController parent_instance;
f41b08
 
f41b08
     GtkWidget *compress_dialog;
f41b08
+    GtkWidget *activate_button;
f41b08
+    GtkWidget *error_label;
f41b08
     GtkWidget *name_entry;
f41b08
     GtkWidget *extension_stack;
f41b08
     GtkWidget *zip_label;
f41b08
+    GtkWidget *encrypted_zip_label;
f41b08
     GtkWidget *tar_xz_label;
f41b08
     GtkWidget *seven_zip_label;
f41b08
     GtkWidget *extension_popover;
f41b08
     GtkWidget *zip_checkmark;
f41b08
+    GtkWidget *encrypted_zip_checkmark;
f41b08
     GtkWidget *tar_xz_checkmark;
f41b08
     GtkWidget *seven_zip_checkmark;
f41b08
+    GtkWidget *passphrase_label;
f41b08
+    GtkWidget *passphrase_entry;
f41b08
 
f41b08
     const char *extension;
f41b08
+    gchar *passphrase;
f41b08
 
f41b08
     gulong response_handler_id;
f41b08
 };
f41b08
@@ -142,6 +149,7 @@ update_selected_format (NautilusCompressDialogController *self,
f41b08
     const char *extension;
f41b08
     GtkWidget *active_label;
f41b08
     GtkWidget *active_checkmark;
f41b08
+    gboolean show_passphrase = FALSE;
f41b08
 
f41b08
     switch (format)
f41b08
     {
f41b08
@@ -153,6 +161,15 @@ update_selected_format (NautilusCompressDialogController *self,
f41b08
         }
f41b08
         break;
f41b08
 
f41b08
+        case NAUTILUS_COMPRESSION_ENCRYPTED_ZIP:
f41b08
+        {
f41b08
+            extension = ".zip";
f41b08
+            active_label = self->encrypted_zip_label;
f41b08
+            active_checkmark = self->encrypted_zip_checkmark;
f41b08
+            show_passphrase = TRUE;
f41b08
+        }
f41b08
+        break;
f41b08
+
f41b08
         case NAUTILUS_COMPRESSION_TAR_XZ:
f41b08
         {
f41b08
             extension = ".tar.xz";
f41b08
@@ -178,12 +195,26 @@ update_selected_format (NautilusCompressDialogController *self,
f41b08
 
f41b08
     self->extension = extension;
f41b08
 
f41b08
+    gtk_widget_set_visible (self->passphrase_label, show_passphrase);
f41b08
+    gtk_widget_set_visible (self->passphrase_entry, show_passphrase);
f41b08
+    if (!show_passphrase)
f41b08
+    {
f41b08
+        gtk_entry_set_text (GTK_ENTRY (self->passphrase_entry), "");
f41b08
+        gtk_entry_set_visibility (GTK_ENTRY (self->passphrase_entry), FALSE);
f41b08
+        gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->passphrase_entry),
f41b08
+                                           GTK_ENTRY_ICON_SECONDARY,
f41b08
+                                           "view-conceal");
f41b08
+    }
f41b08
+
f41b08
     gtk_stack_set_visible_child (GTK_STACK (self->extension_stack),
f41b08
                                  active_label);
f41b08
 
f41b08
     gtk_image_set_from_icon_name (GTK_IMAGE (self->zip_checkmark),
f41b08
                                   NULL,
f41b08
                                   GTK_ICON_SIZE_BUTTON);
f41b08
+    gtk_image_set_from_icon_name (GTK_IMAGE (self->encrypted_zip_checkmark),
f41b08
+                                  NULL,
f41b08
+                                  GTK_ICON_SIZE_BUTTON);
f41b08
     gtk_image_set_from_icon_name (GTK_IMAGE (self->tar_xz_checkmark),
f41b08
                                   NULL,
f41b08
                                   GTK_ICON_SIZE_BUTTON);
f41b08
@@ -200,6 +231,7 @@ update_selected_format (NautilusCompressDialogController *self,
f41b08
     /* Since the extension changes when the button is toggled, force a
f41b08
      * verification of the new file name by simulating an entry change
f41b08
      */
f41b08
+    gtk_widget_set_sensitive (self->activate_button, FALSE);
f41b08
     g_signal_emit_by_name (self->name_entry, "changed");
f41b08
 }
f41b08
 
f41b08
@@ -216,6 +248,19 @@ zip_row_on_activated (HdyActionRow *row,
f41b08
                             NAUTILUS_COMPRESSION_ZIP);
f41b08
 }
f41b08
 
f41b08
+static void
f41b08
+encrypted_zip_row_on_activated (HdyActionRow *row,
f41b08
+                                gpointer      user_data)
f41b08
+{
f41b08
+    NautilusCompressDialogController *controller;
f41b08
+
f41b08
+    controller = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
f41b08
+
f41b08
+    gtk_popover_popdown (GTK_POPOVER (controller->extension_popover));
f41b08
+    update_selected_format (controller,
f41b08
+                            NAUTILUS_COMPRESSION_ENCRYPTED_ZIP);
f41b08
+}
f41b08
+
f41b08
 static void
f41b08
 tar_xz_row_on_activated (HdyActionRow *row,
f41b08
                          gpointer      user_data)
f41b08
@@ -242,6 +287,67 @@ seven_zip_row_on_activated (HdyActionRow *row,
f41b08
                             NAUTILUS_COMPRESSION_7ZIP);
f41b08
 }
f41b08
 
f41b08
+static void
f41b08
+passphrase_entry_on_changed (GtkEditable *editable,
f41b08
+                             gpointer     user_data)
f41b08
+{
f41b08
+    NautilusCompressDialogController *self;
f41b08
+    const gchar *error_message;
f41b08
+
f41b08
+    self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
f41b08
+
f41b08
+    g_free (self->passphrase);
f41b08
+    self->passphrase = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->passphrase_entry)));
f41b08
+
f41b08
+    /* Simulate a change of the name_entry to ensure the correct sensitivity of
f41b08
+     * the activate_button, but only if the name_entry is valid in order to
f41b08
+     * avoid changes of the error_revealer.
f41b08
+     */
f41b08
+    error_message = gtk_label_get_text (GTK_LABEL (self->error_label));
f41b08
+    if (error_message[0] == '\0')
f41b08
+    {
f41b08
+        gtk_widget_set_sensitive (self->activate_button, FALSE);
f41b08
+        g_signal_emit_by_name (self->name_entry, "changed");
f41b08
+    }
f41b08
+}
f41b08
+
f41b08
+static void
f41b08
+passphrase_entry_on_icon_press (GtkEntry             *entry,
f41b08
+                                GtkEntryIconPosition  icon_pos,
f41b08
+                                GdkEvent             *event,
f41b08
+                                gpointer              user_data)
f41b08
+{
f41b08
+    NautilusCompressDialogController *self;
f41b08
+    gboolean visibility;
f41b08
+
f41b08
+    self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
f41b08
+    visibility = gtk_entry_get_visibility (GTK_ENTRY (self->passphrase_entry));
f41b08
+
f41b08
+    gtk_entry_set_icon_from_icon_name (GTK_ENTRY (self->passphrase_entry),
f41b08
+                                       GTK_ENTRY_ICON_SECONDARY,
f41b08
+                                       visibility ? "view-conceal" : "view-reveal");
f41b08
+    gtk_entry_set_visibility (GTK_ENTRY (self->passphrase_entry), !visibility);
f41b08
+}
f41b08
+
f41b08
+static void
f41b08
+activate_button_on_sensitive_notify (GObject    *gobject,
f41b08
+                                     GParamSpec *pspec,
f41b08
+                                     gpointer    user_data)
f41b08
+{
f41b08
+    NautilusCompressDialogController *self;
f41b08
+    NautilusCompressionFormat format;
f41b08
+
f41b08
+    self = NAUTILUS_COMPRESS_DIALOG_CONTROLLER (user_data);
f41b08
+    format = g_settings_get_enum (nautilus_compression_preferences,
f41b08
+                                  NAUTILUS_PREFERENCES_DEFAULT_COMPRESSION_FORMAT);
f41b08
+    if (format == NAUTILUS_COMPRESSION_ENCRYPTED_ZIP &&
f41b08
+        (self->passphrase == NULL || self->passphrase[0] == '\0'))
f41b08
+    {
f41b08
+        /* Reset sensitivity of the activate_button if password is not set. */
f41b08
+        gtk_widget_set_sensitive (self->activate_button, FALSE);
f41b08
+    }
f41b08
+}
f41b08
+
f41b08
 NautilusCompressDialogController *
f41b08
 nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
f41b08
                                          NautilusDirectory *destination_directory,
f41b08
@@ -256,12 +362,16 @@ nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
f41b08
     GtkWidget *activate_button;
f41b08
     GtkWidget *extension_stack;
f41b08
     GtkWidget *zip_label;
f41b08
+    GtkWidget *encrypted_zip_label;
f41b08
     GtkWidget *tar_xz_label;
f41b08
     GtkWidget *seven_zip_label;
f41b08
     GtkWidget *extension_popover;
f41b08
     GtkWidget *zip_checkmark;
f41b08
+    GtkWidget *encrypted_zip_checkmark;
f41b08
     GtkWidget *tar_xz_checkmark;
f41b08
     GtkWidget *seven_zip_checkmark;
f41b08
+    GtkWidget *passphrase_label;
f41b08
+    GtkWidget *passphrase_entry;
f41b08
     NautilusCompressionFormat format;
f41b08
 
f41b08
     builder = gtk_builder_new_from_resource ("/org/gnome/nautilus/ui/nautilus-compress-dialog.ui");
f41b08
@@ -272,12 +382,16 @@ nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
f41b08
     activate_button = GTK_WIDGET (gtk_builder_get_object (builder, "activate_button"));
f41b08
     extension_stack = GTK_WIDGET (gtk_builder_get_object (builder, "extension_stack"));
f41b08
     zip_label = GTK_WIDGET (gtk_builder_get_object (builder, "zip_label"));
f41b08
+    encrypted_zip_label = GTK_WIDGET (gtk_builder_get_object (builder, "encrypted_zip_label"));
f41b08
     tar_xz_label = GTK_WIDGET (gtk_builder_get_object (builder, "tar_xz_label"));
f41b08
     seven_zip_label = GTK_WIDGET (gtk_builder_get_object (builder, "seven_zip_label"));
f41b08
     extension_popover = GTK_WIDGET (gtk_builder_get_object (builder, "extension_popover"));
f41b08
     zip_checkmark = GTK_WIDGET (gtk_builder_get_object (builder, "zip_checkmark"));
f41b08
+    encrypted_zip_checkmark = GTK_WIDGET (gtk_builder_get_object (builder, "encrypted_zip_checkmark"));
f41b08
     tar_xz_checkmark = GTK_WIDGET (gtk_builder_get_object (builder, "tar_xz_checkmark"));
f41b08
     seven_zip_checkmark = GTK_WIDGET (gtk_builder_get_object (builder, "seven_zip_checkmark"));
f41b08
+    passphrase_label = GTK_WIDGET (gtk_builder_get_object (builder, "passphrase_label"));
f41b08
+    passphrase_entry = GTK_WIDGET (gtk_builder_get_object (builder, "passphrase_entry"));
f41b08
 
f41b08
     gtk_window_set_transient_for (GTK_WINDOW (compress_dialog),
f41b08
                                   parent_window);
f41b08
@@ -290,16 +404,22 @@ nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
f41b08
                          "containing-directory", destination_directory, NULL);
f41b08
 
f41b08
     self->compress_dialog = compress_dialog;
f41b08
+    self->activate_button = activate_button;
f41b08
+    self->error_label = error_label;
f41b08
     self->extension_stack = extension_stack;
f41b08
     self->zip_label = zip_label;
f41b08
+    self->encrypted_zip_label = encrypted_zip_label;
f41b08
     self->tar_xz_label = tar_xz_label;
f41b08
     self->seven_zip_label = seven_zip_label;
f41b08
     self->name_entry = name_entry;
f41b08
     self->extension_popover = extension_popover;
f41b08
     self->zip_checkmark = zip_checkmark;
f41b08
+    self->encrypted_zip_checkmark = encrypted_zip_checkmark;
f41b08
     self->tar_xz_checkmark = tar_xz_checkmark;
f41b08
     self->seven_zip_checkmark = seven_zip_checkmark;
f41b08
     self->name_entry = name_entry;
f41b08
+    self->passphrase_label = passphrase_label;
f41b08
+    self->passphrase_entry = passphrase_entry;
f41b08
 
f41b08
     self->response_handler_id = g_signal_connect (compress_dialog,
f41b08
                                                   "response",
f41b08
@@ -309,10 +429,18 @@ nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
f41b08
     gtk_builder_add_callback_symbols (builder,
f41b08
                                       "zip_row_on_activated",
f41b08
                                       G_CALLBACK (zip_row_on_activated),
f41b08
+                                      "encrypted_zip_row_on_activated",
f41b08
+                                      G_CALLBACK (encrypted_zip_row_on_activated),
f41b08
                                       "tar_xz_row_on_activated",
f41b08
                                       G_CALLBACK (tar_xz_row_on_activated),
f41b08
                                       "seven_zip_row_on_activated",
f41b08
                                       G_CALLBACK (seven_zip_row_on_activated),
f41b08
+                                      "passphrase_entry_on_changed",
f41b08
+                                      G_CALLBACK (passphrase_entry_on_changed),
f41b08
+                                      "passphrase_entry_on_icon_press",
f41b08
+                                      G_CALLBACK (passphrase_entry_on_icon_press),
f41b08
+                                      "activate_button_on_sensitive_notify",
f41b08
+                                      G_CALLBACK (activate_button_on_sensitive_notify),
f41b08
                                       NULL);
f41b08
     gtk_builder_connect_signals (builder, self);
f41b08
 
f41b08
@@ -350,6 +478,8 @@ nautilus_compress_dialog_controller_finalize (GObject *object)
f41b08
         self->compress_dialog = NULL;
f41b08
     }
f41b08
 
f41b08
+    g_free (self->passphrase);
f41b08
+
f41b08
     G_OBJECT_CLASS (nautilus_compress_dialog_controller_parent_class)->finalize (object);
f41b08
 }
f41b08
 
f41b08
@@ -364,3 +494,9 @@ nautilus_compress_dialog_controller_class_init (NautilusCompressDialogController
f41b08
     parent_class->get_new_name = nautilus_compress_dialog_controller_get_new_name;
f41b08
     parent_class->name_is_valid = nautilus_compress_dialog_controller_name_is_valid;
f41b08
 }
f41b08
+
f41b08
+const gchar *
f41b08
+nautilus_compress_dialog_controller_get_passphrase (NautilusCompressDialogController *self)
f41b08
+{
f41b08
+    return self->passphrase;
f41b08
+}
f41b08
diff --git a/src/nautilus-compress-dialog-controller.h b/src/nautilus-compress-dialog-controller.h
f41b08
index 2421b8115..6c96d68fa 100644
f41b08
--- a/src/nautilus-compress-dialog-controller.h
f41b08
+++ b/src/nautilus-compress-dialog-controller.h
f41b08
@@ -31,3 +31,4 @@ G_DECLARE_FINAL_TYPE (NautilusCompressDialogController, nautilus_compress_dialog
f41b08
 NautilusCompressDialogController * nautilus_compress_dialog_controller_new (GtkWindow         *parent_window,
f41b08
                                                                             NautilusDirectory *destination_directory,
f41b08
                                                                             gchar             *initial_name);
f41b08
+const gchar * nautilus_compress_dialog_controller_get_passphrase (NautilusCompressDialogController *controller);
f41b08
diff --git a/src/nautilus-file-operations.c b/src/nautilus-file-operations.c
f41b08
index 59beecd7e..f909173f9 100644
f41b08
--- a/src/nautilus-file-operations.c
f41b08
+++ b/src/nautilus-file-operations.c
f41b08
@@ -222,6 +222,7 @@ typedef struct
f41b08
 
f41b08
     AutoarFormat format;
f41b08
     AutoarFilter filter;
f41b08
+    gchar *passphrase;
f41b08
 
f41b08
     guint64 total_size;
f41b08
     guint total_files;
f41b08
@@ -8753,6 +8754,7 @@ compress_task_done (GObject      *source_object,
f41b08
 
f41b08
     g_object_unref (compress_job->output_file);
f41b08
     g_list_free_full (compress_job->source_files, g_object_unref);
f41b08
+    g_free (compress_job->passphrase);
f41b08
 
f41b08
     finalize_common ((CommonJob *) compress_job);
f41b08
 
f41b08
@@ -9027,6 +9029,7 @@ compress_task_thread_func (GTask        *task,
f41b08
                                         compress_job->format,
f41b08
                                         compress_job->filter,
f41b08
                                         FALSE);
f41b08
+    autoar_compressor_set_passphrase (compressor, compress_job->passphrase);
f41b08
 
f41b08
     autoar_compressor_set_output_is_dest (compressor, TRUE);
f41b08
 
f41b08
@@ -9057,6 +9060,7 @@ nautilus_file_operations_compress (GList                          *files,
f41b08
                                    GFile                          *output,
f41b08
                                    AutoarFormat                    format,
f41b08
                                    AutoarFilter                    filter,
f41b08
+                                   const gchar                    *passphrase,
f41b08
                                    GtkWindow                      *parent_window,
f41b08
                                    NautilusFileOperationsDBusData *dbus_data,
f41b08
                                    NautilusCreateCallback          done_callback,
f41b08
@@ -9072,6 +9076,7 @@ nautilus_file_operations_compress (GList                          *files,
f41b08
     compress_job->output_file = g_object_ref (output);
f41b08
     compress_job->format = format;
f41b08
     compress_job->filter = filter;
f41b08
+    compress_job->passphrase = g_strdup (passphrase);
f41b08
     compress_job->done_callback = done_callback;
f41b08
     compress_job->done_callback_data = done_callback_data;
f41b08
 
f41b08
@@ -9082,7 +9087,8 @@ nautilus_file_operations_compress (GList                          *files,
f41b08
         compress_job->common.undo_info = nautilus_file_undo_info_compress_new (files,
f41b08
                                                                                output,
f41b08
                                                                                format,
f41b08
-                                                                               filter);
f41b08
+                                                                               filter,
f41b08
+                                                                               passphrase);
f41b08
     }
f41b08
 
f41b08
     task = g_task_new (NULL, compress_job->common.cancellable,
f41b08
diff --git a/src/nautilus-file-operations.h b/src/nautilus-file-operations.h
f41b08
index 8236e0e06..14d664f80 100644
f41b08
--- a/src/nautilus-file-operations.h
f41b08
+++ b/src/nautilus-file-operations.h
f41b08
@@ -159,6 +159,7 @@ void nautilus_file_operations_compress (GList                          *files,
f41b08
                                         GFile                          *output,
f41b08
                                         AutoarFormat                    format,
f41b08
                                         AutoarFilter                    filter,
f41b08
+                                        const gchar                    *passphrase,
f41b08
                                         GtkWindow                      *parent_window,
f41b08
                                         NautilusFileOperationsDBusData *dbus_data,
f41b08
                                         NautilusCreateCallback          done_callback,
f41b08
diff --git a/src/nautilus-file-undo-operations.c b/src/nautilus-file-undo-operations.c
f41b08
index a6a3b2025..64f9ce76c 100644
f41b08
--- a/src/nautilus-file-undo-operations.c
f41b08
+++ b/src/nautilus-file-undo-operations.c
f41b08
@@ -2495,6 +2495,7 @@ struct _NautilusFileUndoInfoCompress
f41b08
     GFile *output;
f41b08
     AutoarFormat format;
f41b08
     AutoarFilter filter;
f41b08
+    gchar *passphrase;
f41b08
 };
f41b08
 
f41b08
 G_DEFINE_TYPE (NautilusFileUndoInfoCompress, nautilus_file_undo_info_compress, NAUTILUS_TYPE_FILE_UNDO_INFO)
f41b08
@@ -2562,6 +2563,7 @@ compress_redo_func (NautilusFileUndoInfo           *info,
f41b08
                                        self->output,
f41b08
                                        self->format,
f41b08
                                        self->filter,
f41b08
+                                       self->passphrase,
f41b08
                                        parent_window,
f41b08
                                        dbus_data,
f41b08
                                        compress_callback,
f41b08
@@ -2597,6 +2599,7 @@ nautilus_file_undo_info_compress_finalize (GObject *obj)
f41b08
 
f41b08
     g_list_free_full (self->sources, g_object_unref);
f41b08
     g_clear_object (&self->output);
f41b08
+    g_free (self->passphrase);
f41b08
 
f41b08
     G_OBJECT_CLASS (nautilus_file_undo_info_compress_parent_class)->finalize (obj);
f41b08
 }
f41b08
@@ -2618,7 +2621,8 @@ NautilusFileUndoInfo *
f41b08
 nautilus_file_undo_info_compress_new (GList        *sources,
f41b08
                                       GFile        *output,
f41b08
                                       AutoarFormat  format,
f41b08
-                                      AutoarFilter  filter)
f41b08
+                                      AutoarFilter  filter,
f41b08
+                                      const gchar  *passphrase)
f41b08
 {
f41b08
     NautilusFileUndoInfoCompress *self;
f41b08
 
f41b08
@@ -2631,6 +2635,7 @@ nautilus_file_undo_info_compress_new (GList        *sources,
f41b08
     self->output = g_object_ref (output);
f41b08
     self->format = format;
f41b08
     self->filter = filter;
f41b08
+    self->passphrase = g_strdup (passphrase);
f41b08
 
f41b08
     return NAUTILUS_FILE_UNDO_INFO (self);
f41b08
 }
f41b08
diff --git a/src/nautilus-file-undo-operations.h b/src/nautilus-file-undo-operations.h
f41b08
index f96f2fe69..09ae17cef 100644
f41b08
--- a/src/nautilus-file-undo-operations.h
f41b08
+++ b/src/nautilus-file-undo-operations.h
f41b08
@@ -226,4 +226,5 @@ G_DECLARE_FINAL_TYPE (NautilusFileUndoInfoCompress, nautilus_file_undo_info_comp
f41b08
 NautilusFileUndoInfo * nautilus_file_undo_info_compress_new (GList        *sources,
f41b08
                                                              GFile        *output,
f41b08
                                                              AutoarFormat  format,
f41b08
-                                                             AutoarFilter  filter);
f41b08
+                                                             AutoarFilter  filter,
f41b08
+                                                             const gchar  *passphrase);
f41b08
diff --git a/src/nautilus-files-view.c b/src/nautilus-files-view.c
f41b08
index b4a91226b..47aed3cc1 100644
f41b08
--- a/src/nautilus-files-view.c
f41b08
+++ b/src/nautilus-files-view.c
f41b08
@@ -2235,6 +2235,7 @@ compress_dialog_controller_on_name_accepted (NautilusFileNameWidgetController *c
f41b08
     NautilusFilesViewPrivate *priv;
f41b08
     AutoarFormat format;
f41b08
     AutoarFilter filter;
f41b08
+    const gchar *passphrase = NULL;
f41b08
 
f41b08
     view = NAUTILUS_FILES_VIEW (callback_data->view);
f41b08
     priv = nautilus_files_view_get_instance_private (view);
f41b08
@@ -2280,6 +2281,14 @@ compress_dialog_controller_on_name_accepted (NautilusFileNameWidgetController *c
f41b08
         }
f41b08
         break;
f41b08
 
f41b08
+        case NAUTILUS_COMPRESSION_ENCRYPTED_ZIP:
f41b08
+        {
f41b08
+            format = AUTOAR_FORMAT_ZIP;
f41b08
+            filter = AUTOAR_FILTER_NONE;
f41b08
+            passphrase = nautilus_compress_dialog_controller_get_passphrase (priv->compress_controller);
f41b08
+        }
f41b08
+        break;
f41b08
+
f41b08
         case NAUTILUS_COMPRESSION_TAR_XZ:
f41b08
         {
f41b08
             format = AUTOAR_FORMAT_TAR;
f41b08
@@ -2301,6 +2310,7 @@ compress_dialog_controller_on_name_accepted (NautilusFileNameWidgetController *c
f41b08
     nautilus_file_operations_compress (source_files, output,
f41b08
                                        format,
f41b08
                                        filter,
f41b08
+                                       passphrase,
f41b08
                                        nautilus_files_view_get_containing_window (view),
f41b08
                                        NULL,
f41b08
                                        compress_done,
f41b08
diff --git a/src/nautilus-global-preferences.h b/src/nautilus-global-preferences.h
f41b08
index 8c482f7ce..2e8753b3c 100644
f41b08
--- a/src/nautilus-global-preferences.h
f41b08
+++ b/src/nautilus-global-preferences.h
f41b08
@@ -77,7 +77,8 @@ typedef enum
f41b08
 {
f41b08
         NAUTILUS_COMPRESSION_ZIP = 0,
f41b08
         NAUTILUS_COMPRESSION_TAR_XZ,
f41b08
-        NAUTILUS_COMPRESSION_7ZIP
f41b08
+        NAUTILUS_COMPRESSION_7ZIP,
f41b08
+        NAUTILUS_COMPRESSION_ENCRYPTED_ZIP
f41b08
 } NautilusCompressionFormat;
f41b08
 
f41b08
 /* Icon View */
f41b08
diff --git a/src/resources/css/nautilus.css b/src/resources/css/nautilus.css
f41b08
index 2e46b7abe..ee25a36a8 100644
f41b08
--- a/src/resources/css/nautilus.css
f41b08
+++ b/src/resources/css/nautilus.css
f41b08
@@ -3,3 +3,12 @@
f41b08
     padding-left: 5px;
f41b08
     padding-right: 5px;
f41b08
 }
f41b08
+
f41b08
+label.encrypted_zip,
f41b08
+row.encrypted_zip label.title {
f41b08
+    background-image: -gtk-icontheme('system-lock-screen-symbolic');
f41b08
+    background-position: right center;
f41b08
+    background-repeat: no-repeat;
f41b08
+    background-size: 16px 16px;
f41b08
+    padding-right: 24px;
f41b08
+}
f41b08
diff --git a/src/resources/ui/nautilus-compress-dialog.ui b/src/resources/ui/nautilus-compress-dialog.ui
f41b08
index b36539294..a57765eed 100644
f41b08
--- a/src/resources/ui/nautilus-compress-dialog.ui
f41b08
+++ b/src/resources/ui/nautilus-compress-dialog.ui
f41b08
@@ -28,6 +28,26 @@
f41b08
             </child>
f41b08
           </object>
f41b08
         </child>
f41b08
+        <child>
f41b08
+          <object class="HdyActionRow" id="encrypted_zip_row">
f41b08
+            <property name="visible">True</property>
f41b08
+            <property name="activatable">True</property>
f41b08
+            <property name="title" translatable="no">.zip</property>
f41b08
+            <property name="subtitle" translatable="yes">Password protected .zip, must be installed on Windows and Mac.</property>
f41b08
+            <signal name="activated" handler="encrypted_zip_row_on_activated"/>
f41b08
+            <style>
f41b08
+              <class name="encrypted_zip"/>
f41b08
+            </style>
f41b08
+            <child>
f41b08
+              <object class="GtkImage" id="encrypted_zip_checkmark">
f41b08
+                <property name="visible">True</property>
f41b08
+                <property name="width-request">16</property>
f41b08
+                <property name="margin-start">12</property>
f41b08
+                <property name="margin-end">12</property>
f41b08
+              </object>
f41b08
+            </child>
f41b08
+          </object>
f41b08
+        </child>
f41b08
         <child>
f41b08
           <object class="HdyActionRow">
f41b08
             <property name="visible">True</property>
f41b08
@@ -129,6 +149,15 @@
f41b08
                             <property name="xalign">0</property>
f41b08
                           </object>
f41b08
                         </child>
f41b08
+                        <child>
f41b08
+                          <object class="GtkLabel" id="encrypted_zip_label">
f41b08
+                            <property name="label" translatable="no">.zip</property>
f41b08
+                            <property name="xalign">0</property>
f41b08
+                            <style>
f41b08
+                              <class name="encrypted_zip"/>
f41b08
+                            </style>
f41b08
+                          </object>
f41b08
+                        </child>
f41b08
                         <child>
f41b08
                           <object class="GtkLabel" id="tar_xz_label">
f41b08
                             <property name="label" translatable="no">.tar.xz</property>
f41b08
@@ -179,6 +208,33 @@
f41b08
             <property name="position">3</property>
f41b08
           </packing>
f41b08
         </child>
f41b08
+        <child>
f41b08
+          <object class="GtkLabel" id="passphrase_label">
f41b08
+            <property name="label" translatable="yes">Password</property>
f41b08
+            <property name="margin-top">6</property>
f41b08
+            <property name="xalign">0</property>
f41b08
+          </object>
f41b08
+          <packing>
f41b08
+            <property name="expand">False</property>
f41b08
+            <property name="fill">True</property>
f41b08
+            <property name="position">4</property>
f41b08
+          </packing>
f41b08
+        </child>
f41b08
+        <child>
f41b08
+          <object class="GtkEntry" id="passphrase_entry">
f41b08
+            <property name="placeholder-text" translatable="yes">Enter a password here.</property>
f41b08
+            <property name="input-purpose">password</property>
f41b08
+            <property name="visibility">False</property>
f41b08
+            <property name="secondary-icon-name">view-conceal</property>
f41b08
+            <signal name="changed" handler="passphrase_entry_on_changed"/>
f41b08
+            <signal name="icon-press" handler="passphrase_entry_on_icon_press"/>
f41b08
+          </object>
f41b08
+          <packing>
f41b08
+            <property name="expand">False</property>
f41b08
+            <property name="fill">True</property>
f41b08
+            <property name="position">5</property>
f41b08
+          </packing>
f41b08
+        </child>
f41b08
       </object>
f41b08
     </child>
f41b08
     <child type="action">
f41b08
@@ -197,6 +253,7 @@
f41b08
         <property name="can_default">True</property>
f41b08
         <property name="receives_default">True</property>
f41b08
         <property name="sensitive">False</property>
f41b08
+        <signal name="notify::sensitive" handler="activate_button_on_sensitive_notify"/>
f41b08
       </object>
f41b08
     </child>
f41b08
     <action-widgets>
f41b08
-- 
f41b08
2.31.1
f41b08