=== modified file 'data/org.gnome.DejaDup.gschema.xml.in' --- data/org.gnome.DejaDup.gschema.xml.in 2015-11-29 15:53:51 +0000 +++ data/org.gnome.DejaDup.gschema.xml.in 2015-12-24 16:01:55 +0000 @@ -65,6 +65,7 @@ + @@ -80,9 +81,27 @@ + + + + '' + <_summary>Backblaze B2 Account ID + <_description>Your Backblaze B2 Account Identifier. This acts as your B2 username. + + + '' + <_summary>The Backblaze B2 bucket name to use + <_description>Which Backblaze B2 bucket to store files in. This does not need to exist already. Only legal hostname strings are valid. + + + '$HOSTNAME' + <_summary>The Backblaze B2 folder + <_description>An optional folder name to store files in. This folder will be created in the chosen bucket. + + '' === modified file 'deja-dup/widgets/CMakeLists.txt' --- deja-dup/widgets/CMakeLists.txt 2015-11-29 15:53:51 +0000 +++ deja-dup/widgets/CMakeLists.txt 2015-12-24 15:19:16 +0000 @@ -36,6 +36,7 @@ ConfigLocationOpenstack.vala ConfigLocationRackspace.vala ConfigLocationS3.vala + ConfigLocationB2.vala ConfigLocationSSH.vala ConfigLocationSMB.vala ConfigLocationTable.vala === modified file 'deja-dup/widgets/ConfigLabelLocation.vala' --- deja-dup/widgets/ConfigLabelLocation.vala 2015-11-29 15:53:51 +0000 +++ deja-dup/widgets/ConfigLabelLocation.vala 2015-12-24 15:19:16 +0000 @@ -27,6 +27,7 @@ FilteredSettings file_root; FilteredSettings gdrive_root; FilteredSettings s3_root; + FilteredSettings b2_root; FilteredSettings rackspace_root; FilteredSettings openstack_root; @@ -42,6 +43,7 @@ watch_key(null, (file_root = DejaDup.get_settings(FILE_ROOT))); watch_key(null, (gdrive_root = DejaDup.get_settings(GDRIVE_ROOT))); watch_key(null, (s3_root = DejaDup.get_settings(S3_ROOT))); + watch_key(null, (b2_root = DejaDup.get_settings(B2_ROOT))); watch_key(null, (rackspace_root = DejaDup.get_settings(RACKSPACE_ROOT))); watch_key(null, (openstack_root = DejaDup.get_settings(OPENSTACK_ROOT))); set_from_config.begin(); === modified file 'deja-dup/widgets/ConfigLocation.vala' --- deja-dup/widgets/ConfigLocation.vala 2015-11-29 15:53:51 +0000 +++ deja-dup/widgets/ConfigLocation.vala 2015-12-24 15:19:16 +0000 @@ -61,6 +61,7 @@ int index_ftp; int index_dav; int index_s3 = -2; + int index_b2 = -2; int index_gcs = -2; int index_gdrive = -2; int index_rackspace = -2; @@ -114,6 +115,7 @@ // Insert cloud providers insert_u1(); insert_s3(); + insert_b2(); insert_gcs(); insert_gdrive(); insert_rackspace(); @@ -176,6 +178,14 @@ delegate void CloudCallback(); + void insert_b2() { + insert_cloud_if_available("b2", BackendB2.get_checker(), + new ThemedIcon("deja-dup-cloud"), + _("Backblaze B2"), + new ConfigLocationB2(label_sizes), + ref index_b2, insert_b2); + } + void insert_s3() { insert_cloud_if_available("s3", BackendS3.get_checker(), new ThemedIcon("deja-dup-cloud"), @@ -444,6 +454,8 @@ var backend = Backend.get_default_type(); if (backend == "s3") index = index_s3; + else if (backend == "b2") + index = index_b2; else if (backend == "gcs") index = index_gcs; else if (backend == "gdrive") @@ -540,6 +552,8 @@ if (index == index_s3) settings.set_string(BACKEND_KEY, "s3"); + else if (index == index_b2) + settings.set_string(BACKEND_KEY, "b2"); else if (index == index_gcs) settings.set_string(BACKEND_KEY, "gcs"); else if (index == index_gdrive) === added file 'deja-dup/widgets/ConfigLocationB2.vala' --- deja-dup/widgets/ConfigLocationB2.vala 1970-01-01 00:00:00 +0000 +++ deja-dup/widgets/ConfigLocationB2.vala 2015-12-24 16:01:55 +0000 @@ -0,0 +1,41 @@ +/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 2 -*- */ +/* + This file is part of Déjà Dup. + For copyright information, see AUTHORS. + + Déjà Dup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Déjà Dup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Déjà Dup. If not, see . +*/ + +using GLib; + +namespace DejaDup { + +public class ConfigLocationB2 : ConfigLocationTable +{ + public ConfigLocationB2(Gtk.SizeGroup sg) { + Object(label_sizes: sg); + } + + construct { + add_widget(_("Backblaze Cloud Storage Account I_D"), + new ConfigEntry(DejaDup.B2_ID_KEY, DejaDup.B2_ROOT)); + add_widget(_("_Bucket"), + new ConfigEntry(DejaDup.B2_BUCKET_KEY, DejaDup.B2_ROOT)); + add_widget(_("_Folder"), + new ConfigFolder(DejaDup.B2_FOLDER_KEY, DejaDup.B2_ROOT)); + } +} + +} + === modified file 'libdeja/Backend.vala' --- libdeja/Backend.vala 2015-11-29 15:53:51 +0000 +++ libdeja/Backend.vala 2015-12-24 15:19:16 +0000 @@ -57,6 +57,7 @@ if (backend != "auto" && backend != "s3" && + backend != "b2" && backend != "gcs" && backend != "gdrive" && backend != "rackspace" && @@ -73,6 +74,8 @@ var backend_name = get_default_type(); if (backend_name == "s3") return new BackendS3(); + else if (backend_name == "b2") + return new BackendB2(); else if (backend_name == "gcs") return new BackendGCS(); else if (backend_name == "gdrive") === added file 'libdeja/BackendB2.vala' --- libdeja/BackendB2.vala 1970-01-01 00:00:00 +0000 +++ libdeja/BackendB2.vala 2015-12-24 15:19:16 +0000 @@ -0,0 +1,177 @@ +/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 2 -*- */ +/* + This file is part of Déjà Dup. + For copyright information, see AUTHORS. + + Déjà Dup is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Déjà Dup is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Déjà Dup. If not, see . +*/ + +using GLib; + +namespace DejaDup { + +public const string B2_ROOT = "B2"; +public const string B2_ID_KEY = "id"; +public const string B2_BUCKET_KEY = "bucket"; +public const string B2_FOLDER_KEY = "folder"; + +const string B2_SERVER = "api.backblaze.com"; + +public class BackendB2 : Backend + +{ + public static Checker get_checker() { + return PythonChecker.get_checker("duplicity.backends.b2backend"); + } + + public override Backend clone() { + return new BackendB2(); + } + + public override bool is_native() { + return false; + } + + public override Icon? get_icon() { + return new ThemedIcon("deja-dup-cloud"); + } + + public override async bool is_ready(out string when) { + when = _("Backup will begin when a network connection becomes available."); + return yield Network.get().can_reach ("https://%s/".printf(B2_SERVER)); + } + + /** + * duplicity syntax: + * b2://account_id[:application_key]@bucket_name/[folder/] + */ + public override string get_location(ref bool as_root) + { + var settings = get_settings(B2_ROOT); + + var account_id = settings.get_string(B2_ID_KEY); + var bucket = settings.get_string(B2_BUCKET_KEY); + var folder = get_folder_key(settings, B2_FOLDER_KEY); + + return "b2://%s@%s/%s".printf(account_id, bucket, folder); + } + + public override string get_location_pretty() + { + var settings = get_settings(B2_ROOT); + var bucket = settings.get_string(B2_BUCKET_KEY); + var folder = get_folder_key(settings, B2_FOLDER_KEY); + if (folder == "") + return _("Backblaze Cloud Storage"); + else + // Translators: %s/%s is a folder. + return _("%s/%s on Backblaze Cloud Storage").printf(bucket, folder); + } + + string settings_id; + string id; + string secret_key; + public override async void get_envp() throws Error + { + var settings = get_settings(B2_ROOT); + settings_id = settings.get_string(B2_ID_KEY); + id = settings_id == null ? "" : settings_id; + + if (id != "" && secret_key != null) { + // We've already been run before and got the key + got_secret_key(); + return; + } + + if (id != "") { + // First, try user's keyring + try { + secret_key = yield Secret.password_lookup(Secret.SCHEMA_COMPAT_NETWORK, + null, + "user", id, + "server", B2_SERVER, + "protocol", "https"); + if (secret_key != null) { + got_secret_key(); + return; + } + } + catch (Error e) { + // fall through to ask_password below + } + } + + // Didn't find it, so ask user + ask_password(); + } + + async void got_password_reply(MountOperation mount_op, MountOperationResult result) + { + if (result != MountOperationResult.HANDLED) { + envp_ready(false, new List(), _("Permission denied")); + return; + } + + id = mount_op.username; + secret_key = mount_op.password; + + // Save it + var remember = mount_op.password_save; + if (remember != PasswordSave.NEVER) { + string where = (remember == PasswordSave.FOR_SESSION) ? + Secret.COLLECTION_SESSION : Secret.COLLECTION_DEFAULT; + try { + yield Secret.password_store(Secret.SCHEMA_COMPAT_NETWORK, + where, + "%s@%s".printf(id, B2_SERVER), + secret_key, + null, + "user", id, + "server", B2_SERVER, + "protocol", "https"); + } + catch (Error e) { + warning("%s\n", e.message); + } + } + + got_secret_key(); + } + + void ask_password() { + mount_op.set("label_help", _("You can sign up for a Backblaze Cloud Storage account online. Remember to enable the product in settings and create keys.").printf("https://www.backblaze.com/b2/cloud-storage.html")); + mount_op.set("label_title", _("Connect to Backblaze Cloud Storage")); + mount_op.set("label_username", _("_Account ID")); + mount_op.set("label_password", _("Application _key")); + mount_op.set("label_show_password", _("_Show Application key")); + mount_op.set("label_remember_password", _("_Remember Application key")); + mount_op.reply.connect(got_password_reply); + mount_op.ask_password("", id, "", + AskPasswordFlags.NEED_PASSWORD | + AskPasswordFlags.NEED_USERNAME | + AskPasswordFlags.SAVING_SUPPORTED); + } + + void got_secret_key() { + var settings = get_settings(B2_ROOT); + if (id != settings_id) + settings.set_string(B2_ID_KEY, id); + + List envp = new List(); + envp.append("FTP_PASSWORD=%s".printf(secret_key)); + envp_ready(true, envp); + } +} + +} // end namespace === modified file 'libdeja/CMakeLists.txt' --- libdeja/CMakeLists.txt 2015-11-29 15:53:51 +0000 +++ libdeja/CMakeLists.txt 2015-12-24 15:19:16 +0000 @@ -25,6 +25,7 @@ BackendOpenstack.vala BackendRackspace.vala BackendS3.vala + BackendB2.vala BackendU1.vala Checker.vala CommonUtils.vala