summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorintrigeri <intrigeri@boum.org>2019-10-07 06:08:06 +0000
committerintrigeri <intrigeri@boum.org>2019-10-07 06:08:06 +0000
commit0fdb65f67c2cb047e33ae9909283ccdf75efb333 (patch)
tree86e24763e0c95b14d15d2f6e5db3fa8dda6e2622
parentecec6894219cd4d702e7432c77acd8b20904a3a5 (diff)
parent158f68778b5df4aa0d9ef137fd4a5028113ddecc (diff)
Merge remote-tracking branch 'origin/devel' into feature/tor-nightly-masterfeature/tor-nightly-master
-rw-r--r--.gitignore3
-rwxr-xr-xauto/build3
-rwxr-xr-xauto/config1
-rw-r--r--config/APT_overlays.d/bugfix-17110-whisperback-drop-tls0
-rw-r--r--config/amnesia2
-rw-r--r--config/chroot_apt/preferences8
-rwxr-xr-xconfig/chroot_local-hooks/12-kernel-modules-build-environment25
-rwxr-xr-xconfig/chroot_local-hooks/13-aufs6
-rw-r--r--config/chroot_local-hooks/16-greeter48
-rwxr-xr-xconfig/chroot_local-hooks/30-gdm-debug6
-rwxr-xr-xconfig/chroot_local-includes/etc/NetworkManager/dispatcher.d/10-tor.sh4
-rwxr-xr-xconfig/chroot_local-includes/etc/NetworkManager/dispatcher.d/60-tor-ready.sh5
-rw-r--r--config/chroot_local-includes/etc/environment2
-rwxr-xr-xconfig/chroot_local-includes/etc/gdm3/PostLogin/Default10
-rw-r--r--config/chroot_local-includes/etc/skel/.electrum/config2
-rw-r--r--config/chroot_local-includes/etc/whisperback/4mvq3pnvid3awjln.onion.pem28
-rw-r--r--config/chroot_local-includes/etc/whisperback/config.py6
-rw-r--r--config/chroot_local-includes/etc/whisperback/debugging-info.json5
-rw-r--r--config/chroot_local-includes/lib/systemd/system/tails-tor-has-bootstrapped.target10
-rw-r--r--config/chroot_local-includes/lib/systemd/system/tails-unblock-network.service15
-rw-r--r--config/chroot_local-includes/lib/systemd/system/tails-wait-until-tor-has-bootstrapped.service5
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/__init__.py2
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/config.py23
-rw-r--r--[-rwxr-xr-x]config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/greeter.py (renamed from config/chroot_local-includes/usr/share/tails-greeter/tails-greeter.py)121
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/gui.py1171
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/language.py861
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/physicalsecurity.py69
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/rootaccess.py62
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/__init__.py0
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/admin.py34
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/formats.py128
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/keyboard.py214
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/language.py222
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization.py84
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization_settings.py70
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/macspoof.py19
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/network.py23
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/persistence.py (renamed from config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/persistence.py)6
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/translatable_window.py155
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/__init__.py3
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/add_settings_dialog.py142
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/additional_settings.py276
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/help_window.py72
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/main_window.py422
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/persistent_storage.py128
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/popover.py40
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/region_settings.py179
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/setting.py56
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/settings_collection.py36
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/utils.py49
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailslib/systemd.py8
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/tailslib/tor.py15
-rw-r--r--config/chroot_local-includes/usr/lib/python3/dist-packages/unlock_veracrypt_volumes/volume.py10
-rwxr-xr-xconfig/chroot_local-includes/usr/local/bin/electrum7
-rwxr-xr-xconfig/chroot_local-includes/usr/local/bin/replace-su-with-sudo2
-rwxr-xr-xconfig/chroot_local-includes/usr/local/bin/tails-documentation4
-rwxr-xr-xconfig/chroot_local-includes/usr/local/bin/tor-browser5
-rwxr-xr-xconfig/chroot_local-includes/usr/local/lib/tails-greeter6
-rw-r--r--config/chroot_local-includes/usr/local/lib/tails-shell-library/po.sh9
-rwxr-xr-xconfig/chroot_local-includes/usr/local/lib/tails-shell-library/systemd.sh5
-rw-r--r--config/chroot_local-includes/usr/local/lib/tails-shell-library/tails-greeter.sh13
-rwxr-xr-xconfig/chroot_local-includes/usr/local/lib/tails-unblock-network2
-rwxr-xr-xconfig/chroot_local-includes/usr/local/sbin/restart-tor2
-rwxr-xr-xconfig/chroot_local-includes/usr/local/sbin/tor-has-bootstrapped4
-rwxr-xr-xconfig/chroot_local-includes/usr/local/sbin/unsafe-browser6
-rw-r--r--config/chroot_local-includes/usr/share/gdm/dconf/50-tails4
-rw-r--r--config/chroot_local-includes/usr/share/tails-greeter/greeter.ui2021
-rw-r--r--config/chroot_local-includes/usr/share/tails/greeter/additional_settings.ui.in497
-rw-r--r--config/chroot_local-includes/usr/share/tails/greeter/default_locales (renamed from config/chroot_local-includes/usr/share/tails-greeter/default_langcodes)0
-rw-r--r--config/chroot_local-includes/usr/share/tails/greeter/greeter.css (renamed from config/chroot_local-includes/usr/share/tails-greeter/greeter.css)0
-rw-r--r--config/chroot_local-includes/usr/share/tails/greeter/main.ui.in681
-rw-r--r--config/chroot_local-includes/usr/share/tails/greeter/no-password-lecture.txt (renamed from config/chroot_local-includes/usr/share/tails-greeter/no-password-lecture.txt)0
-rw-r--r--config/chroot_local-includes/usr/share/tails/greeter/region_settings.ui.in182
-rwxr-xr-xconfig/chroot_local-includes/usr/share/tails/greeter/set-cursor.py (renamed from config/chroot_local-includes/usr/share/tails-greeter/set-cursor.py)0
-rw-r--r--config/chroot_local-includes/usr/share/tails/greeter/setting.ui.in56
-rwxr-xr-xconfig/chroot_local-includes/usr/share/tails/greeter/tails-greeter.py68
-rw-r--r--config/chroot_local-includes/usr/share/tails/greeter/tails-logging.conf (renamed from config/chroot_local-includes/usr/share/tails-greeter/tails-logging.conf)0
-rw-r--r--config/chroot_local-packageslists/tails-common.list2
-rw-r--r--config/chroot_local-patches/apparmor-adjust-thunderbird-profile.diff14
l---------config/chroot_sources/experimental.binary1
-rw-r--r--config/chroot_sources/experimental.chroot1
-rw-r--r--features/images/UnsafeBrowserStartPage.fr.pngbin0 -> 5040 bytes
-rw-r--r--features/step_definitions/common_steps.rb1
-rw-r--r--features/support/extra_hooks.rb32
-rw-r--r--features/support/helpers/misc_helpers.rb2
-rwxr-xr-xgenerate-languages-list19
-rwxr-xr-ximport-translations24
-rw-r--r--po/POTFILES.in13
-rw-r--r--po/POTFILES.skip13
-rw-r--r--po/ar.po500
-rw-r--r--po/bn_BD.po1261
-rw-r--r--po/ca.po503
-rw-r--r--po/cs.po502
-rw-r--r--po/de.po503
-rw-r--r--po/el.po501
-rw-r--r--po/es.po601
-rw-r--r--po/es_AR.po503
-rw-r--r--po/fi.po503
-rw-r--r--po/fr.po503
-rw-r--r--po/fr_CA.po1235
-rw-r--r--po/ga.po503
-rw-r--r--po/he.po503
-rw-r--r--po/hr_HR.po1229
-rw-r--r--po/hu.po505
-rw-r--r--po/id.po500
-rw-r--r--po/it.po503
-rw-r--r--po/km.po502
-rw-r--r--po/ko.po502
-rw-r--r--po/lt.po502
-rw-r--r--po/pl.po500
-rw-r--r--po/pt.po1235
-rw-r--r--po/pt_BR.po503
-rw-r--r--po/pt_PT.po502
-rw-r--r--po/ro.po503
-rw-r--r--po/sk_SK.po1229
-rw-r--r--po/sl_SI.po1415
-rw-r--r--po/sv.po503
-rw-r--r--po/tails.pot500
-rw-r--r--po/tr.po597
-rw-r--r--po/zh_CN.po503
-rwxr-xr-xrefresh-translations11
m---------submodules/aufs-standalone0
-rw-r--r--wiki/src/about/contact.ar.po23
-rw-r--r--wiki/src/about/contact.ca.po23
-rw-r--r--wiki/src/about/contact.de.po32
-rw-r--r--wiki/src/about/contact.es.po96
-rw-r--r--wiki/src/about/contact.fa.po23
-rw-r--r--wiki/src/about/contact.fr.po32
-rw-r--r--wiki/src/about/contact.id.po23
-rw-r--r--wiki/src/about/contact.it.po32
-rw-r--r--wiki/src/about/contact.mdwn10
-rw-r--r--wiki/src/about/contact.pl.po23
-rw-r--r--wiki/src/about/contact.pt.po32
-rw-r--r--wiki/src/about/contact.ru.po23
-rw-r--r--wiki/src/about/contact.sr_Latn.po23
-rw-r--r--wiki/src/about/contact.tr.po23
-rw-r--r--wiki/src/about/contact.zh.po23
-rw-r--r--wiki/src/about/contact.zh_TW.po26
-rw-r--r--wiki/src/blueprint/GitLab.mdwn2
-rw-r--r--wiki/src/blueprint/translation_platform.mdwn561
-rw-r--r--wiki/src/blueprint/wi-fi_adapters.mdwn9
-rw-r--r--wiki/src/contribute.fr.po2
-rw-r--r--wiki/src/contribute/calendar.mdwn10
-rw-r--r--wiki/src/contribute/design.mdwn1
-rw-r--r--wiki/src/contribute/how/documentation/release_notes/template.mdwn2
-rw-r--r--wiki/src/contribute/how/documentation/style_guide.mdwn15
-rw-r--r--wiki/src/contribute/how/translate.mdwn4
-rw-r--r--wiki/src/contribute/how/translate/with_translation_platform.mdwn211
-rw-r--r--wiki/src/contribute/l10n_tricks.mdwn5
-rw-r--r--wiki/src/contribute/l10n_tricks/core_po_files.txt14
-rwxr-xr-xwiki/src/contribute/l10n_tricks/language_statistics.sh31
-rw-r--r--wiki/src/contribute/release_process.mdwn28
-rw-r--r--wiki/src/contribute/working_together/roles/sysadmins.mdwn1
-rw-r--r--wiki/src/contribute/working_together/roles/sysadmins/automated_tests_in_Jenkins.mdwn9
-rw-r--r--wiki/src/doc.ar.po37
-rw-r--r--wiki/src/doc.ca.po37
-rw-r--r--wiki/src/doc.de.po82
-rw-r--r--wiki/src/doc.es.po66
-rw-r--r--wiki/src/doc.fa.po47
-rw-r--r--wiki/src/doc.fr.po62
-rw-r--r--wiki/src/doc.id.po37
-rw-r--r--wiki/src/doc.it.po62
-rw-r--r--wiki/src/doc.mdwn26
-rw-r--r--wiki/src/doc.pl.po37
-rw-r--r--wiki/src/doc.pt.po62
-rw-r--r--wiki/src/doc.ru.po37
-rw-r--r--wiki/src/doc.sr_Latn.po37
-rw-r--r--wiki/src/doc.tr.po37
-rw-r--r--wiki/src/doc.zh.po49
-rw-r--r--wiki/src/doc.zh_TW.po46
-rw-r--r--wiki/src/doc/about/acknowledgments_and_similar_projects.fr.po96
-rw-r--r--wiki/src/doc/about/features.ar.po3
-rw-r--r--wiki/src/doc/about/features.ca.po3
-rw-r--r--wiki/src/doc/about/features.de.po2
-rw-r--r--wiki/src/doc/about/features.es.po2
-rw-r--r--wiki/src/doc/about/features.fa.po4
-rw-r--r--wiki/src/doc/about/features.fr.po41
-rw-r--r--wiki/src/doc/about/features.id.po2
-rw-r--r--wiki/src/doc/about/features.it.po2
-rw-r--r--wiki/src/doc/about/features.mdwn2
-rw-r--r--wiki/src/doc/about/features.pl.po2
-rw-r--r--wiki/src/doc/about/features.pt.po2
-rw-r--r--wiki/src/doc/about/features.ru.po2
-rw-r--r--wiki/src/doc/about/features.sr_Latn.po2
-rw-r--r--wiki/src/doc/about/features.tr.po2
-rw-r--r--wiki/src/doc/about/features.zh.po2
-rw-r--r--wiki/src/doc/about/features.zh_TW.po2
-rw-r--r--wiki/src/doc/about/openpgp_keys.ar.po34
-rw-r--r--wiki/src/doc/about/openpgp_keys.ca.po34
-rw-r--r--wiki/src/doc/about/openpgp_keys.de.po60
-rw-r--r--wiki/src/doc/about/openpgp_keys.es.po83
-rw-r--r--wiki/src/doc/about/openpgp_keys.fa.po59
-rw-r--r--wiki/src/doc/about/openpgp_keys.fr.po173
-rw-r--r--wiki/src/doc/about/openpgp_keys.id.po34
-rw-r--r--wiki/src/doc/about/openpgp_keys.it.po51
-rw-r--r--wiki/src/doc/about/openpgp_keys.mdwn31
-rw-r--r--wiki/src/doc/about/openpgp_keys.pl.po34
-rw-r--r--wiki/src/doc/about/openpgp_keys.pt.po39
-rw-r--r--wiki/src/doc/about/openpgp_keys.ru.po34
-rw-r--r--wiki/src/doc/about/openpgp_keys.sr_Latn.po34
-rw-r--r--wiki/src/doc/about/openpgp_keys.tr.po34
-rw-r--r--wiki/src/doc/about/openpgp_keys.zh.po34
-rw-r--r--wiki/src/doc/about/openpgp_keys.zh_TW.po34
-rw-r--r--wiki/src/doc/about/openpgp_keys/signing_key_revocation.fr.po204
-rw-r--r--wiki/src/doc/about/tor.fr.po17
-rw-r--r--wiki/src/doc/about/warning.fr.po5
-rw-r--r--wiki/src/doc/advanced_topics.index.ar.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.ca.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.de.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.es.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.fa.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.fr.po42
-rw-r--r--wiki/src/doc/advanced_topics.index.id.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.it.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.mdwn2
-rw-r--r--wiki/src/doc/advanced_topics.index.pl.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.pt.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.ru.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.sr_Latn.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.tr.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.zh.po4
-rw-r--r--wiki/src/doc/advanced_topics.index.zh_TW.po4
-rw-r--r--wiki/src/doc/advanced_topics/virtualization/virt-manager.fr.po23
-rw-r--r--wiki/src/doc/anonymous_internet/Tor_Browser.fr.po92
-rw-r--r--wiki/src/doc/anonymous_internet/electrum.fr.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager.fr.po12
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.ar.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.ca.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.de.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.es.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.fa.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.fr.po35
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.id.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.it.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.mdwn15
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.pl.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.pt.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.ru.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.sr_Latn.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.tr.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.zh.po20
-rw-r--r--wiki/src/doc/anonymous_internet/networkmanager/no-wifi.inline.zh_TW.po20
-rw-r--r--wiki/src/doc/anonymous_internet/onionshare.ar.po6
-rw-r--r--wiki/src/doc/anonymous_internet/onionshare.ca.po6
-rw-r--r--wiki/src/doc/anonymous_internet/onionshare.fr.po155
-rw-r--r--wiki/src/doc/anonymous_internet/onionshare.id.po6
-rw-r--r--wiki/src/doc/anonymous_internet/onionshare.mdwn2
-rw-r--r--wiki/src/doc/anonymous_internet/onionshare.pl.po6
-rw-r--r--wiki/src/doc/anonymous_internet/onionshare.ru.po6
-rw-r--r--wiki/src/doc/anonymous_internet/onionshare.sr_Latn.po6
-rw-r--r--wiki/src/doc/anonymous_internet/onionshare.tr.po6
-rw-r--r--wiki/src/doc/anonymous_internet/onionshare.zh.po6
-rw-r--r--wiki/src/doc/anonymous_internet/onionshare.zh_TW.po6
-rw-r--r--wiki/src/doc/anonymous_internet/pidgin.fr.po46
-rw-r--r--wiki/src/doc/anonymous_internet/thunderbird.fr.po16
-rw-r--r--wiki/src/doc/anonymous_internet/tor_status.es.po12
-rw-r--r--wiki/src/doc/anonymous_internet/unsafe_browser.fr.po38
-rw-r--r--wiki/src/doc/anonymous_internet/unsafe_browser/captive_portal.inline.fr.po21
-rw-r--r--wiki/src/doc/anonymous_internet/why_tor_is_slow.fr.po17
-rw-r--r--wiki/src/doc/encryption_and_privacy.index.fr.po15
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.ar.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.ca.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.de.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.es.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.fa.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.fr.po20
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.id.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.it.po4
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.mdwn2
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.pl.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.pt.po4
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.ru.po10
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.sr_Latn.po19
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.tr.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.zh.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/checksums.zh_TW.po17
-rw-r--r--wiki/src/doc/encryption_and_privacy/encrypted_volumes.fr.po100
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.ar.po4
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.ca.po4
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.de.po10
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.es.po12
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.fa.po10
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.fr.po16
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.id.po4
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.it.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.mdwn2
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.pl.po4
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.pt.po13
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.ru.po4
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.sr_Latn.po4
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.tr.po4
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.zh.po4
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/decrypt_verify.zh_TW.po4
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.ar.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.ca.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.de.po19
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.es.po27
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.fa.po12
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.fr.po19
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.id.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.it.po10
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.mdwn4
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.pl.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.pt.po18
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.ru.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.sr_Latn.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.tr.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.zh.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/passphrase_encryption.zh_TW.po6
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.ar.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.ca.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.de.po20
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.es.po23
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.fa.po13
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.fr.po20
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.id.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.it.po12
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.mdwn4
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.pl.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.pt.po20
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.ru.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.sr_Latn.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.tr.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.zh.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/gpgapplet/public-key_cryptography.zh_TW.po8
-rw-r--r--wiki/src/doc/encryption_and_privacy/manage_passwords.fr.po134
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.ar.po13
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.ca.po9
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.de.po11
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.es.po3
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.fa.po11
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.fr.po113
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.id.po9
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.it.po3
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.mdwn4
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.pl.po9
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.pt.po3
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.ru.po13
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.sr_Latn.po45
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.tr.po9
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.zh.po9
-rw-r--r--wiki/src/doc/encryption_and_privacy/secure_deletion.zh_TW.po41
-rw-r--r--wiki/src/doc/encryption_and_privacy/your_data_wont_be_saved_unless_explicitly_asked.fr.po41
-rw-r--r--wiki/src/doc/first_steps.index.ar.po9
-rw-r--r--wiki/src/doc/first_steps.index.ca.po9
-rw-r--r--wiki/src/doc/first_steps.index.de.po9
-rw-r--r--wiki/src/doc/first_steps.index.es.po9
-rw-r--r--wiki/src/doc/first_steps.index.fa.po9
-rw-r--r--wiki/src/doc/first_steps.index.fr.po21
-rw-r--r--wiki/src/doc/first_steps.index.id.po9
-rw-r--r--wiki/src/doc/first_steps.index.it.po9
-rw-r--r--wiki/src/doc/first_steps.index.mdwn7
-rw-r--r--wiki/src/doc/first_steps.index.pl.po9
-rw-r--r--wiki/src/doc/first_steps.index.pt.po9
-rw-r--r--wiki/src/doc/first_steps.index.ru.po9
-rw-r--r--wiki/src/doc/first_steps.index.sr_Latn.po9
-rw-r--r--wiki/src/doc/first_steps.index.tr.po9
-rw-r--r--wiki/src/doc/first_steps.index.zh.po9
-rw-r--r--wiki/src/doc/first_steps.index.zh_TW.po9
-rw-r--r--wiki/src/doc/first_steps/accessibility.fr.po12
-rw-r--r--wiki/src/doc/first_steps/additional_software.ar.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.ca.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.de.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.es.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.fa.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.fr.po192
-rw-r--r--wiki/src/doc/first_steps/additional_software.id.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.it.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.mdwn8
-rw-r--r--wiki/src/doc/first_steps/additional_software.pl.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.pt.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.ru.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.sr_Latn.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.tr.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.zh.po21
-rw-r--r--wiki/src/doc/first_steps/additional_software.zh_TW.po21
-rw-r--r--wiki/src/doc/first_steps/introduction_to_gnome_and_the_tails_desktop.es.po20
-rw-r--r--wiki/src/doc/first_steps/introduction_to_gnome_and_the_tails_desktop.fr.po374
-rw-r--r--wiki/src/doc/first_steps/persistence.fr.po10
-rw-r--r--wiki/src/doc/first_steps/persistence/configure.fr.po111
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.ar.po268
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.ca.po268
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.de.po722
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.es.po439
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.fa.po722
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.fr.po692
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.id.po266
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.it.po283
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.mdwn208
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.pl.po268
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.pt.po779
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.ru.po268
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.sr_Latn.po268
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.tr.po268
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.zh.po268
-rw-r--r--wiki/src/doc/first_steps/persistence/copy.zh_TW.po266
-rw-r--r--wiki/src/doc/first_steps/persistence/delete.fr.po47
-rw-r--r--wiki/src/doc/first_steps/persistence/thunderbird.pngbin5398 -> 3605 bytes
-rw-r--r--wiki/src/doc/reset.ar.po (renamed from wiki/src/doc/first_steps/reset.ar.po)0
-rw-r--r--wiki/src/doc/reset.ca.po (renamed from wiki/src/doc/first_steps/reset.ca.po)0
-rw-r--r--wiki/src/doc/reset.de.po (renamed from wiki/src/doc/first_steps/reset.de.po)4
-rw-r--r--wiki/src/doc/reset.es.po (renamed from wiki/src/doc/first_steps/reset.es.po)4
-rw-r--r--wiki/src/doc/reset.fa.po (renamed from wiki/src/doc/first_steps/reset.fa.po)4
-rw-r--r--wiki/src/doc/reset.fr.po (renamed from wiki/src/doc/first_steps/reset.fr.po)4
-rw-r--r--wiki/src/doc/reset.id.po (renamed from wiki/src/doc/first_steps/reset.id.po)0
-rw-r--r--wiki/src/doc/reset.intro.ar.po (renamed from wiki/src/doc/first_steps/reset.intro.ar.po)0
-rw-r--r--wiki/src/doc/reset.intro.ca.po (renamed from wiki/src/doc/first_steps/reset.intro.ca.po)0
-rw-r--r--wiki/src/doc/reset.intro.de.po (renamed from wiki/src/doc/first_steps/reset.intro.de.po)0
-rw-r--r--wiki/src/doc/reset.intro.es.po (renamed from wiki/src/doc/first_steps/reset.intro.es.po)0
-rw-r--r--wiki/src/doc/reset.intro.fa.po (renamed from wiki/src/doc/first_steps/reset.intro.fa.po)0
-rw-r--r--wiki/src/doc/reset.intro.fr.po (renamed from wiki/src/doc/first_steps/reset.intro.fr.po)0
-rw-r--r--wiki/src/doc/reset.intro.id.po (renamed from wiki/src/doc/first_steps/reset.intro.id.po)0
-rw-r--r--wiki/src/doc/reset.intro.it.po (renamed from wiki/src/doc/first_steps/reset.intro.it.po)0
-rw-r--r--wiki/src/doc/reset.intro.mdwn (renamed from wiki/src/doc/first_steps/reset.intro.mdwn)0
-rw-r--r--wiki/src/doc/reset.intro.pl.po (renamed from wiki/src/doc/first_steps/reset.intro.pl.po)0
-rw-r--r--wiki/src/doc/reset.intro.pt.po (renamed from wiki/src/doc/first_steps/reset.intro.pt.po)0
-rw-r--r--wiki/src/doc/reset.intro.ru.po (renamed from wiki/src/doc/first_steps/reset.intro.ru.po)0
-rw-r--r--wiki/src/doc/reset.intro.sr_Latn.po (renamed from wiki/src/doc/first_steps/reset.intro.sr_Latn.po)0
-rw-r--r--wiki/src/doc/reset.intro.tr.po (renamed from wiki/src/doc/first_steps/reset.intro.tr.po)0
-rw-r--r--wiki/src/doc/reset.intro.zh.po (renamed from wiki/src/doc/first_steps/reset.intro.zh.po)0
-rw-r--r--wiki/src/doc/reset.intro.zh_TW.po (renamed from wiki/src/doc/first_steps/reset.intro.zh_TW.po)0
-rw-r--r--wiki/src/doc/reset.it.po (renamed from wiki/src/doc/first_steps/reset.it.po)4
-rw-r--r--wiki/src/doc/reset.mdwn (renamed from wiki/src/doc/first_steps/reset.mdwn)2
-rw-r--r--wiki/src/doc/reset.pl.po (renamed from wiki/src/doc/first_steps/reset.pl.po)0
-rw-r--r--wiki/src/doc/reset.pt.po (renamed from wiki/src/doc/first_steps/reset.pt.po)4
-rw-r--r--wiki/src/doc/reset.ru.po (renamed from wiki/src/doc/first_steps/reset.ru.po)0
-rw-r--r--wiki/src/doc/reset.sr_Latn.po (renamed from wiki/src/doc/first_steps/reset.sr_Latn.po)0
-rw-r--r--wiki/src/doc/reset.tr.po (renamed from wiki/src/doc/first_steps/reset.tr.po)0
-rw-r--r--wiki/src/doc/reset.zh.po (renamed from wiki/src/doc/first_steps/reset.zh.po)0
-rw-r--r--wiki/src/doc/reset.zh_TW.po (renamed from wiki/src/doc/first_steps/reset.zh_TW.po)0
-rw-r--r--wiki/src/doc/reset/linux.ar.po (renamed from wiki/src/doc/first_steps/reset/linux.ar.po)0
-rw-r--r--wiki/src/doc/reset/linux.ca.po (renamed from wiki/src/doc/first_steps/reset/linux.ca.po)0
-rw-r--r--wiki/src/doc/reset/linux.de.po (renamed from wiki/src/doc/first_steps/reset/linux.de.po)4
-rw-r--r--wiki/src/doc/reset/linux.es.po (renamed from wiki/src/doc/first_steps/reset/linux.es.po)4
-rw-r--r--wiki/src/doc/reset/linux.fa.po (renamed from wiki/src/doc/first_steps/reset/linux.fa.po)4
-rw-r--r--wiki/src/doc/reset/linux.fr.po (renamed from wiki/src/doc/first_steps/reset/linux.fr.po)4
-rw-r--r--wiki/src/doc/reset/linux.id.po (renamed from wiki/src/doc/first_steps/reset/linux.id.po)0
-rw-r--r--wiki/src/doc/reset/linux.it.po (renamed from wiki/src/doc/first_steps/reset/linux.it.po)4
-rw-r--r--wiki/src/doc/reset/linux.mdwn (renamed from wiki/src/doc/first_steps/reset/linux.mdwn)2
-rw-r--r--wiki/src/doc/reset/linux.pl.po (renamed from wiki/src/doc/first_steps/reset/linux.pl.po)0
-rw-r--r--wiki/src/doc/reset/linux.pt.po (renamed from wiki/src/doc/first_steps/reset/linux.pt.po)4
-rw-r--r--wiki/src/doc/reset/linux.ru.po (renamed from wiki/src/doc/first_steps/reset/linux.ru.po)0
-rw-r--r--wiki/src/doc/reset/linux.sr_Latn.po (renamed from wiki/src/doc/first_steps/reset/linux.sr_Latn.po)0
-rw-r--r--wiki/src/doc/reset/linux.tr.po (renamed from wiki/src/doc/first_steps/reset/linux.tr.po)0
-rw-r--r--wiki/src/doc/reset/linux.zh.po (renamed from wiki/src/doc/first_steps/reset/linux.zh.po)0
-rw-r--r--wiki/src/doc/reset/linux.zh_TW.po (renamed from wiki/src/doc/first_steps/reset/linux.zh_TW.po)0
-rw-r--r--wiki/src/doc/reset/mac.ar.po (renamed from wiki/src/doc/first_steps/reset/mac.ar.po)0
-rw-r--r--wiki/src/doc/reset/mac.ca.po (renamed from wiki/src/doc/first_steps/reset/mac.ca.po)0
-rw-r--r--wiki/src/doc/reset/mac.de.po (renamed from wiki/src/doc/first_steps/reset/mac.de.po)4
-rw-r--r--wiki/src/doc/reset/mac.es.po (renamed from wiki/src/doc/first_steps/reset/mac.es.po)4
-rw-r--r--wiki/src/doc/reset/mac.fa.po (renamed from wiki/src/doc/first_steps/reset/mac.fa.po)4
-rw-r--r--wiki/src/doc/reset/mac.fr.po (renamed from wiki/src/doc/first_steps/reset/mac.fr.po)18
-rw-r--r--wiki/src/doc/reset/mac.id.po (renamed from wiki/src/doc/first_steps/reset/mac.id.po)0
-rw-r--r--wiki/src/doc/reset/mac.it.po (renamed from wiki/src/doc/first_steps/reset/mac.it.po)4
-rw-r--r--wiki/src/doc/reset/mac.mdwn (renamed from wiki/src/doc/first_steps/reset/mac.mdwn)2
-rw-r--r--wiki/src/doc/reset/mac.pl.po (renamed from wiki/src/doc/first_steps/reset/mac.pl.po)0
-rw-r--r--wiki/src/doc/reset/mac.pt.po (renamed from wiki/src/doc/first_steps/reset/mac.pt.po)4
-rw-r--r--wiki/src/doc/reset/mac.ru.po (renamed from wiki/src/doc/first_steps/reset/mac.ru.po)0
-rw-r--r--wiki/src/doc/reset/mac.sr_Latn.po (renamed from wiki/src/doc/first_steps/reset/mac.sr_Latn.po)0
-rw-r--r--wiki/src/doc/reset/mac.tr.po (renamed from wiki/src/doc/first_steps/reset/mac.tr.po)0
-rw-r--r--wiki/src/doc/reset/mac.zh.po (renamed from wiki/src/doc/first_steps/reset/mac.zh.po)0
-rw-r--r--wiki/src/doc/reset/mac.zh_TW.po (renamed from wiki/src/doc/first_steps/reset/mac.zh_TW.po)0
-rw-r--r--wiki/src/doc/reset/windows.ar.po (renamed from wiki/src/doc/first_steps/reset/windows.ar.po)0
-rw-r--r--wiki/src/doc/reset/windows.ca.po (renamed from wiki/src/doc/first_steps/reset/windows.ca.po)0
-rw-r--r--wiki/src/doc/reset/windows.de.po (renamed from wiki/src/doc/first_steps/reset/windows.de.po)4
-rw-r--r--wiki/src/doc/reset/windows.es.po (renamed from wiki/src/doc/first_steps/reset/windows.es.po)4
-rw-r--r--wiki/src/doc/reset/windows.fa.po (renamed from wiki/src/doc/first_steps/reset/windows.fa.po)4
-rw-r--r--wiki/src/doc/reset/windows.fr.po (renamed from wiki/src/doc/first_steps/reset/windows.fr.po)4
-rw-r--r--wiki/src/doc/reset/windows.id.po (renamed from wiki/src/doc/first_steps/reset/windows.id.po)0
-rw-r--r--wiki/src/doc/reset/windows.it.po (renamed from wiki/src/doc/first_steps/reset/windows.it.po)4
-rw-r--r--wiki/src/doc/reset/windows.mdwn (renamed from wiki/src/doc/first_steps/reset/windows.mdwn)2
-rw-r--r--wiki/src/doc/reset/windows.pl.po (renamed from wiki/src/doc/first_steps/reset/windows.pl.po)0
-rw-r--r--wiki/src/doc/reset/windows.pt.po (renamed from wiki/src/doc/first_steps/reset/windows.pt.po)4
-rw-r--r--wiki/src/doc/reset/windows.ru.po (renamed from wiki/src/doc/first_steps/reset/windows.ru.po)0
-rw-r--r--wiki/src/doc/reset/windows.sr_Latn.po (renamed from wiki/src/doc/first_steps/reset/windows.sr_Latn.po)0
-rw-r--r--wiki/src/doc/reset/windows.tr.po (renamed from wiki/src/doc/first_steps/reset/windows.tr.po)0
-rw-r--r--wiki/src/doc/reset/windows.zh.po (renamed from wiki/src/doc/first_steps/reset/windows.zh.po)0
-rw-r--r--wiki/src/doc/reset/windows.zh_TW.po (renamed from wiki/src/doc/first_steps/reset/windows.zh_TW.po)0
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.ar.po6
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.ca.po6
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.de.po11
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.es.po6
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.fa.po11
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.fr.po26
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.id.po6
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.it.po6
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.mdwn1
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.pl.po6
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.pt.po6
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.ru.po6
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.sr_Latn.po6
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.tr.po6
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.zh.po6
-rw-r--r--wiki/src/doc/sensitive_documents/office_suite.zh_TW.po9
-rw-r--r--wiki/src/doc/sensitive_documents/sound_and_video.fr.po28
-rw-r--r--wiki/src/doc/upgrade.ar.po (renamed from wiki/src/doc/first_steps/upgrade.ar.po)17
-rw-r--r--wiki/src/doc/upgrade.ca.po (renamed from wiki/src/doc/first_steps/upgrade.ca.po)17
-rw-r--r--wiki/src/doc/upgrade.de.po (renamed from wiki/src/doc/first_steps/upgrade.de.po)44
-rw-r--r--wiki/src/doc/upgrade.es.po (renamed from wiki/src/doc/first_steps/upgrade.es.po)54
-rw-r--r--wiki/src/doc/upgrade.fa.po (renamed from wiki/src/doc/first_steps/upgrade.fa.po)36
-rw-r--r--wiki/src/doc/upgrade.fr.po (renamed from wiki/src/doc/first_steps/upgrade.fr.po)33
-rw-r--r--wiki/src/doc/upgrade.id.po (renamed from wiki/src/doc/first_steps/upgrade.id.po)17
-rw-r--r--wiki/src/doc/upgrade.it.po (renamed from wiki/src/doc/first_steps/upgrade.it.po)37
-rw-r--r--wiki/src/doc/upgrade.mdwn (renamed from wiki/src/doc/first_steps/upgrade.mdwn)8
-rw-r--r--wiki/src/doc/upgrade.pl.po (renamed from wiki/src/doc/first_steps/upgrade.pl.po)17
-rw-r--r--wiki/src/doc/upgrade.pt.po (renamed from wiki/src/doc/first_steps/upgrade.pt.po)44
-rw-r--r--wiki/src/doc/upgrade.ru.po (renamed from wiki/src/doc/first_steps/upgrade.ru.po)17
-rw-r--r--wiki/src/doc/upgrade.sr_Latn.po (renamed from wiki/src/doc/first_steps/upgrade.sr_Latn.po)17
-rw-r--r--wiki/src/doc/upgrade.tr.po (renamed from wiki/src/doc/first_steps/upgrade.tr.po)17
-rw-r--r--wiki/src/doc/upgrade.zh.po (renamed from wiki/src/doc/first_steps/upgrade.zh.po)17
-rw-r--r--wiki/src/doc/upgrade.zh_TW.po (renamed from wiki/src/doc/first_steps/upgrade.zh_TW.po)18
-rw-r--r--wiki/src/doc/upgrade/error/install.ar.po44
-rw-r--r--wiki/src/doc/upgrade/error/install.ca.po40
-rw-r--r--wiki/src/doc/upgrade/error/install.de.po72
-rw-r--r--wiki/src/doc/upgrade/error/install.es.po68
-rw-r--r--wiki/src/doc/upgrade/error/install.fa.po41
-rw-r--r--wiki/src/doc/upgrade/error/install.fr.po64
-rw-r--r--wiki/src/doc/upgrade/error/install.id.po40
-rw-r--r--wiki/src/doc/upgrade/error/install.it.po74
-rw-r--r--wiki/src/doc/upgrade/error/install.mdwn23
-rw-r--r--wiki/src/doc/upgrade/error/install.pl.po40
-rw-r--r--wiki/src/doc/upgrade/error/install.pt.po72
-rw-r--r--wiki/src/doc/upgrade/error/install.ru.po44
-rw-r--r--wiki/src/doc/upgrade/error/install.sr_Latn.po51
-rw-r--r--wiki/src/doc/upgrade/error/install.tr.po40
-rw-r--r--wiki/src/doc/upgrade/error/install.zh.po40
-rw-r--r--wiki/src/doc/upgrade/error/install.zh_TW.po59
-rw-r--r--wiki/src/doc/upgrade/release_notes.ar.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.ar.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.ca.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.ca.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.de.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.de.po)0
-rwxr-xr-xwiki/src/doc/upgrade/release_notes.es.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.es.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.fa.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.fa.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.fr.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.fr.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.id.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.id.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.it.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.it.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.mdwn (renamed from wiki/src/doc/first_steps/upgrade/release_notes.mdwn)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.pl.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.pl.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.pt.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.pt.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.ru.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.ru.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.sr_Latn.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.sr_Latn.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.tr.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.tr.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.zh.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.zh.po)0
-rw-r--r--wiki/src/doc/upgrade/release_notes.zh_TW.po (renamed from wiki/src/doc/first_steps/upgrade/release_notes.zh_TW.po)0
-rw-r--r--wiki/src/doc/upgrade/repair.ar.po27
-rw-r--r--wiki/src/doc/upgrade/repair.ca.po27
-rw-r--r--wiki/src/doc/upgrade/repair.de.po29
-rw-r--r--wiki/src/doc/upgrade/repair.es.po29
-rw-r--r--wiki/src/doc/upgrade/repair.fa.po29
-rw-r--r--wiki/src/doc/upgrade/repair.fr.po29
-rw-r--r--wiki/src/doc/upgrade/repair.id.po27
-rw-r--r--wiki/src/doc/upgrade/repair.inline.ar.po56
-rw-r--r--wiki/src/doc/upgrade/repair.inline.ca.po56
-rw-r--r--wiki/src/doc/upgrade/repair.inline.de.po55
-rw-r--r--wiki/src/doc/upgrade/repair.inline.es.po55
-rw-r--r--wiki/src/doc/upgrade/repair.inline.fa.po55
-rw-r--r--wiki/src/doc/upgrade/repair.inline.fr.po55
-rw-r--r--wiki/src/doc/upgrade/repair.inline.id.po56
-rw-r--r--wiki/src/doc/upgrade/repair.inline.it.po55
-rw-r--r--wiki/src/doc/upgrade/repair.inline.mdwn16
-rw-r--r--wiki/src/doc/upgrade/repair.inline.pl.po56
-rw-r--r--wiki/src/doc/upgrade/repair.inline.pt.po55
-rw-r--r--wiki/src/doc/upgrade/repair.inline.ru.po56
-rw-r--r--wiki/src/doc/upgrade/repair.inline.sr_Latn.po56
-rw-r--r--wiki/src/doc/upgrade/repair.inline.tr.po56
-rw-r--r--wiki/src/doc/upgrade/repair.inline.zh.po56
-rw-r--r--wiki/src/doc/upgrade/repair.inline.zh_TW.po56
-rw-r--r--wiki/src/doc/upgrade/repair.it.po29
-rw-r--r--wiki/src/doc/upgrade/repair.mdwn3
-rw-r--r--wiki/src/doc/upgrade/repair.pl.po27
-rw-r--r--wiki/src/doc/upgrade/repair.pt.po29
-rw-r--r--wiki/src/doc/upgrade/repair.ru.po27
-rw-r--r--wiki/src/doc/upgrade/repair.sr_Latn.po27
-rw-r--r--wiki/src/doc/upgrade/repair.tr.po27
-rw-r--r--wiki/src/doc/upgrade/repair.zh.po27
-rw-r--r--wiki/src/doc/upgrade/repair.zh_TW.po27
-rw-r--r--wiki/src/doc/upgrade/upgrader_automatic.png (renamed from wiki/src/doc/first_steps/upgrade/upgrader_automatic.png)bin26167 -> 26167 bytes
-rw-r--r--wiki/src/doc/upgrade/upgrader_manual.png (renamed from wiki/src/doc/first_steps/upgrade/upgrader_manual.png)bin22171 -> 22171 bytes
-rw-r--r--wiki/src/donate.ar.po12
-rw-r--r--wiki/src/donate.ca.po12
-rw-r--r--wiki/src/donate.de.po17
-rw-r--r--wiki/src/donate.es.po17
-rw-r--r--wiki/src/donate.fa.po12
-rw-r--r--wiki/src/donate.fr.po172
-rw-r--r--wiki/src/donate.html2
-rw-r--r--wiki/src/donate.id.po12
-rw-r--r--wiki/src/donate.it.po17
-rw-r--r--wiki/src/donate.pl.po12
-rw-r--r--wiki/src/donate.pt.po17
-rw-r--r--wiki/src/donate.ru.po12
-rw-r--r--wiki/src/donate.sr_Latn.po12
-rw-r--r--wiki/src/donate.tr.po12
-rw-r--r--wiki/src/donate.zh.po13
-rw-r--r--wiki/src/donate.zh_TW.po13
-rw-r--r--wiki/src/donate/thanks.ar.po11
-rw-r--r--wiki/src/donate/thanks.ca.po11
-rw-r--r--wiki/src/donate/thanks.de.po80
-rw-r--r--wiki/src/donate/thanks.es.po80
-rw-r--r--wiki/src/donate/thanks.fa.po41
-rw-r--r--wiki/src/donate/thanks.fr.po54
-rw-r--r--wiki/src/donate/thanks.html2
-rw-r--r--wiki/src/donate/thanks.id.po11
-rw-r--r--wiki/src/donate/thanks.it.po79
-rw-r--r--wiki/src/donate/thanks.pl.po11
-rw-r--r--wiki/src/donate/thanks.pt.po41
-rw-r--r--wiki/src/donate/thanks.ru.po11
-rw-r--r--wiki/src/donate/thanks.sr_Latn.po11
-rw-r--r--wiki/src/donate/thanks.tr.po11
-rw-r--r--wiki/src/donate/thanks.zh.po11
-rw-r--r--wiki/src/donate/thanks.zh_TW.po12
-rw-r--r--wiki/src/home.ar.po11
-rw-r--r--wiki/src/home.ca.po11
-rw-r--r--wiki/src/home.de.po16
-rw-r--r--wiki/src/home.es.po20
-rw-r--r--wiki/src/home.fa.po11
-rw-r--r--wiki/src/home.fr.po21
-rw-r--r--wiki/src/home.html4
-rw-r--r--wiki/src/home.id.po11
-rw-r--r--wiki/src/home.it.po11
-rw-r--r--wiki/src/home.pl.po11
-rw-r--r--wiki/src/home.pt.po11
-rw-r--r--wiki/src/home.ru.po11
-rw-r--r--wiki/src/home.sr_Latn.po11
-rw-r--r--wiki/src/home.tr.po11
-rw-r--r--wiki/src/home.zh.po11
-rw-r--r--wiki/src/home.zh_TW.po11
-rw-r--r--wiki/src/home/testing.ar.po11
-rw-r--r--wiki/src/home/testing.ca.po11
-rw-r--r--wiki/src/home/testing.de.po11
-rw-r--r--wiki/src/home/testing.es.po11
-rw-r--r--wiki/src/home/testing.fa.po11
-rw-r--r--wiki/src/home/testing.fr.po11
-rw-r--r--wiki/src/home/testing.html4
-rw-r--r--wiki/src/home/testing.id.po11
-rw-r--r--wiki/src/home/testing.it.po11
-rw-r--r--wiki/src/home/testing.pl.po11
-rw-r--r--wiki/src/home/testing.pt.po11
-rw-r--r--wiki/src/home/testing.ru.po11
-rw-r--r--wiki/src/home/testing.sr_Latn.po11
-rw-r--r--wiki/src/home/testing.tr.po11
-rw-r--r--wiki/src/home/testing.zh.po11
-rw-r--r--wiki/src/home/testing.zh_TW.po11
-rw-r--r--wiki/src/index.ar.po16
-rw-r--r--wiki/src/index.ca.po16
-rw-r--r--wiki/src/index.de.po30
-rw-r--r--wiki/src/index.es.po32
-rw-r--r--wiki/src/index.fa.po39
-rw-r--r--wiki/src/index.fr.po39
-rw-r--r--wiki/src/index.html5
-rw-r--r--wiki/src/index.id.po16
-rw-r--r--wiki/src/index.it.po28
-rw-r--r--wiki/src/index.pl.po16
-rw-r--r--wiki/src/index.pt.po28
-rw-r--r--wiki/src/index.ru.po16
-rw-r--r--wiki/src/index.sr_Latn.po16
-rw-r--r--wiki/src/index.tr.po16
-rw-r--r--wiki/src/index.zh.po16
-rw-r--r--wiki/src/index.zh_TW.po16
-rw-r--r--wiki/src/install/expert/usb-overview.ar.po21
-rw-r--r--wiki/src/install/expert/usb-overview.ca.po21
-rw-r--r--wiki/src/install/expert/usb-overview.de.po29
-rw-r--r--wiki/src/install/expert/usb-overview.es.po41
-rw-r--r--wiki/src/install/expert/usb-overview.fa.po19
-rw-r--r--wiki/src/install/expert/usb-overview.fr.po29
-rw-r--r--wiki/src/install/expert/usb-overview.html2
-rw-r--r--wiki/src/install/expert/usb-overview.id.po19
-rw-r--r--wiki/src/install/expert/usb-overview.it.po40
-rw-r--r--wiki/src/install/expert/usb-overview.pl.po21
-rw-r--r--wiki/src/install/expert/usb-overview.pt.po19
-rw-r--r--wiki/src/install/expert/usb-overview.ru.po21
-rw-r--r--wiki/src/install/expert/usb-overview.sr_Latn.po24
-rw-r--r--wiki/src/install/expert/usb-overview.tr.po21
-rw-r--r--wiki/src/install/expert/usb-overview.zh.po19
-rw-r--r--wiki/src/install/expert/usb-overview.zh_TW.po19
-rw-r--r--wiki/src/install/expert/usb.fr.po10
-rw-r--r--wiki/src/install/inc/steps/create_persistence.inline.fr.po14
-rw-r--r--wiki/src/install/inc/steps/download.inline.ar.po8
-rw-r--r--wiki/src/install/inc/steps/download.inline.ca.po8
-rw-r--r--wiki/src/install/inc/steps/download.inline.de.po12
-rw-r--r--wiki/src/install/inc/steps/download.inline.es.po152
-rw-r--r--wiki/src/install/inc/steps/download.inline.fa.po8
-rw-r--r--wiki/src/install/inc/steps/download.inline.fr.po30
-rw-r--r--wiki/src/install/inc/steps/download.inline.html4
-rw-r--r--wiki/src/install/inc/steps/download.inline.id.po8
-rw-r--r--wiki/src/install/inc/steps/download.inline.it.po12
-rw-r--r--wiki/src/install/inc/steps/download.inline.pl.po8
-rw-r--r--wiki/src/install/inc/steps/download.inline.pt.po8
-rw-r--r--wiki/src/install/inc/steps/download.inline.ru.po8
-rw-r--r--wiki/src/install/inc/steps/download.inline.sr_Latn.po8
-rw-r--r--wiki/src/install/inc/steps/download.inline.tr.po8
-rw-r--r--wiki/src/install/inc/steps/download.inline.zh.po8
-rw-r--r--wiki/src/install/inc/steps/download.inline.zh_TW.po9
-rw-r--r--wiki/src/install/inc/steps/install_with_etcher.inline.fr.po12
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.ar.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.ca.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.de.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.es.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.fa.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.fr.po47
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.html2
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.id.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.it.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.pl.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.pt.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.ru.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.sr_Latn.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.tr.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.zh.po4
-rw-r--r--wiki/src/install/inc/steps/pc_boot_menu.inline.zh_TW.po4
-rw-r--r--wiki/src/install/inc/steps/reporting.inline.fr.po11
-rw-r--r--wiki/src/install/inc/steps/restart_first_time.inline.es.po12
-rw-r--r--wiki/src/install/inc/steps/restart_first_time.inline.fr.po47
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.ar.po19
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.ca.po19
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.de.po17
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.es.po27
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.fa.po17
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.fr.po27
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.id.po17
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.it.po17
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.mdwn15
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.pl.po19
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.pt.po17
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.ru.po19
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.sr_Latn.po19
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.tr.po19
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.zh.po19
-rw-r--r--wiki/src/install/inc/steps/verify_up-to-date.inline.zh_TW.po34
-rw-r--r--wiki/src/install/linux.ar.po14
-rw-r--r--wiki/src/install/linux.ca.po14
-rw-r--r--wiki/src/install/linux.de.po14
-rw-r--r--wiki/src/install/linux.es.po22
-rw-r--r--wiki/src/install/linux.fa.po14
-rw-r--r--wiki/src/install/linux.fr.po20
-rw-r--r--wiki/src/install/linux.html2
-rw-r--r--wiki/src/install/linux.id.po14
-rw-r--r--wiki/src/install/linux.it.po14
-rw-r--r--wiki/src/install/linux.pl.po14
-rw-r--r--wiki/src/install/linux.pt.po14
-rw-r--r--wiki/src/install/linux.ru.po14
-rw-r--r--wiki/src/install/linux.sr_Latn.po14
-rw-r--r--wiki/src/install/linux.tr.po14
-rw-r--r--wiki/src/install/linux.zh.po14
-rw-r--r--wiki/src/install/linux.zh_TW.po14
-rw-r--r--wiki/src/install/linux/clone-overview.ar.po21
-rw-r--r--wiki/src/install/linux/clone-overview.ca.po21
-rw-r--r--wiki/src/install/linux/clone-overview.de.po28
-rwxr-xr-xwiki/src/install/linux/clone-overview.es.po36
-rw-r--r--wiki/src/install/linux/clone-overview.fa.po19
-rw-r--r--wiki/src/install/linux/clone-overview.fr.po28
-rw-r--r--wiki/src/install/linux/clone-overview.html2
-rw-r--r--wiki/src/install/linux/clone-overview.id.po19
-rw-r--r--wiki/src/install/linux/clone-overview.it.po36
-rw-r--r--wiki/src/install/linux/clone-overview.pl.po21
-rw-r--r--wiki/src/install/linux/clone-overview.pt.po19
-rw-r--r--wiki/src/install/linux/clone-overview.ru.po21
-rw-r--r--wiki/src/install/linux/clone-overview.sr_Latn.po21
-rw-r--r--wiki/src/install/linux/clone-overview.tr.po21
-rw-r--r--wiki/src/install/linux/clone-overview.zh.po19
-rw-r--r--wiki/src/install/linux/clone-overview.zh_TW.po19
-rw-r--r--wiki/src/install/linux/usb-overview.ar.po20
-rw-r--r--wiki/src/install/linux/usb-overview.ca.po20
-rw-r--r--wiki/src/install/linux/usb-overview.de.po27
-rw-r--r--wiki/src/install/linux/usb-overview.es.po31
-rw-r--r--wiki/src/install/linux/usb-overview.fa.po31
-rw-r--r--wiki/src/install/linux/usb-overview.fr.po27
-rw-r--r--wiki/src/install/linux/usb-overview.html2
-rw-r--r--wiki/src/install/linux/usb-overview.id.po18
-rw-r--r--wiki/src/install/linux/usb-overview.it.po33
-rw-r--r--wiki/src/install/linux/usb-overview.pl.po20
-rw-r--r--wiki/src/install/linux/usb-overview.pt.po18
-rw-r--r--wiki/src/install/linux/usb-overview.ru.po20
-rw-r--r--wiki/src/install/linux/usb-overview.sr_Latn.po21
-rw-r--r--wiki/src/install/linux/usb-overview.tr.po20
-rw-r--r--wiki/src/install/linux/usb-overview.zh.po18
-rw-r--r--wiki/src/install/linux/usb-overview.zh_TW.po18
-rw-r--r--wiki/src/install/mac.ar.po12
-rw-r--r--wiki/src/install/mac.ca.po12
-rw-r--r--wiki/src/install/mac.de.po12
-rw-r--r--wiki/src/install/mac.es.po19
-rw-r--r--wiki/src/install/mac.fa.po12
-rw-r--r--wiki/src/install/mac.fr.po29
-rw-r--r--wiki/src/install/mac.html2
-rw-r--r--wiki/src/install/mac.id.po12
-rw-r--r--wiki/src/install/mac.it.po12
-rw-r--r--wiki/src/install/mac.pl.po12
-rw-r--r--wiki/src/install/mac.pt.po12
-rw-r--r--wiki/src/install/mac.ru.po16
-rw-r--r--wiki/src/install/mac.sr_Latn.po12
-rw-r--r--wiki/src/install/mac.tr.po12
-rw-r--r--wiki/src/install/mac.zh.po12
-rw-r--r--wiki/src/install/mac.zh_TW.po16
-rw-r--r--wiki/src/install/mac/clone-overview.ar.po18
-rw-r--r--wiki/src/install/mac/clone-overview.ca.po18
-rw-r--r--wiki/src/install/mac/clone-overview.de.po28
-rw-r--r--wiki/src/install/mac/clone-overview.es.po36
-rw-r--r--wiki/src/install/mac/clone-overview.fa.po19
-rw-r--r--wiki/src/install/mac/clone-overview.fr.po28
-rw-r--r--wiki/src/install/mac/clone-overview.html2
-rw-r--r--wiki/src/install/mac/clone-overview.id.po18
-rw-r--r--wiki/src/install/mac/clone-overview.it.po33
-rw-r--r--wiki/src/install/mac/clone-overview.pl.po18
-rw-r--r--wiki/src/install/mac/clone-overview.pt.po19
-rw-r--r--wiki/src/install/mac/clone-overview.ru.po18
-rw-r--r--wiki/src/install/mac/clone-overview.sr_Latn.po18
-rw-r--r--wiki/src/install/mac/clone-overview.tr.po18
-rw-r--r--wiki/src/install/mac/clone-overview.zh.po18
-rw-r--r--wiki/src/install/mac/clone-overview.zh_TW.po18
-rw-r--r--wiki/src/install/mac/usb-overview.ar.po18
-rw-r--r--wiki/src/install/mac/usb-overview.ca.po18
-rw-r--r--wiki/src/install/mac/usb-overview.de.po18
-rw-r--r--wiki/src/install/mac/usb-overview.es.po38
-rw-r--r--wiki/src/install/mac/usb-overview.fa.po18
-rw-r--r--wiki/src/install/mac/usb-overview.fr.po27
-rw-r--r--wiki/src/install/mac/usb-overview.html2
-rw-r--r--wiki/src/install/mac/usb-overview.id.po18
-rw-r--r--wiki/src/install/mac/usb-overview.it.po18
-rw-r--r--wiki/src/install/mac/usb-overview.pl.po18
-rw-r--r--wiki/src/install/mac/usb-overview.pt.po18
-rw-r--r--wiki/src/install/mac/usb-overview.ru.po18
-rw-r--r--wiki/src/install/mac/usb-overview.sr_Latn.po18
-rw-r--r--wiki/src/install/mac/usb-overview.tr.po18
-rw-r--r--wiki/src/install/mac/usb-overview.zh.po18
-rw-r--r--wiki/src/install/mac/usb-overview.zh_TW.po18
-rw-r--r--wiki/src/install/mac/usb.es.po11
-rw-r--r--wiki/src/install/mac/usb.fr.po20
-rw-r--r--wiki/src/install/win.ar.po14
-rw-r--r--wiki/src/install/win.ca.po14
-rw-r--r--wiki/src/install/win.de.po21
-rw-r--r--wiki/src/install/win.es.po21
-rw-r--r--wiki/src/install/win.fa.po14
-rw-r--r--wiki/src/install/win.fr.po21
-rw-r--r--wiki/src/install/win.html2
-rw-r--r--wiki/src/install/win.id.po14
-rw-r--r--wiki/src/install/win.it.po21
-rw-r--r--wiki/src/install/win.pl.po14
-rw-r--r--wiki/src/install/win.pt.po14
-rw-r--r--wiki/src/install/win.ru.po14
-rw-r--r--wiki/src/install/win.sr_Latn.po14
-rw-r--r--wiki/src/install/win.tr.po14
-rw-r--r--wiki/src/install/win.zh.po14
-rw-r--r--wiki/src/install/win.zh_TW.po14
-rw-r--r--wiki/src/install/win/clone-overview.ar.po21
-rw-r--r--wiki/src/install/win/clone-overview.ca.po21
-rw-r--r--wiki/src/install/win/clone-overview.de.po28
-rw-r--r--wiki/src/install/win/clone-overview.es.po36
-rw-r--r--wiki/src/install/win/clone-overview.fa.po19
-rw-r--r--wiki/src/install/win/clone-overview.fr.po28
-rw-r--r--wiki/src/install/win/clone-overview.html2
-rw-r--r--wiki/src/install/win/clone-overview.id.po19
-rw-r--r--wiki/src/install/win/clone-overview.it.po36
-rw-r--r--wiki/src/install/win/clone-overview.pl.po21
-rw-r--r--wiki/src/install/win/clone-overview.pt.po19
-rw-r--r--wiki/src/install/win/clone-overview.ru.po21
-rw-r--r--wiki/src/install/win/clone-overview.sr_Latn.po21
-rw-r--r--wiki/src/install/win/clone-overview.tr.po21
-rw-r--r--wiki/src/install/win/clone-overview.zh.po19
-rw-r--r--wiki/src/install/win/clone-overview.zh_TW.po19
-rw-r--r--wiki/src/install/win/usb-overview.ar.po20
-rw-r--r--wiki/src/install/win/usb-overview.ca.po20
-rw-r--r--wiki/src/install/win/usb-overview.de.po27
-rwxr-xr-xwiki/src/install/win/usb-overview.es.po32
-rw-r--r--wiki/src/install/win/usb-overview.fa.po18
-rw-r--r--wiki/src/install/win/usb-overview.fr.po27
-rw-r--r--wiki/src/install/win/usb-overview.html2
-rw-r--r--wiki/src/install/win/usb-overview.id.po18
-rw-r--r--wiki/src/install/win/usb-overview.it.po36
-rw-r--r--wiki/src/install/win/usb-overview.pl.po18
-rw-r--r--wiki/src/install/win/usb-overview.pt.po18
-rw-r--r--wiki/src/install/win/usb-overview.ru.po22
-rw-r--r--wiki/src/install/win/usb-overview.sr_Latn.po23
-rw-r--r--wiki/src/install/win/usb-overview.tr.po20
-rw-r--r--wiki/src/install/win/usb-overview.zh.po18
-rw-r--r--wiki/src/install/win/usb-overview.zh_TW.po18
-rw-r--r--wiki/src/jobs.mdwn10
-rw-r--r--wiki/src/jobs/about_tails.html (renamed from wiki/src/jobs/about-tails.html)5
-rw-r--r--wiki/src/jobs/apply.mdwn10
-rw-r--r--wiki/src/jobs/illustration-how-tails-work.mdwn257
-rw-r--r--wiki/src/jobs/illustrations_how_tails_work.mdwn258
-rw-r--r--wiki/src/jobs/technical_writer.mdwn (renamed from wiki/src/jobs/technical-writer.mdwn)0
-rw-r--r--wiki/src/lib/design/git_repository_details.svg587
-rw-r--r--wiki/src/local.css9
-rw-r--r--wiki/src/misc/unsafe_browser_warning.ar.po4
-rw-r--r--wiki/src/misc/unsafe_browser_warning.ca.po4
-rw-r--r--wiki/src/misc/unsafe_browser_warning.de.po14
-rw-r--r--wiki/src/misc/unsafe_browser_warning.es.po14
-rw-r--r--wiki/src/misc/unsafe_browser_warning.fa.po18
-rw-r--r--wiki/src/misc/unsafe_browser_warning.fr.po50
-rw-r--r--wiki/src/misc/unsafe_browser_warning.html3
-rw-r--r--wiki/src/misc/unsafe_browser_warning.id.po4
-rw-r--r--wiki/src/misc/unsafe_browser_warning.it.po14
-rw-r--r--wiki/src/misc/unsafe_browser_warning.pl.po4
-rw-r--r--wiki/src/misc/unsafe_browser_warning.pt.po8
-rw-r--r--wiki/src/misc/unsafe_browser_warning.ru.po4
-rw-r--r--wiki/src/misc/unsafe_browser_warning.sr_Latn.po4
-rw-r--r--wiki/src/misc/unsafe_browser_warning.tr.po4
-rw-r--r--wiki/src/misc/unsafe_browser_warning.zh.po4
-rw-r--r--wiki/src/misc/unsafe_browser_warning.zh_TW.po4
-rw-r--r--wiki/src/news.ar.po4
-rw-r--r--wiki/src/news.ca.po4
-rw-r--r--wiki/src/news.de.po4
-rw-r--r--wiki/src/news.es.po4
-rw-r--r--wiki/src/news.fa.po4
-rw-r--r--wiki/src/news.fr.po4
-rw-r--r--wiki/src/news.html2
-rw-r--r--wiki/src/news.id.po4
-rw-r--r--wiki/src/news.it.po4
-rw-r--r--wiki/src/news.pl.po4
-rw-r--r--wiki/src/news.pt.po4
-rw-r--r--wiki/src/news.ru.po4
-rw-r--r--wiki/src/news.sr_Latn.po4
-rw-r--r--wiki/src/news.tr.po4
-rw-r--r--wiki/src/news.zh.po4
-rw-r--r--wiki/src/news.zh_TW.po4
-rw-r--r--wiki/src/news/Mac_and_PC_UEFI_hardware_needed.fr.po8
-rw-r--r--wiki/src/news/Tails_HackFest_2014.fr.po9
-rw-r--r--wiki/src/news/additional_software_ux_design.fr.po9
-rw-r--r--wiki/src/news/and_the_winner_is.fr.po11
-rw-r--r--wiki/src/news/duckduckgo_challenge.ar.po10
-rw-r--r--wiki/src/news/duckduckgo_challenge.ca.po10
-rw-r--r--wiki/src/news/duckduckgo_challenge.de.po22
-rw-r--r--wiki/src/news/duckduckgo_challenge.es.po10
-rw-r--r--wiki/src/news/duckduckgo_challenge.fa.po10
-rw-r--r--wiki/src/news/duckduckgo_challenge.fr.po22
-rw-r--r--wiki/src/news/duckduckgo_challenge.id.po10
-rw-r--r--wiki/src/news/duckduckgo_challenge.it.po10
-rw-r--r--wiki/src/news/duckduckgo_challenge.mdwn4
-rw-r--r--wiki/src/news/duckduckgo_challenge.pl.po10
-rw-r--r--wiki/src/news/duckduckgo_challenge.pt.po10
-rw-r--r--wiki/src/news/duckduckgo_challenge.ru.po14
-rw-r--r--wiki/src/news/duckduckgo_challenge.sr_Latn.po13
-rw-r--r--wiki/src/news/duckduckgo_challenge.tr.po10
-rw-r--r--wiki/src/news/duckduckgo_challenge.zh.po10
-rw-r--r--wiki/src/news/duckduckgo_challenge.zh_TW.po10
-rw-r--r--wiki/src/news/fpf_campaign.fr.po9
-rw-r--r--wiki/src/news/improve_the_infrastructure_behind_Tails.fr.po9
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.ar.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.ca.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.de.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.es.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.fa.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.fr.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.id.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.it.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.mdwn25
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.pl.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.pt.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.ru.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.sr_Latn.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.tr.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.zh.po80
-rw-r--r--wiki/src/news/job_illustrations_how_tails_work.zh_TW.po80
-rw-r--r--wiki/src/news/logo_contest.fr.po9
-rw-r--r--wiki/src/news/new_SSL_certificate.fr.po9
-rw-r--r--wiki/src/news/new_project_name.fr.po9
-rw-r--r--wiki/src/news/report_2014_06-07.mdwn2
-rw-r--r--wiki/src/news/report_2015_05.mdwn2
-rw-r--r--wiki/src/news/report_2015_07.mdwn2
-rw-r--r--wiki/src/news/report_2016_03.mdwn2
-rw-r--r--wiki/src/news/tails-testers.fr.po9
-rw-r--r--wiki/src/news/test_1.1-rc1.mdwn2
-rw-r--r--wiki/src/news/test_UEFI.mdwn2
-rw-r--r--wiki/src/news/thedaywefightback.fr.po8
-rw-r--r--wiki/src/news/veracrypt_ux_design.fr.po9
-rw-r--r--wiki/src/news/version_1.0.1.mdwn2
-rw-r--r--wiki/src/news/version_1.0.mdwn4
-rw-r--r--wiki/src/news/version_1.1.1.mdwn2
-rw-r--r--wiki/src/news/version_1.1.2.mdwn2
-rw-r--r--wiki/src/news/version_1.1.mdwn4
-rw-r--r--wiki/src/news/version_1.2.1.mdwn2
-rw-r--r--wiki/src/news/version_1.2.2.mdwn2
-rw-r--r--wiki/src/news/version_1.2.3.mdwn2
-rw-r--r--wiki/src/news/version_1.2.mdwn2
-rw-r--r--wiki/src/news/version_1.3.1.mdwn2
-rw-r--r--wiki/src/news/version_1.3.2.mdwn2
-rw-r--r--wiki/src/news/version_1.3.mdwn2
-rw-r--r--wiki/src/news/version_1.4.1.mdwn2
-rw-r--r--wiki/src/news/version_1.4.mdwn2
-rw-r--r--wiki/src/news/version_1.5.1.mdwn2
-rw-r--r--wiki/src/news/version_1.5.mdwn2
-rw-r--r--wiki/src/news/version_1.6.mdwn6
-rw-r--r--wiki/src/news/version_1.7.mdwn4
-rw-r--r--wiki/src/news/version_1.8.1.mdwn4
-rw-r--r--wiki/src/news/version_1.8.2.mdwn4
-rw-r--r--wiki/src/news/version_1.8.mdwn4
-rw-r--r--wiki/src/news/version_2.0.1.mdwn4
-rw-r--r--wiki/src/news/version_2.2.1.mdwn4
-rw-r--r--wiki/src/news/version_2.2.mdwn2
-rw-r--r--wiki/src/news/version_3.13.1.fr.po2
-rw-r--r--wiki/src/news/version_3.13.ar.po4
-rw-r--r--wiki/src/news/version_3.13.ca.po4
-rw-r--r--wiki/src/news/version_3.13.de.po2
-rw-r--r--wiki/src/news/version_3.13.es.po2
-rw-r--r--wiki/src/news/version_3.13.fa.po2
-rw-r--r--wiki/src/news/version_3.13.fr.po4
-rw-r--r--wiki/src/news/version_3.13.id.po2
-rw-r--r--wiki/src/news/version_3.13.it.po2
-rw-r--r--wiki/src/news/version_3.13.mdwn2
-rw-r--r--wiki/src/news/version_3.13.pl.po2
-rw-r--r--wiki/src/news/version_3.13.pt.po2
-rw-r--r--wiki/src/news/version_3.13.ru.po2
-rw-r--r--wiki/src/news/version_3.13.sr_Latn.po2
-rw-r--r--wiki/src/news/version_3.13.tr.po2
-rw-r--r--wiki/src/news/version_3.13.zh.po2
-rw-r--r--wiki/src/news/version_3.13.zh_TW.po2
-rw-r--r--wiki/src/news/version_3.16.fr.po4
-rw-r--r--wiki/src/news/version_3.9.fr.po11
-rw-r--r--wiki/src/news/who_are_you_helping.fr.po21
-rw-r--r--wiki/src/partners.fr.po22
-rw-r--r--wiki/src/recentchanges.mdwn2
-rw-r--r--wiki/src/security/Iceweasel_exposes_a_rare_User-Agent.fr.po6
-rw-r--r--wiki/src/security/Security_hole_in_I2P_0.9.13.fr.po6
-rw-r--r--wiki/src/security/use_of_untrusted_Live_system_found_on_local_hard-disk.fr.po4
-rw-r--r--wiki/src/sidebar.ar.po4
-rw-r--r--wiki/src/sidebar.ca.po4
-rw-r--r--wiki/src/sidebar.de.po4
-rw-r--r--wiki/src/sidebar.es.po8
-rw-r--r--wiki/src/sidebar.fa.po4
-rw-r--r--wiki/src/sidebar.fr.po22
-rw-r--r--wiki/src/sidebar.id.po4
-rw-r--r--wiki/src/sidebar.it.po4
-rw-r--r--wiki/src/sidebar.mdwn2
-rw-r--r--wiki/src/sidebar.pl.po4
-rw-r--r--wiki/src/sidebar.pt.po4
-rw-r--r--wiki/src/sidebar.ru.po4
-rw-r--r--wiki/src/sidebar.sr_Latn.po4
-rw-r--r--wiki/src/sidebar.tr.po4
-rw-r--r--wiki/src/sidebar.zh.po4
-rw-r--r--wiki/src/sidebar.zh_TW.po4
-rw-r--r--wiki/src/support.ar.po6
-rw-r--r--wiki/src/support.ca.po6
-rw-r--r--wiki/src/support.de.po10
-rw-r--r--wiki/src/support.es.po12
-rw-r--r--wiki/src/support.fa.po14
-rw-r--r--wiki/src/support.fr.po23
-rw-r--r--wiki/src/support.id.po6
-rw-r--r--wiki/src/support.it.po10
-rw-r--r--wiki/src/support.mdwn2
-rw-r--r--wiki/src/support.pl.po6
-rw-r--r--wiki/src/support.pt.po10
-rw-r--r--wiki/src/support.ru.po6
-rw-r--r--wiki/src/support.sr_Latn.po6
-rw-r--r--wiki/src/support.tr.po6
-rw-r--r--wiki/src/support.zh.po9
-rw-r--r--wiki/src/support.zh_TW.po9
-rw-r--r--wiki/src/support/faq.ar.po14
-rw-r--r--wiki/src/support/faq.ca.po14
-rw-r--r--wiki/src/support/faq.de.po14
-rw-r--r--wiki/src/support/faq.es.po41
-rw-r--r--wiki/src/support/faq.fa.po26
-rw-r--r--wiki/src/support/faq.fr.po117
-rw-r--r--wiki/src/support/faq.id.po14
-rw-r--r--wiki/src/support/faq.it.po33
-rw-r--r--wiki/src/support/faq.mdwn6
-rw-r--r--wiki/src/support/faq.pl.po14
-rw-r--r--wiki/src/support/faq.pt.po22
-rw-r--r--wiki/src/support/faq.ru.po14
-rw-r--r--wiki/src/support/faq.sr_Latn.po14
-rw-r--r--wiki/src/support/faq.tr.po14
-rw-r--r--wiki/src/support/faq.zh.po14
-rw-r--r--wiki/src/support/faq.zh_TW.po14
-rw-r--r--wiki/src/support/known_issues.fr.po22
-rw-r--r--wiki/src/support/known_issues.pt.po2
-rw-r--r--wiki/src/support/known_issues/graphics.fr.po111
-rw-r--r--wiki/src/tails-translations.key79
-rw-r--r--wiki/src/torrents.fr.po4
-rw-r--r--wiki/src/upgrade.ar.po13
-rw-r--r--wiki/src/upgrade.ca.po13
-rw-r--r--wiki/src/upgrade.de.po29
-rw-r--r--wiki/src/upgrade.es.po24
-rw-r--r--wiki/src/upgrade.fa.po13
-rw-r--r--wiki/src/upgrade.fr.po28
-rw-r--r--wiki/src/upgrade.html2
-rw-r--r--wiki/src/upgrade.id.po13
-rw-r--r--wiki/src/upgrade.it.po29
-rw-r--r--wiki/src/upgrade.pl.po13
-rw-r--r--wiki/src/upgrade.pt.po22
-rw-r--r--wiki/src/upgrade.ru.po13
-rw-r--r--wiki/src/upgrade.sr_Latn.po13
-rw-r--r--wiki/src/upgrade.tr.po13
-rw-r--r--wiki/src/upgrade.zh.po13
-rw-r--r--wiki/src/upgrade.zh_TW.po13
-rw-r--r--wiki/src/upgrade/clone-overview.ar.po19
-rw-r--r--wiki/src/upgrade/clone-overview.ca.po19
-rw-r--r--wiki/src/upgrade/clone-overview.de.po31
-rw-r--r--wiki/src/upgrade/clone-overview.es.po31
-rw-r--r--wiki/src/upgrade/clone-overview.fa.po17
-rw-r--r--wiki/src/upgrade/clone-overview.fr.po26
-rw-r--r--wiki/src/upgrade/clone-overview.html2
-rw-r--r--wiki/src/upgrade/clone-overview.id.po17
-rw-r--r--wiki/src/upgrade/clone-overview.it.po37
-rw-r--r--wiki/src/upgrade/clone-overview.pl.po19
-rw-r--r--wiki/src/upgrade/clone-overview.pt.po22
-rw-r--r--wiki/src/upgrade/clone-overview.ru.po19
-rw-r--r--wiki/src/upgrade/clone-overview.sr_Latn.po19
-rw-r--r--wiki/src/upgrade/clone-overview.tr.po19
-rw-r--r--wiki/src/upgrade/clone-overview.zh.po17
-rw-r--r--wiki/src/upgrade/clone-overview.zh_TW.po17
-rw-r--r--wiki/src/upgrade/tails-overview.ar.po17
-rw-r--r--wiki/src/upgrade/tails-overview.ca.po17
-rw-r--r--wiki/src/upgrade/tails-overview.de.po17
-rw-r--r--wiki/src/upgrade/tails-overview.es.po30
-rw-r--r--wiki/src/upgrade/tails-overview.fa.po17
-rw-r--r--wiki/src/upgrade/tails-overview.fr.po26
-rw-r--r--wiki/src/upgrade/tails-overview.html2
-rw-r--r--wiki/src/upgrade/tails-overview.id.po17
-rw-r--r--wiki/src/upgrade/tails-overview.it.po17
-rw-r--r--wiki/src/upgrade/tails-overview.pl.po17
-rw-r--r--wiki/src/upgrade/tails-overview.pt.po17
-rw-r--r--wiki/src/upgrade/tails-overview.ru.po17
-rw-r--r--wiki/src/upgrade/tails-overview.sr_Latn.po17
-rw-r--r--wiki/src/upgrade/tails-overview.tr.po17
-rw-r--r--wiki/src/upgrade/tails-overview.zh.po17
-rw-r--r--wiki/src/upgrade/tails-overview.zh_TW.po17
1113 files changed, 25733 insertions, 29153 deletions
diff --git a/.gitignore b/.gitignore
index 4c144db..3f91291 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,6 +30,8 @@
/config/chroot_local-includes/usr/share/doc/amnesia/Changelog
/config/chroot_local-includes/usr/share/doc/tails/website
/config/chroot_local-includes/usr/share/tails/build/variables
+/config/chroot_local-includes/usr/share/tails/greeter/supported_languages
+/config/chroot_local-includes/usr/share/tails/greeter/supported_locales
/.lock
/.stage
/source
@@ -57,6 +59,7 @@
/config/chroot_local-includes/usr/share/desktop-directories/Tails.directory
/config/chroot_local-includes/usr/share/polkit-1/actions/org.boum.tails.root-terminal.policy
/config/chroot_local-includes/usr/share/polkit-1/actions/org.boum.tails.additional-software.policy
+/config/chroot_local-includes/usr/share/tails/greeter/*.ui
/config/chroot_local-includes/usr/share/tails/unlock-veracrypt-volumes/*.ui
/tmp/
diff --git a/auto/build b/auto/build
index bfed3a6..d6cd96e 100755
--- a/auto/build
+++ b/auto/build
@@ -117,6 +117,9 @@ export MKSQUASHFS_OPTIONS
# refresh translations of our programs
./refresh-translations || fatal "refresh-translations failed ($?)."
+# generate list of supported languages
+./generate-languages-list || fatal "generate-languages-list failed ($?)."
+
BUILD_ISO_FILENAME="${BUILD_BASENAME}.iso"
BUILD_MANIFEST="${BUILD_BASENAME}.build-manifest"
BUILD_APT_SOURCES="${BUILD_BASENAME}.apt-sources"
diff --git a/auto/config b/auto/config
index 2b0a177..fd7f6c8 100755
--- a/auto/config
+++ b/auto/config
@@ -155,7 +155,6 @@ $RUN_LB_CONFIG \
--packages-lists none \
--tasks none \
--linux-packages="linux-image-${KERNEL_VERSION}" \
- --security false \
--syslinux-menu vesamenu \
--syslinux-splash data/splash.png \
--syslinux-timeout 4 \
diff --git a/config/APT_overlays.d/bugfix-17110-whisperback-drop-tls b/config/APT_overlays.d/bugfix-17110-whisperback-drop-tls
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/config/APT_overlays.d/bugfix-17110-whisperback-drop-tls
diff --git a/config/amnesia b/config/amnesia
index e0d2885..5cb1a7c 100644
--- a/config/amnesia
+++ b/config/amnesia
@@ -23,7 +23,7 @@ AMNESIA_APPEND="live-media=removable nopersistence noprompt timezone=Etc/UTC blo
AMNESIA_ISOHYBRID_OPTS="-h 255 -s 63 --id 42 --verbose"
# Kernel version
-KERNEL_VERSION='5.2.0-3'
+KERNEL_VERSION='5.3.0-trunk'
KERNEL_SOURCE_VERSION=$(
echo "$KERNEL_VERSION" \
| perl -p -E 's{\A (\d+ [.] \d+) [.] .*}{$1}xms'
diff --git a/config/chroot_apt/preferences b/config/chroot_apt/preferences
index 771fee2..7d1665e 100644
--- a/config/chroot_apt/preferences
+++ b/config/chroot_apt/preferences
@@ -10,9 +10,9 @@ Package: b43-fwcutter
Pin: release o=Debian,n=sid
Pin-Priority: 999
-Explanation: unavailable in Buster, version in sid is intentionally broken (Debian#928518)
-Package: electrum python3-electrum
-Pin: origin deb.tails.boum.org
+Explanation: unavailable in Buster
+Package: electrum python3-electrum python3-aiohttp-socks python3-aiorpcx
+Pin: release o=Debian,n=sid
Pin-Priority: 999
Package: enigmail
@@ -41,7 +41,7 @@ Pin: release o=Debian,n=sid
Pin-Priority: 999
Package: linux-compiler-* linux-headers-* linux-image-* linux-kbuild-* linux-source-*
-Pin: release o=Debian,n=sid
+Pin: release o=Debian,n=experimental
Pin-Priority: 999
Explanation: src:live-boot (#15477)
diff --git a/config/chroot_local-hooks/12-kernel-modules-build-environment b/config/chroot_local-hooks/12-kernel-modules-build-environment
index a3bb017..886e40b 100755
--- a/config/chroot_local-hooks/12-kernel-modules-build-environment
+++ b/config/chroot_local-hooks/12-kernel-modules-build-environment
@@ -11,20 +11,17 @@ echo "Setting up a build environment for kernel modules"
# Import ensure_hook_dependency_is_installed()
. /usr/local/lib/tails-shell-library/build.sh
-# This hack is not needed on Buster but let's keep the commented code around
-# for next time we need it.
-#
-# # Install gcc-6 and fake linux-compiler-gcc-8-x86
-# # (linux-headers-4.19+ depends on it, but Stretch hasn't GCC 8)
-# ensure_hook_dependency_is_installed gcc-6
-# NEWEST_INSTALLED_KERNEL_VERSION="$(
-# dpkg-query --showformat '${Version}\n' --show 'linux-image-*-amd64' \
-# | sort --version-sort | tail -n1
-# )"
-# install_fake_package \
-# linux-compiler-gcc-8-x86 \
-# "${NEWEST_INSTALLED_KERNEL_VERSION}~0tails1"
-# ln -s /usr/bin/gcc-6 /usr/bin/gcc-8
+# Install gcc-8 and fake linux-compiler-gcc-9-x86
+# (linux-headers-5.3.0+ depends on it, but Buster hasn't GCC 9)
+ensure_hook_dependency_is_installed gcc-8
+NEWEST_INSTALLED_KERNEL_VERSION="$(
+ dpkg-query --showformat '${Version}\n' --show 'linux-image-*-amd64' \
+ | sort --version-sort | tail -n1
+)"
+install_fake_package \
+ linux-compiler-gcc-9-x86 \
+ "${NEWEST_INSTALLED_KERNEL_VERSION}~0tails1"
+ln -s /usr/bin/gcc-8 /usr/bin/gcc-9
ensure_hook_dependency_is_installed \
build-essential \
diff --git a/config/chroot_local-hooks/13-aufs b/config/chroot_local-hooks/13-aufs
index 122d3dd..edff20b 100755
--- a/config/chroot_local-hooks/13-aufs
+++ b/config/chroot_local-hooks/13-aufs
@@ -16,11 +16,11 @@ ensure_hook_dependency_is_installed \
# aufs build needs fs/mount.h, which is in linux-source-* but not
# in linux-headers-*, so we'll symlink it.
tar --directory=/usr/src \
- -xf "/usr/src/linux-source-${KERNEL_SOURCE_VERSION}.tar."*
+ -xf "/usr/src/linux-source-${KERNEL_SOURCE_VERSION}"*.tar.*
arch=amd64
ln -s \
- "/usr/src/linux-source-${KERNEL_SOURCE_VERSION}/fs" \
+ "/usr/src/linux-source-${KERNEL_SOURCE_VERSION}"*/fs \
"/usr/src/linux-headers-${KERNEL_VERSION}-${arch}/fs"
(
cd /usr/src/aufs-standalone
@@ -43,4 +43,4 @@ strip --strip-debug /lib/modules/*/extra/aufs.ko
depmod "${KERNEL_VERSION}-${arch}"
rm -r /usr/src/aufs-standalone
-rm -r "/usr/src/linux-source-${KERNEL_SOURCE_VERSION}"
+rm -r "/usr/src/linux-source-${KERNEL_SOURCE_VERSION}"*/
diff --git a/config/chroot_local-hooks/16-greeter b/config/chroot_local-hooks/16-greeter
index 5069f36..920efd6 100644
--- a/config/chroot_local-hooks/16-greeter
+++ b/config/chroot_local-hooks/16-greeter
@@ -3,12 +3,42 @@
set -e
set -u
-echo "Set up greeter language codes"
-
-# Extract language codes from the supported locales
-perl -n -E 'next unless m{_}xms; \
- next if m{\@}xms; \
- say $1 if m{(.*?) [. ]}xms' \
- /usr/share/i18n/SUPPORTED \
- | uniq \
- > /usr/share/tails-greeter/language_codes
+echo "Generate list of supported locales"
+
+OUTFILE="/usr/share/tails/greeter/supported_locales"
+LANGUAGES_FILE="/usr/share/tails/greeter/supported_languages"
+DEFAULT_LOCALES="$(cat /usr/share/tails/greeter/default_locales)"
+
+# Ensure that the output file is empty
+rm -f "${OUTFILE}"
+
+# Extract language and country part from the locales supported by Debian
+ALL_LOCALES="$(tr '.' ' ' < /usr/share/i18n/SUPPORTED | \
+ grep -E ".+_[^.@]+ " | \
+ awk '{print $1;}' | \
+ uniq)"
+
+# Filter the locales by the supported languages
+for lang_code in $(cat ${LANGUAGES_FILE}); do
+ # First add our default locale for the language (i.e. the locale
+ # with the country code that should be used as the default for the
+ # language).
+ default_locale="$(echo "${DEFAULT_LOCALES}" | \
+ grep -E "^${lang_code}_" || true)"
+ if [ -n "${default_locale}" ]; then
+ echo "${default_locale}" >> "${OUTFILE}"
+ fi
+
+ # Get all the locales for the language
+ locales="$(echo "${ALL_LOCALES}" | grep -E "^${lang_code}_")"
+
+ # Remove the default locale from this list to avoid duplicates
+ if [ -n "${default_locale}" ]; then
+ locales="$(echo "${locales}" | grep -v "${default_locale}" || true)"
+ fi
+
+ # Add the locales to the output
+ if [ -n "${locales}" ]; then
+ echo "${locales}" >> "${OUTFILE}"
+ fi
+done
diff --git a/config/chroot_local-hooks/30-gdm-debug b/config/chroot_local-hooks/30-gdm-debug
deleted file mode 100755
index 410f7c0..0000000
--- a/config/chroot_local-hooks/30-gdm-debug
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/sh
-set -e
-set -u
-echo "Enable GDM debug logs"
-sed --in-place --regexp-extended \
- 's/^#Enable=true$/Enable=true/' /etc/gdm3/daemon.conf
diff --git a/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/10-tor.sh b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/10-tor.sh
index e0a1714..32304db 100755
--- a/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/10-tor.sh
+++ b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/10-tor.sh
@@ -30,10 +30,6 @@ systemctl stop tor@default.service
# tordate/20-time.sh), so deleting it seems like a Good Thing(TM).
rm -f "${TOR_LOG}"
-# Let the rest of the system know that Tor is not working at the moment.
-# This matters e.g. if we have already bootstrapped.
-systemctl --no-block restart tails-tor-has-bootstrapped.target
-
# The Tor syscall sandbox is not compatible with managed proxies.
# We could possibly detect whether the user has configured any such
# thing via Tor Launcher later (e.g. in 60-tor-ready.sh),
diff --git a/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/60-tor-ready.sh b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/60-tor-ready.sh
index 91e8514..682d298 100755
--- a/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/60-tor-ready.sh
+++ b/config/chroot_local-includes/etc/NetworkManager/dispatcher.d/60-tor-ready.sh
@@ -10,6 +10,9 @@ if [ "$2" != "up" ]; then
exit 0
fi
+# Import tor_has_bootstrapped()
+. /usr/local/lib/tails-shell-library/systemd.sh
+
# Get LANG
. /etc/default/locale
export LANG
@@ -19,7 +22,7 @@ export LANG
TEXTDOMAIN="tails"
export TEXTDOMAIN
-while ! /usr/local/sbin/tor-has-bootstrapped; do
+while ! tor_has_bootstrapped; do
sleep 1
done
diff --git a/config/chroot_local-includes/etc/environment b/config/chroot_local-includes/etc/environment
index afa3fab..54185cc 100644
--- a/config/chroot_local-includes/etc/environment
+++ b/config/chroot_local-includes/etc/environment
@@ -6,5 +6,3 @@ SOCKS5_SERVER=127.0.0.1:9050
# Have Qt applications use the Adwaita theme
QT_STYLE_OVERRIDE=adwaita
-# Add our Python version independent search path
-PYTHONPATH=/usr/local/lib/python3/dist-packages
diff --git a/config/chroot_local-includes/etc/gdm3/PostLogin/Default b/config/chroot_local-includes/etc/gdm3/PostLogin/Default
index ada42a8..a3fe997 100755
--- a/config/chroot_local-includes/etc/gdm3/PostLogin/Default
+++ b/config/chroot_local-includes/etc/gdm3/PostLogin/Default
@@ -10,7 +10,6 @@
# * /var/lib/gdm3/tails.locale : $TAILS_LOCALE_NAME, $TAILS_XKBMODEL,
# $TAILS_XKBLAYOUT, $TAILS_XKBVARIANT, $TAILS_XKBOPTIONS, $CODESET
# * /var/lib/gdm3/tails.password : $TAILS_USER_PASSWORD
-# * /var/lib/gdm3/tails.physical_security : $TAILS_MACSPOOF_ENABLED
# For whatever reason, /usr/sbin (needed by at least chpasswd)
# is not in our PATH
@@ -94,6 +93,13 @@ localectl set-locale \
"LC_MEASUREMENT=${TAILS_FORMATS}.UTF-8" \
"LC_PAPER=${TAILS_FORMATS}.UTF-8" \
+# Set the system locale GSetting (#16806)
+cat > /etc/dconf/db/local.d/01_Tails_settings << EOF
+[system/locale]
+region = '${TAILS_FORMATS}.UTF-8'
+EOF
+dconf update
+
# Save keyboard settings so that tails-configure-keyboard can set it
# in the GNOME session.
cat > /var/lib/tails-user-session/keyboard <<EOF
@@ -120,7 +126,7 @@ if [ -z "${TAILS_USER_PASSWORD}" ] ; then
passwd -d "${LIVE_USERNAME}"
install -o root -g root -m 0440 /dev/null "${NO_PASSWORD_LECTURE}"
echo "Defaults:amnesia lecture=always" > "${NO_PASSWORD_LECTURE}"
- echo "Defaults:amnesia lecture_file=/usr/share/tails-greeter/no-password-lecture.txt" >> "${NO_PASSWORD_LECTURE}"
+ echo "Defaults:amnesia lecture_file=/usr/share/tails/greeter/no-password-lecture.txt" >> "${NO_PASSWORD_LECTURE}"
echo "Defaults:amnesia badpass_message=\"The administration password is disabled.\"" >> "${NO_PASSWORD_LECTURE}"
log_n_exit "Password variable not found."
fi
diff --git a/config/chroot_local-includes/etc/skel/.electrum/config b/config/chroot_local-includes/etc/skel/.electrum/config
index 9b65c41..e2cd56e 100644
--- a/config/chroot_local-includes/etc/skel/.electrum/config
+++ b/config/chroot_local-includes/etc/skel/.electrum/config
@@ -1,6 +1,6 @@
{
"auto_connect": true,
- "coin_chooser": "Privacy",
+ "check_updates": false,
"proxy": "socks5:localhost:9050",
"server": ""
}
diff --git a/config/chroot_local-includes/etc/whisperback/4mvq3pnvid3awjln.onion.pem b/config/chroot_local-includes/etc/whisperback/4mvq3pnvid3awjln.onion.pem
deleted file mode 100644
index 7e7bb65..0000000
--- a/config/chroot_local-includes/etc/whisperback/4mvq3pnvid3awjln.onion.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEvjCCAqYCCQC0kD+1GKCKDzANBgkqhkiG9w0BAQUFADAhMR8wHQYDVQQDExY0
-bXZxM3BudmlkM2F3amxuLm9uaW9uMB4XDTA5MDkxMjE3MjUzM1oXDTE5MDkxMDE3
-MjUzM1owITEfMB0GA1UEAxMWNG12cTNwbnZpZDNhd2psbi5vbmlvbjCCAiIwDQYJ
-KoZIhvcNAQEBBQADggIPADCCAgoCggIBAOsO/hK2WNClY4lq82nTrJ8CGCfUYUzL
-TiBz7P0XIAcGB34DkFO96aCyFz4TsjpPalIhna8BabuIPRZo6Gt0gpE6lpqLbYiG
-qyvXK63ENlL92LzennKdeYSBlAUi9Bt38T3jDZ8dAWxFhkjKKPrtqjpN9d6gA7aU
-IDWzczXUl0rmE5UC5bh8NmcaHDogiNR5r/Wj24FqncS6Ilfjhn1mXacINX9mqzOV
-IX/WHWQ6NGFWd+uV3D0U/7TkVDQDJ+Ni/RZGXgcVJ5JoSgJAPAefUTKuC9X7FGVt
-i1iu/Cy0DYLVjTHO30oazKTcJuMdOVZ70fRnDyXI8m4hHqyUB16lyw4lHN10OgY/
-haOm6C6VW1OoBAcgxvOdNo/h/jkhSKzgC5iWbtDPB2+qrBvgDVqgYPFDVaBCXewd
-qnd02ysMe0axu4nSjRSODG3CRJjuQ0Zhaz4cPsHeOBeLOlDTFuHN/YyPDaWOD7xH
-FyDE0hn7kMQWh955Hh5CVZZrx6GI2AbppCgLiWFo2M9e16YAssiZ86yOg2j3PYhW
-RDcNuInfj1U/YHv/DnunS0o2eNKxmNLbcaQMu8+4AdGPBhUX7dNtR1iK3o3OB25Z
-6ZU2FloEYJGaTiRV3ZMPuABlyxOJxLCSuSfaUk5Xl0+K51sW8FoQU4XhKyej561y
-/fSgAJST37/RAgMBAAEwDQYJKoZIhvcNAQEFBQADggIBACf9gKIdXBnNuLiaBmt2
-t78Ton2geH8IT5eT6sr7NaWRRfaHkKgTNzqE4/KItNM5LDMCN96JulIns9mSnfyE
-gYB4KYgfVtHdm5RJ6vlnO1q/UveYXvwTvBcOQBr62ztG41L4xGPZZb7NVOihXr1f
-2iGyc/mEy9QiB3b26Tx5+3N4lyJWEadNyqDNbP4RhHSdDMcDhbTPu9tzbhjMVehL
-FLEhHGCIxKoFqyc/OWZRrvrKZtjhvRxkCiQ3sCc7qdVMnK8qaa6JUyrPrZomeF2p
-csOTEyVc24iWz9XuQgZjmx9b5BKreUPoZuQ8mQqU7CdVasIKREe/+pk8VyBUgAvV
-+vdxJ77WI7XUarILH0ZuSbSgl5iV4Krkqk4o65GoVW9VCjw9aiEeb6X5ijZxe1/j
-h2PWFb1603eHDuuCrZYywzl3DLjZ6xzQF5kQGcpR+ORs/wcaxxcDveiBk7oEfRkr
-pxGo8batLy5NtCbp5eB2Nvd0oWA1ALsdIwNCSZyuYOUO5lr4cjl98KF9KBhHGbhN
-AHn4jKgDHsJwfMRBUaiYtcPQLfhsyM5C4t2xXBJ2ycZuoOCEDxx0yONatRAnbHAX
-UdPjN/ijn12c6uvrjAOVK54o0uZ+h1DiGvwU5i31yCHFQX11TZY4FHohuCKl4oTj
-39ZLEAZs4/tAyWm1eAZK4GrF
------END CERTIFICATE-----
diff --git a/config/chroot_local-includes/etc/whisperback/config.py b/config/chroot_local-includes/etc/whisperback/config.py
index 32ee87d..20175e0 100644
--- a/config/chroot_local-includes/etc/whisperback/config.py
+++ b/config/chroot_local-includes/etc/whisperback/config.py
@@ -110,13 +110,9 @@ from_address = "devnull@tails.boum.org"
# This section defines the SMTP server parameters
#
# The SMTP server to use to send the mail
-smtp_host = "4mvq3pnvid3awjln.onion"
+smtp_host = "xgvhluz6szspb2od6yi37cs4tdm27hgjunbig23yc5hxececcax5wlyd.onion"
# The port to connect to on that SMTP server
smtp_port = 25
-# The path to a file containing the certificate to trust
-# This can be either a CA certificate used to sign the SMTP server
-# certificate or the certificate of the SMTP server itself
-smtp_tlscafile = "/etc/whisperback/4mvq3pnvid3awjln.onion.pem"
# SOCKS
#
diff --git a/config/chroot_local-includes/etc/whisperback/debugging-info.json b/config/chroot_local-includes/etc/whisperback/debugging-info.json
index 44f2d70..b9c451a 100644
--- a/config/chroot_local-includes/etc/whisperback/debugging-info.json
+++ b/config/chroot_local-includes/etc/whisperback/debugging-info.json
@@ -16,8 +16,9 @@
["file", {"user": "Debian-gdm", "path": "/var/log/gdm3/tails-greeter.errors"}],
["file", {"user": "root", "path": "/var/log/live/boot.log"}],
["file", {"user": "root", "path": "/var/log/live/config.log"}],
-["file", {"user": "root", "path": "/var/lib/live/config/tails.physical_security"}],
-["file", {"user": "root", "path": "/var/lib/gdm3/tails.persistence"}],
+["file", {"user": "root", "path": "/var/lib/live/config/tails.macspoof"}],
+["file", {"user": "root", "path": "/var/lib/live/config/tails.network"}],
+["file", {"user": "root", "path": "/var/lib/live/config/tails.persistence"}],
["file", {"user": "tails-persistence-setup", "path": "/live/persistence/TailsData_unlocked/persistence.conf"}],
["file", {"user": "tails-persistence-setup", "path": "/live/persistence/TailsData_unlocked/live-additional-software.conf"}],
["directory", {"user": "root", "path": "/live/persistence/TailsData_unlocked/apt-sources.list.d"}],
diff --git a/config/chroot_local-includes/lib/systemd/system/tails-tor-has-bootstrapped.target b/config/chroot_local-includes/lib/systemd/system/tails-tor-has-bootstrapped.target
index 0aca04f..e514116 100644
--- a/config/chroot_local-includes/lib/systemd/system/tails-tor-has-bootstrapped.target
+++ b/config/chroot_local-includes/lib/systemd/system/tails-tor-has-bootstrapped.target
@@ -1,10 +1,8 @@
[Unit]
-Description=Tor has bootstrapped
+Description=Tor has Bootstrapped
Documentation=https://tails.boum.org/contribute/design/
-Requires=graphical.target
-Conflicts=rescue.service rescue.target
-After=graphical.target rescue.service rescue.target
-AllowIsolate=yes
+After=tails-wait-until-tor-has-bootstrapped.service
+BindsTo=tails-wait-until-tor-has-bootstrapped.service
[Install]
-WantedBy=graphical.target
+WantedBy=tails-wait-until-tor-has-bootstrapped.service \ No newline at end of file
diff --git a/config/chroot_local-includes/lib/systemd/system/tails-unblock-network.service b/config/chroot_local-includes/lib/systemd/system/tails-unblock-network.service
index e8feaca..f9836e0 100644
--- a/config/chroot_local-includes/lib/systemd/system/tails-unblock-network.service
+++ b/config/chroot_local-includes/lib/systemd/system/tails-unblock-network.service
@@ -5,15 +5,18 @@ Documentation=https://tails.boum.org/contribute/design/MAC_address/
[Service]
Type=oneshot
RemainAfterExit=yes
-EnvironmentFile=/var/lib/gdm3/tails.physical_security
+EnvironmentFile=/var/lib/gdm3/tails.network
-# It's important we "export" the settings from tails.physical_security
-# before unblocking the network; doing so will make the user-set MAC spoofing
+# It's important we "export" the settings from tails.macspoof before
+# unblocking the network; doing so will make the user-set MAC spoofing
# option apply (via the custom udev rule) when loading the modules for the
# previously blocked network devices.
-ExecStartPre=/usr/bin/install -m 0640 -o root -g root \
- /var/lib/gdm3/tails.physical_security \
- /var/lib/live/config/tails.physical_security
+ExecStartPre=/bin/sh -c \
+ 'for setting in macspoof network; do \
+ /usr/bin/install -m 0640 -o root -g root \
+ "/var/lib/gdm3/tails.$setting" \
+ "/var/lib/live/config/tails.$setting" ; \
+ done'
ExecStartPre=/bin/sync
ExecStartPre=/bin/sh -c \
'if [ "${TAILS_NETCONF}" = "obstacle" ] ; then \
diff --git a/config/chroot_local-includes/lib/systemd/system/tails-wait-until-tor-has-bootstrapped.service b/config/chroot_local-includes/lib/systemd/system/tails-wait-until-tor-has-bootstrapped.service
index 64f2afd..853aac7 100644
--- a/config/chroot_local-includes/lib/systemd/system/tails-wait-until-tor-has-bootstrapped.service
+++ b/config/chroot_local-includes/lib/systemd/system/tails-wait-until-tor-has-bootstrapped.service
@@ -2,10 +2,11 @@
Description=Wait for Tor to Have Bootstrapped
Documentation=https://tails.boum.org/contribute/design/
After=tor@default.service
-Before=tails-tor-has-bootstrapped.target
+BindsTo=tor@default.service
[Service]
Type=oneshot
+RemainAfterExit=yes
User=debian-tor
ExecStart=/bin/sh -c '. /usr/local/lib/tails-shell-library/tor.sh ; \
while ! tor_is_working ; do \
@@ -19,4 +20,4 @@ ProtectHome=yes
ProtectSystem=full
[Install]
-WantedBy=tails-tor-has-bootstrapped.target
+WantedBy=tor@default.service \ No newline at end of file
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/__init__.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/__init__.py
index 45230ec..6e8bda9 100644
--- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/__init__.py
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/__init__.py
@@ -26,4 +26,4 @@ __all__ = tailsgreeter.errors
APPLICATION_TITLE = "Welcome to Tails!"
APPLICATION_ICON_NAME = 'gdm-setup'
-TRANSLATION_DOMAIN = "tails" \ No newline at end of file
+TRANSLATION_DOMAIN = "tails"
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/config.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/config.py
index dbc8f89..e5fc4a8 100644
--- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/config.py
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/config.py
@@ -24,26 +24,25 @@ LPASSWORD = 'live'
LUSER = 'amnesia'
# data path
-data_path = '/usr/share/tails-greeter/'
+data_path = '/usr/share/tails/greeter/'
-# File where supported language codes (such as en_US) are stored
-# while building the tails-greeter binary package
-language_codes_path = os.path.join(data_path, 'language_codes')
+# File containing the locales for the supported languages
+supported_locales_path = os.path.join(data_path, 'supported_locales')
-# File where default language code for languages are stored
-default_langcodes_path = os.path.join(data_path, 'default_langcodes')
-
-# Locales path
-locales_path = '/usr/share/locale/'
+# System locales directory
+system_locale_dir = '/usr/share/locale/'
# File where session locale settings are stored
locale_output_path = '/var/lib/gdm3/tails.locale'
# File where the session sudo password is stored
-rootpassword_output_path = '/var/lib/gdm3/tails.password'
+admin_password_output_path = '/var/lib/gdm3/tails.password'
# World-readable file where Tails persistence status is stored
persistence_state_file = '/var/lib/live/config/tails.persistence'
-# File where settings related to physical security are stored
-physical_security_settings = '/var/lib/gdm3/tails.physical_security'
+# File where the network setting is stored
+network_setting = '/var/lib/gdm3/tails.network'
+
+# File where the MAC address spoofing setting is stored
+macspoof_setting = '/var/lib/gdm3/tails.macspoof'
diff --git a/config/chroot_local-includes/usr/share/tails-greeter/tails-greeter.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/greeter.py
index a656924..4af91ed 100755..100644
--- a/config/chroot_local-includes/usr/share/tails-greeter/tails-greeter.py
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/greeter.py
@@ -1,6 +1,6 @@
#!/usr/bin/python3
#
-# Copyright 2012-2016 Tails developers <tails@boum.org>
+# Copyright 2012-2019 Tails developers <tails@boum.org>
# Copyright 2011 Max <govnototalitarizm@gmail.com>
# Copyright 2011 Martin Owens
#
@@ -17,63 +17,34 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>
#
-"""
-GDM greeter for Tails project using gtk
-"""
-import gettext
-import locale
+import gi
import logging
-import logging.config
-import sys
-import traceback # NOQA: F401
-
-logging.config.fileConfig('tails-logging.conf')
-# Set loglevel if debug is found in kernel command line
-with open('/proc/cmdline') as cmdline_fd:
- cmdline = cmdline_fd.read()
-if "debug" in cmdline.split():
- logging.getLogger().setLevel(logging.DEBUG)
-
-
-def log_exc(etype, value, tb):
- for line in traceback.format_exception(etype, value, tb):
- print(line, file=sys.stderr)
-
-
-sys.excepthook = log_exc
-
-
-import gi # NOQA: F401
-gi.require_version('GLib', '2.0')
-from gi.repository import GLib # NOQA: F401
-from gi.repository import Gio # NOQA: F401
+from tailsgreeter.gdmclient import GdmClient
+from tailsgreeter.settings import localization
+from tailsgreeter.settings.admin import AdminSetting
+from tailsgreeter.settings.localization_settings import LocalisationSettings
+from tailsgreeter.settings.macspoof import MacSpoofSetting
+from tailsgreeter.settings.network import NetworkSetting
+from tailsgreeter.settings.persistence import PersistenceSettings
+from tailsgreeter.translatable_window import TranslatableWindow
+from tailsgreeter.ui.additional_settings import AdminSettingUI, MACSpoofSettingUI, NetworkSettingUI
+from tailsgreeter.ui.main_window import GreeterMainWindow
+from tailsgreeter.ui.region_settings import LanguageSettingUI, KeyboardSettingUI, FormatsSettingUI
+from tailsgreeter.ui.settings_collection import GreeterSettingsCollection
+
+gi.require_version('Gio', '2.0')
gi.require_version("Gtk", "3.0")
-from gi.repository import Gtk # NOQA: F401
-
-import tailsgreeter # NOQA: F401
-import tailsgreeter.config # NOQA: F401
-import tailsgreeter.gdmclient # NOQA: F401
-import tailsgreeter.persistence # NOQA: F401
-import tailsgreeter.physicalsecurity # NOQA: F401
-import tailsgreeter.rootaccess # NOQA: F401
-
-from tailsgreeter.language import TranslatableWindow # NOQA: F401
-from tailsgreeter.gui import GreeterMainWindow # NOQA: F401
+from gi.repository import Gio, Gtk
-gettext.install(tailsgreeter.__appname__, tailsgreeter.config.locales_path)
-locale.bindtextdomain(tailsgreeter.__appname__,
- tailsgreeter.config.locales_path)
-
-class GreeterApplication():
+class GreeterApplication(object):
"""Tails greeter main controller
This class is the greeter dbus service"""
def __init__(self):
- self.language = 'en_US.UTF-8'
self.session = None
self.forced = False
self.postponed = False
@@ -90,21 +61,29 @@ class GreeterApplication():
"org.gnome.SessionManager")
# Load models
- self.gdmclient = tailsgreeter.gdmclient.GdmClient(
- session_opened_cb=self.close_app
- )
- self.persistence = tailsgreeter.persistence.PersistenceSettings()
- self.localisationsettings = tailsgreeter.language.LocalisationSettings(
+ self.gdmclient = GdmClient(session_opened_cb=self.close_app)
+
+ persistence = PersistenceSettings()
+ self.localisationsettings = LocalisationSettings(
usermanager_loaded_cb=self.usermanager_loaded,
- locale_selected_cb=self.locale_selected
+ locale_selected_cb=self.on_language_changed
+ )
+ self.admin_setting = AdminSetting()
+ self.network_setting = NetworkSetting()
+ self.macspoof_setting = MacSpoofSetting()
+
+ # Initialize the settings
+ settings = GreeterSettingsCollection(
+ LanguageSettingUI(self.localisationsettings.language),
+ KeyboardSettingUI(self.localisationsettings.keyboard),
+ FormatsSettingUI(self.localisationsettings.formats),
+ AdminSettingUI(self.admin_setting),
+ MACSpoofSettingUI(self.macspoof_setting),
+ NetworkSettingUI(self.network_setting),
)
- self.rootaccess = \
- tailsgreeter.rootaccess.RootAccessSettings()
- self.physical_security = \
- tailsgreeter.physicalsecurity.PhysicalSecuritySettings()
- # Load views
- self.mainwindow = GreeterMainWindow(self)
+ # Initialize main window
+ self.mainwindow = GreeterMainWindow(self, persistence, settings)
# Inhibit the session being marked as idle
self.inhibit_idle()
@@ -116,6 +95,13 @@ class GreeterApplication():
def login(self):
"""Login GDM to the server"""
logging.debug("login called")
+
+ # Apply settings
+ self.localisationsettings.apply_to_upcoming_session()
+ self.admin_setting.apply_to_upcoming_session()
+ self.macspoof_setting.apply_to_upcoming_session()
+ self.network_setting.apply_to_upcoming_session()
+
self.mainwindow.hide()
self.gdmclient.do_login()
@@ -123,13 +109,15 @@ class GreeterApplication():
"""UserManager is ready"""
logging.debug("Entering usermanager_loaded")
self.ready = True
- self.localisationsettings.text.set_value('en_US')
logging.info("tails-greeter is ready.")
self.mainwindow.show()
- def locale_selected(self, locale_code):
+ def on_language_changed(self, locale_code: str):
"""Translate to the given locale"""
+ self.localisationsettings.formats.on_language_changed(locale_code) # XXX: notify
+ self.localisationsettings.keyboard.on_language_changed(locale_code) # XXX: notify
self.translate_to(locale_code)
+ self.mainwindow.current_language = localization.language_from_locale(locale_code)
def close_app(self):
"""We're done, quit gtk app"""
@@ -149,14 +137,3 @@ class GreeterApplication():
"Greeter session shouldn't idle",
8) # Inhibit the session being marked as idle
logging.debug("inhibitor cookie=%i", cookie)
-
-
-if __name__ == "__main__":
- GLib.set_prgname(tailsgreeter.APPLICATION_TITLE)
- GLib.set_application_name(
- _(tailsgreeter.APPLICATION_TITLE)) # NOQA: F821
- Gtk.init(sys.argv)
- Gtk.Window.set_default_icon_name(tailsgreeter.APPLICATION_ICON_NAME)
-
- application = GreeterApplication()
- Gtk.main()
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/gui.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/gui.py
deleted file mode 100644
index 91d1ec9..0000000
--- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/gui.py
+++ /dev/null
@@ -1,1171 +0,0 @@
-# -*- coding: utf-8 -*-/
-#
-# Copyright 2015-2016 Tails developers <tails@boum.org>
-#
-# This program 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.
-#
-# This program 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 this program. If not, see <http://www.gnu.org/licenses/>
-
-import locale
-import logging
-import threading
-import webbrowser
-
-import gi
-
-gi.require_version('GLib', '2.0')
-from gi.repository import GLib # NOQA: E402
-gi.require_version('Gdk', '3.0')
-from gi.repository import Gdk # NOQA: E402
-gi.require_version('Gtk', '3.0')
-from gi.repository import Gtk # NOQA: E402
-gi.require_version('Pango', '1.0')
-from gi.repository import Pango # NOQA: E402
-gi.require_version('WebKit2', '4.0')
-from gi.repository import WebKit2 # NOQA: E402
-
-import tailsgreeter # NOQA: E402
-import tailsgreeter.config # NOQA: E402
-import tailsgreeter.utils # NOQA: E402
-from tailsgreeter.language import TranslatableWindow # NOQA: E402
-
-from tailsgreeter import TRANSLATION_DOMAIN
-
-UI_FILE = 'greeter.ui'
-CSS_FILE = 'greeter.css'
-ICON_DIR = 'icons/'
-MAIN_WINDOW_PREFERRED_WIDTH = 620
-MAIN_WINDOW_PREFERRED_HEIGHT = 470
-ADD_SETTING_DIALOG_PREFERRED_WIDTH = 400
-HELP_WINDOW_PREFERRED_WIDTH = 800
-
-locale.bindtextdomain(TRANSLATION_DOMAIN, tailsgreeter.config.locales_path)
-# Mark translatable strings, but don't actually translate them, as we
-# delegate this to TranslatableWindow that handles on-the-fly language changes
-_ = lambda text: text # NOQA: E731
-
-
-class GreeterSetting(object):
- def __init__(self, setting_id):
- self.setting_id = setting_id
- self.listbox_container = None
- self.accel_key = None
-
- def cb_popover_closed(self, popover, user_data=None):
- self.listbox_container.unselect_all()
- return False
-
- @staticmethod
- def _add_popover(widget, content, closed_cb=None):
- popover = Gtk.Popover.new(widget)
- popover.set_position(Gtk.PositionType.BOTTOM)
- popover.add(content)
- if closed_cb:
- popover.connect('closed', closed_cb)
- return popover
-
- @staticmethod
- def _fill_tree_view(name, treeview):
- assert isinstance(name, str)
- assert isinstance(treeview, Gtk.TreeView)
- renderer = Gtk.CellRendererText()
- renderer.props.ellipsize = Pango.EllipsizeMode.END
- column = Gtk.TreeViewColumn(name, renderer, text=1)
- treeview.append_column(column)
-
-
-class RegionSetting(GreeterSetting):
- def __init__(self, setting_id, greeter, builder, setting_target=None):
- super().__init__(setting_id)
- self.greeter = greeter
-
- if not setting_target:
- setting_target = setting_id
- self.target = setting_target
-
- self.target.connect("notify::value", self.cb_value_changed)
-
- self.treestore = self.target.get_tree()
- self.build_ui(builder)
-
- def build_ui(self, builder):
- self.listbox_container = builder.get_object("listbox_language")
-
- listboxrow = builder.get_object(
- "listboxrow_{}".format(self.setting_id))
- self.label_value = builder.get_object(
- "label_{}_value".format(self.setting_id))
- box = builder.get_object(
- "box_{}_popover".format(self.setting_id))
- self.treeview = builder.get_object(
- "treeview_{}".format(self.setting_id))
- searchentry = builder.get_object(
- "searchentry_{}".format(self.setting_id))
-
- self.popover = GreeterSetting._add_popover(
- listboxrow, box, closed_cb=self.cb_popover_closed)
-
- GreeterSetting._fill_tree_view("", self.treeview)
- self.treestore_filtered = self.treestore.filter_new()
- self.treestore_filtered.set_visible_func(
- self.cb_liststore_filtered_visible_func, data=searchentry)
- self.treeview.set_model(self.treestore_filtered)
-
- searchentry.connect("search-changed",
- self.cb_searchentry_search_changed)
- searchentry.connect("activate", self.cb_searchentry_activate)
- self.treeview.connect("row-activated", self.cb_treeview_row_activated)
-
- def cb_searchentry_activate(self, searchentry, user_data=None):
- """Selects the topmost item in the treeview when pressing Enter"""
- if searchentry.get_text():
- self.treeview.row_activated(Gtk.TreePath.new_from_string("0"),
- self.treeview.get_column(0))
- else:
- self.popover.set_visible(False)
-
- def cb_searchentry_search_changed(self, searchentry, user_data=None):
- self.treestore_filtered.refilter()
- if searchentry.get_text():
- self.treeview.expand_all()
- self.treeview.scroll_to_point(0, 0) # scroll to top
- else:
- self.treeview.collapse_all()
- return False
-
- def cb_treeview_row_activated(self, treeview, path, column,
- user_data=None):
- treemodel = treeview.get_model()
- code = treemodel.get_value(treemodel.get_iter(path), 0)
- name = treemodel.get_value(treemodel.get_iter(path), 1)
-
- self.label_value.set_label(name)
- self.popover.set_visible(False)
-
- self.target.set_value(code)
-
- def cb_value_changed(self, obj, param):
- logging.debug("refreshing {}".format(self.target))
- self.label_value.set_label(self.target.get_name())
-
- def treeview_select_line(model, path, iter, data):
- if model.get_value(iter, 0) == data:
- self.treeview.get_selection().select_iter(iter)
- self.treeview.scroll_to_cell(path, use_align=True,
- row_align=0.5)
- return True
- else:
- return False
-
- self.treestore_filtered.foreach(
- treeview_select_line,
- self.target.get_value())
-
- def cb_liststore_filtered_visible_func(self, model, treeiter, searchentry):
- search_query = searchentry.get_text().lower()
- if not search_query:
- return True
-
- # Does the current node match the search?
- value = model.get_value(treeiter, 1).lower()
- if search_query in value:
- return True
-
- # Does the parent node match the search?
- treepath = model.get_path(treeiter)
- parent_treepath = treepath.copy()
- parent_treepath.up()
- if parent_treepath.get_depth() == 1:
- # treepath is now the parent
- parent_value = model.get_value(model.get_iter(parent_treepath), 0)
- return search_query in parent_value
-
- # Does any of the children nodes match the search?
- children_treeiter = model.iter_children(treeiter)
- while children_treeiter:
- child_value = model.get_value(children_treeiter, 0)
- if search_query in child_value:
- return True
- children_treeiter = model.iter_next(children_treeiter)
-
- return False
-
-
-class TextSetting(RegionSetting):
- def __init__(self, greeter, builder):
- super().__init__("text", greeter, builder,
- greeter.localisationsettings.text)
-
-
-class KeyboardSetting(RegionSetting):
- def __init__(self, greeter, builder):
- super().__init__("keyboard", greeter, builder,
- greeter.localisationsettings.layout)
-
-
-class FormatsSetting(RegionSetting):
- def __init__(self, greeter, builder):
- super().__init__("formats", greeter, builder,
- greeter.localisationsettings.formats)
-
-
-class TimezoneSetting(RegionSetting):
- def __init__(self, greeter, builder):
- super().__init__("tz", greeter, builder,
- greeter.localisationsettings.timezone)
-
-
-class AdditionalSetting(GreeterSetting):
- def __init__(self, setting_id, greeter, builder):
- super().__init__(setting_id)
- self.greeter = greeter
- self.build_ui(builder)
-
- def build_ui(self, builder):
- self.listbox_container = builder.get_object("listbox_settings")
-
- self.listboxrow = builder.get_object(
- "listboxrow_{}".format(self.setting_id))
- self.label_value = builder.get_object(
- "label_{}_value".format(self.setting_id))
- self.box = builder.get_object(
- "box_{}_popover".format(self.setting_id))
-
- def build_popover(self):
- self.popover = GreeterSetting._add_popover(
- self.listboxrow, self.box, closed_cb=self.cb_popover_closed)
-
- return self.popover
-
- def close_popover_if_any(self):
- """Closes the popover if it exists
-
- Returns True if the popover was closed, False if there is no popover"""
- if self.has_popover():
- self.popover.set_visible(False)
- return True
- else:
- return False
-
- def has_popover(self):
- return hasattr(self, 'popover')
-
-
-class AdminSetting(AdditionalSetting):
- def __init__(self, greeter, builder):
- super().__init__("admin", greeter, builder)
- self.accel_key = Gdk.KEY_a
-
- def build_ui(self, builder):
- super().build_ui(builder)
- tailsgreeter.utils.import_builder_objects(self, builder, [
- 'box_admin_password',
- 'box_admin_verify',
- 'button_admin_disable',
- 'entry_admin_password',
- 'entry_admin_verify',
- 'label_admin_value',
- ])
-
- # XXX-non-blocker: avoid mixing business logic with GUI code?
- # The "check and return a boolean" operation should live in a pure function
- # outside of this file, and a method here should use it to update the GUI
- # accordingly.
- def check(self):
- password = self.entry_admin_password.get_text()
- verify = self.entry_admin_verify.get_text()
- if verify and verify == password:
- icon = 'emblem-ok-symbolic'
- elif verify and not (verify == password):
- icon = 'dialog-warning-symbolic'
- else:
- icon = None
- self.entry_admin_verify.set_icon_from_icon_name(
- Gtk.EntryIconPosition.SECONDARY, icon)
- return (verify == password)
-
- def apply(self):
- if self.check():
- password = self.entry_admin_password.get_text()
- self.greeter.rootaccess.password = password
- # XXX-non-blocker: the action at a distance on next line is
- # scary; better return the admin password (or False if the check
- # fails), and let the caller modify its own state... or do some
- # slightly less scary action at a distance?
- # Same comment wrt. the disable method, and more
- # generally it feels wrong that each *Setting objects gets a
- # greeter attribute they can mess with as they want.
- self.label_admin_value.set_label(
- tailsgreeter.utils.get_on_off_string(password, default=None))
- self.box_admin_password.set_visible(False)
- self.box_admin_verify.set_visible(False)
- self.button_admin_disable.set_visible(True)
- return True
- else:
- return False
-
- def disable(self):
- self.greeter.rootaccess.password = None
- self.label_admin_value.set_label(
- tailsgreeter.utils.get_on_off_string(None, default=None))
- self.entry_admin_password.set_text("")
- self.entry_admin_verify.set_text("")
- self.box_admin_password.set_visible(True)
- self.box_admin_verify.set_visible(True)
- self.button_admin_disable.set_visible(False)
-
-
-class MACSpoofSetting(AdditionalSetting):
- def __init__(self, greeter, builder):
- super().__init__("macspoof", greeter, builder)
- self.accel_key = Gdk.KEY_m
-
- def build_ui(self, builder):
- super().build_ui(builder)
- tailsgreeter.utils.import_builder_objects(self, builder, [
- 'image_macspoof_off',
- 'image_macspoof_on',
- 'label_macspoof_value',
- 'listboxrow_macspoof_off',
- 'listboxrow_macspoof_on',
- ])
-
- def row_activated(self, row):
- macspoof = None
- if row == self.listboxrow_macspoof_on:
- macspoof = True
- self.image_macspoof_on.set_visible(True)
- self.image_macspoof_off.set_visible(False)
- elif row == self.listboxrow_macspoof_off:
- macspoof = False
- self.image_macspoof_off.set_visible(True)
- self.image_macspoof_on.set_visible(False)
- self.greeter.physical_security.macspoof = macspoof
- self.label_macspoof_value.set_label(
- tailsgreeter.utils.get_on_off_string(macspoof, default=True))
-
-
-class NetworkSetting(AdditionalSetting):
- def __init__(self, greeter, builder):
- super().__init__("network", greeter, builder)
- self.accel_key = Gdk.KEY_n
-
- def build_ui(self, builder):
- super().build_ui(builder)
- tailsgreeter.utils.import_builder_objects(self, builder, [
- 'infobar_network',
- 'image_network_clear',
- 'image_network_specific',
- 'image_network_off',
- 'label_network_value',
- 'listboxrow_network_clear',
- 'listboxrow_network_specific',
- 'listboxrow_network_off',
- ])
-
- def build_popover(self):
- super().build_popover()
- self.show_bridge_info_if_needed()
-
- def row_activated(self, row):
- netconf = None
- if row == self.listboxrow_network_clear:
- netconf = self.greeter.physical_security.NETCONF_DIRECT
- self.image_network_clear.set_visible(True)
- self.image_network_specific.set_visible(False)
- self.image_network_off.set_visible(False)
- self.label_network_value.set_label(_("Direct (default)"))
- elif row == self.listboxrow_network_specific:
- netconf = self.greeter.physical_security.NETCONF_OBSTACLE
- self.image_network_specific.set_visible(True)
- self.image_network_clear.set_visible(False)
- self.image_network_off.set_visible(False)
- self.label_network_value.set_label(_("Bridge & Proxy"))
- elif row == self.listboxrow_network_off:
- netconf = self.greeter.physical_security.NETCONF_DISABLED
- self.image_network_off.set_visible(True)
- self.image_network_specific.set_visible(False)
- self.image_network_clear.set_visible(False)
- self.label_network_value.set_label(_("Offline"))
- if netconf:
- self.greeter.physical_security.netconf = netconf
-
- def show_bridge_info_if_needed(self):
- if (self.greeter.physical_security.netconf ==
- self.greeter.physical_security.NETCONF_OBSTACLE):
- self.infobar_network.set_visible(True)
- else:
- self.infobar_network.set_visible(False)
-
-
-class CamouflageSetting(AdditionalSetting):
- def __init__(self, greeter, builder):
- super().__init__("camouflage", greeter, builder)
-
- def build_ui(self, builder):
- super().build_ui(builder)
- tailsgreeter.utils.import_builder_objects(self, builder, [
- 'label_camouflage_value'])
-
- def switch_active(self, switch):
- state = switch.get_active()
- if state:
- self.greeter.camouflage.os = 'win8'
- else:
- self.greeter.camouflage.os = None
- self.label_camouflage_value.set_label(
- tailsgreeter.utils.get_on_off_string(state, default=None))
-
-
-class PersistentStorage(object):
- def __init__(self, greeter, builder):
- self.greeter = greeter
- self.build_ui(builder)
-
- def build_ui(self, builder):
- tailsgreeter.utils.import_builder_objects(self, builder, [
- 'box_storage',
- 'box_storage_unlock',
- 'box_storage_unlocked',
- 'button_storage_configure',
- 'button_storage_unlock',
- 'checkbutton_storage_show_passphrase',
- 'entry_storage_passphrase',
- 'image_storage_state',
- 'infobar_persistence',
- 'label_infobar_persistence',
- 'spinner_storage_unlock',
- ])
-
- if self.greeter.persistence.has_persistence():
- self.button_storage_configure.set_visible(False)
- self.checkbutton_storage_show_passphrase.set_visible(True)
- self.box_storage_unlock.set_visible(True)
- self.image_storage_state.set_visible(True)
- self.entry_storage_passphrase.set_visible(True)
- self.spinner_storage_unlock.set_visible(False)
- else:
- # XXX-future: We have a nice button to configure the persistence
- # but nothing is implemented to do so currently. So let's
- # hide the whole thing for now.
- self.box_storage.set_visible(False)
-
- def configure(self):
- # XXX-future: this should launch the configuration of the persistence.
- logging.warn("User would be able to set up an encrypted storage.")
- raise NotImplementedError
-
- def lock(self):
- if self.greeter.persistence.lock():
- self.button_storage_lock.set_visible(False)
- self.checkbutton_storage_show_passphrase.set_visible(True)
- self.box_storage_unlock.set_visible(True)
- self.image_storage_state.set_visible(True)
- self.image_storage_state.set_from_icon_name(
- 'tails-locked', Gtk.IconSize.BUTTON)
- self.entry_storage_passphrase.set_visible(True)
- self.entry_storage_passphrase.set_sensitive(True)
- self.button_storage_unlock.set_visible(True)
- self.button_storage_unlock.set_sensitive(True)
- self.button_storage_unlock.set_label(_("Unlock"))
- else:
- self.label_infobar_persistence.set_label(
- _("Failed to relock persistent storage."))
- self.infobar_persistence.set_visible(True)
-
- def passphrase_changed(self, editable):
- # Remove warning icon
- editable.set_icon_from_icon_name(
- Gtk.EntryIconPosition.SECONDARY,
- None)
-
- def unlock(self, unlocked_cb=None, failed_cb=None):
- if not unlocked_cb:
- unlocked_cb = self.cb_unlocked
- if not failed_cb:
- failed_cb = self.cb_unlock_failed
-
- self.checkbutton_storage_show_passphrase.set_visible(False)
- self.entry_storage_passphrase.set_sensitive(False)
- self.button_storage_unlock.set_sensitive(False)
- self.button_storage_unlock.set_label(_("Unlocking…"))
- self.image_storage_state.set_visible(False)
- self.spinner_storage_unlock.set_visible(True)
-
- passphrase = self.entry_storage_passphrase.get_text()
-
- # Let's execute the unlocking in a thread
- def do_unlock_storage(unlock_method, passphrase, unlocked_cb,
- failed_cb):
- if unlock_method(passphrase):
- GLib.idle_add(unlocked_cb)
- else:
- GLib.idle_add(failed_cb)
-
- unlocking_thread = threading.Thread(
- target=do_unlock_storage,
- args=(self.greeter.persistence.unlock,
- passphrase,
- unlocked_cb,
- failed_cb)
-
- )
- unlocking_thread.start()
-
- def cb_unlock_failed(self):
- logging.debug("Storage unlock failed")
- self.checkbutton_storage_show_passphrase.set_visible(True)
- self.entry_storage_passphrase.set_sensitive(True)
- self.button_storage_unlock.set_sensitive(True)
- self.button_storage_unlock.set_label(_("Unlock"))
- self.image_storage_state.set_visible(True)
- self.spinner_storage_unlock.set_visible(False)
- self.label_infobar_persistence.set_label(
- _("Cannot unlock encrypted storage with this passphrase."))
- self.infobar_persistence.set_visible(True)
- self.entry_storage_passphrase.select_region(0, -1)
- self.entry_storage_passphrase.set_icon_from_icon_name(
- Gtk.EntryIconPosition.SECONDARY,
- 'dialog-warning-symbolic')
- self.entry_storage_passphrase.grab_focus()
-
- def cb_unlocked(self):
- logging.debug("Storage unlocked")
- self.spinner_storage_unlock.set_visible(False)
- self.entry_storage_passphrase.set_visible(False)
- self.button_storage_unlock.set_visible(False)
- self.infobar_persistence.set_visible(False)
- self.image_storage_state.set_from_icon_name('tails-unlocked',
- Gtk.IconSize.BUTTON)
- self.image_storage_state.set_visible(True)
- self.box_storage_unlocked.set_visible(True)
-
-
-class GreeterSettingsCollection(object):
- def __init__(self, greeter, builder):
- # Region settings
- self.text = TextSetting(greeter, builder)
- self.keyboard = KeyboardSetting(greeter, builder)
- self.formats = FormatsSetting(greeter, builder)
- self.timezone = TimezoneSetting(greeter, builder)
-
- # Additional settings views
- self.admin = AdminSetting(greeter, builder)
- self.macspoof = MACSpoofSetting(greeter, builder)
- self.network = NetworkSetting(greeter, builder)
- self.camouflage = CamouflageSetting(greeter, builder)
-
- def __getitem__(self, key):
- return self.__getattribute__(key)
-
- def __iter__(self):
- return iter([getattr(self, k) for k in self.__dict__.keys()])
-
-
-class DialogAddSetting(Gtk.Dialog):
- def __init__(self, builder, settings):
- super().__init__(use_header_bar=True)
- self.build_ui(builder)
- self.settings = settings
-
- def build_ui(self, builder):
- tailsgreeter.utils.import_builder_objects(self, builder, [
- 'box_admin_popover',
- 'box_camouflage_popover',
- 'box_macspoof_popover',
- 'box_network_popover',
- 'entry_admin_password',
- 'listbox_add_setting',
- 'listboxrow_admin',
- 'listboxrow_camouflage',
- 'listboxrow_macspoof',
- 'listboxrow_network',
- ])
-
- self.set_transient_for(self)
- self.set_title(_("Additional Settings"))
- self.set_default_size(-1, ADD_SETTING_DIALOG_PREFERRED_WIDTH)
-
- sizegroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)
-
- accelgroup = Gtk.AccelGroup.new()
- self.add_accel_group(accelgroup)
-
- self.button_cancel = self.add_button(_("Cancel"),
- Gtk.ResponseType.CANCEL)
- accelgroup.connect(Gdk.KEY_Escape, 0, 0,
- self.cb_accelgroup_cancel_activated)
- sizegroup.add_widget(self.button_cancel)
-
- self.button_add = self.add_button(_("Add"), Gtk.ResponseType.YES)
- Gtk.StyleContext.add_class(self.button_add.get_style_context(),
- 'suggested-action')
- sizegroup.add_widget(self.button_add)
- accelgroup.connect(Gdk.KEY_Return, 0, 0,
- self.cb_accelgroup_add_activated)
- self.button_add.set_visible(False)
-
- self.button_back = Gtk.Button.new_with_label(_("Back"))
- self.button_back.set_visible(False)
- self.button_back.connect('clicked', self.cb_button_back_clicked, None)
- sizegroup.add_widget(self.button_back)
- accelgroup.connect(Gdk.KEY_Back, 0, 0,
- self.cb_accelgroup_back_activated)
- # These key bindings are copied from Firefox, and are the same with
- # right-to-left languages.
- accelgroup.connect(Gdk.KEY_Left, Gdk.ModifierType.MOD1_MASK, 0,
- self.cb_accelgroup_back_activated)
- accelgroup.connect(Gdk.KEY_KP_Left, Gdk.ModifierType.MOD1_MASK, 0,
- self.cb_accelgroup_back_activated)
- self.get_header_bar().pack_end(self.button_back)
-
- self.stack = Gtk.Stack()
- self.stack.add_named(self.listbox_add_setting, "setting-type")
- self.listbox_add_setting.set_valign(Gtk.Align.FILL)
- self.listbox_add_setting.set_vexpand(True)
- self.stack.set_visible(True)
- # XXX: is SLIDE_LEFT_RIGHT automatically inversed in RTL mode?
- self.stack.set_transition_type(
- Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
- self.get_content_area().add(self.stack)
-
- def go_back(self):
- self.stack.set_visible_child_name('setting-type')
- self.button_back.set_visible(False)
- self.button_add.set_visible(False)
- self.stack.remove(self.stack.get_child_by_name('setting-details'))
-
- def listbox_focus(self):
- # Workaround autoselection of 1st item on focus
- self.listbox_add_setting.unselect_all()
-
- def listbox_row_activated(self, row):
- if not row: # this happens when the row gets unselected
- return False
- setting_id = tailsgreeter.utils.setting_id_from_row(row)
- self.stack.add_named(self.settings[setting_id].box, 'setting-details')
- self.stack.set_visible_child_name('setting-details')
- # XXX: this is an ugly workaround for a buggy default focus
- if setting_id == "admin":
- self.entry_admin_password.grab_focus()
- self.button_back.set_visible(True)
- self.button_add.set_visible(True)
-
- def run(self, setting_id=None):
- if setting_id:
- row = self.settings[setting_id].listboxrow
- row.emit("activate")
- else:
- self.stack.set_visible_child_name('setting-type')
- self.button_back.set_visible(False)
- self.button_add.set_visible(False)
- return super().run()
-
- def cb_accelgroup_add_activated(self, accel_group, accelerable, keyval,
- modifier, user_data=None):
- if self.button_add.get_visible() and self.button_add.get_sensitive():
- self.response(Gtk.ResponseType.YES)
- return False
-
- def cb_accelgroup_back_activated(self, accel_group, accelerable, keyval,
- modifier, user_data=None):
- self.go_back()
- return False
-
- def cb_accelgroup_cancel_activated(self, accel_group, accelerable, keyval,
- modifier, user_data=None):
- self.response(Gtk.ResponseType.CANCEL)
- return True # disable the default callbacks that destroys the dialog
-
- def cb_button_back_clicked(self, widget, user_data=None):
- self.go_back()
- return False
-
-
-class GreeterMainWindow(Gtk.Window, TranslatableWindow):
-
- def __init__(self, greeter):
- Gtk.Window.__init__(self, title=_(tailsgreeter.APPLICATION_TITLE))
- TranslatableWindow.__init__(self, self)
- self.greeter = greeter
-
- self._build_ui()
- self.store_translations(self)
-
- self.connect('delete-event', self.cb_window_delete_event, None)
- self.set_position(Gtk.WindowPosition.CENTER)
-
- # Utility methods
-
- def __align_checkbuttons(self):
- """Put the text before the checkbox rather than the opposite (assuming
- LTR), because it's what designers want."""
- for checkbutton in [self.checkbutton_language_save,
- self.checkbutton_storage_show_passphrase,
- self.checkbutton_settings_save]:
- checkbutton.set_direction(not Gtk.Widget.get_default_direction())
-
- def _build_accelerators(self):
- accelgroup = Gtk.AccelGroup.new()
- self.add_accel_group(accelgroup)
- for accel_key in [s.accel_key for s in self.settings if s.accel_key]:
- accelgroup.connect(
- accel_key,
- Gdk.ModifierType.SHIFT_MASK | Gdk.ModifierType.CONTROL_MASK,
- Gtk.AccelFlags.VISIBLE,
- self.cb_accelgroup_setting_activated)
-
- def _build_headerbar(self):
- headerbar = Gtk.HeaderBar()
- headerbar_sizegroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)
-
- self.button_shutdown = Gtk.Button.new_with_label(_("Shutdown"))
- self.button_shutdown.connect('clicked', self.cb_button_shutdown_clicked)
- headerbar_sizegroup.add_widget(self.button_shutdown)
- headerbar.pack_start(self.button_shutdown)
-
- self.button_start = Gtk.Button.new_with_mnemonic(_("_Start Tails"))
- Gtk.StyleContext.add_class(self.button_start.get_style_context(),
- 'suggested-action')
- self.button_start.connect('clicked', self.cb_button_start_clicked)
- headerbar_sizegroup.add_widget(self.button_start)
- headerbar.pack_end(self.button_start)
-
- # XXX-future: the button Take a tour is for phase 2
- # button_tour = Gtk.Button.new_with_label(_("Take a Tour"))
- # button_tour.connect('clicked', self.cb_button_tour_clicked)
- # headerbar_sizegroup.add_widget(button_tour)
- # headerbar.pack_end(button_tour)
-
- headerbar.show_all()
-
- return headerbar
-
- def _build_ui(self):
- # Load custom CSS
- css_provider = Gtk.CssProvider.new()
- css_provider.load_from_path(tailsgreeter.config.data_path + CSS_FILE)
- Gtk.StyleContext.add_provider_for_screen(
- Gdk.Screen.get_default(),
- css_provider,
- Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
-
- # Load UI interface definition
- builder = Gtk.Builder()
- builder.set_translation_domain(TRANSLATION_DOMAIN)
- builder.add_from_file(tailsgreeter.config.data_path + UI_FILE)
- builder.connect_signals(self)
-
- for widget in builder.get_objects():
- # Store translations for the builder objects
- self.store_translations(widget)
- # Workaround Gtk bug #710888 - GtkInfoBar not shown after calling
- # gtk_widget_show:
- # https://bugzilla.gnome.org/show_bug.cgi?id=710888
- if isinstance(widget, Gtk.InfoBar):
- revealer = widget.get_template_child(Gtk.InfoBar, 'revealer')
- revealer.set_transition_type(Gtk.RevealerTransitionType.NONE)
-
- tailsgreeter.utils.import_builder_objects(self, builder, [
- 'box_admin_popover',
- 'box_camouflage_popover',
- 'box_language',
- 'box_language_header',
- 'box_macspoof_popover',
- 'box_main',
- 'box_network_popover',
- 'box_settings',
- 'box_settings_header',
- 'box_settings_values',
- 'box_storage',
- 'box_storage_unlock',
- 'box_storage_unlocked',
- 'button_storage_configure',
- 'checkbutton_language_save',
- 'checkbutton_settings_save',
- 'checkbutton_storage_show_passphrase',
- 'entry_admin_verify',
- 'entry_storage_passphrase',
- 'frame_language',
- 'label_settings_default',
- 'listbox_add_setting',
- 'listbox_settings',
- 'listboxrow_formats',
- 'listboxrow_keyboard',
- 'listboxrow_admin',
- 'listboxrow_camouflage',
- 'listboxrow_macspoof',
- 'listboxrow_network',
- 'listboxrow_text',
- 'listboxrow_tz',
- 'switch_camouflage',
- 'toolbutton_settings_add',
- ])
-
- # Set preferred width
- self.set_default_size(min(Gdk.Screen.get_default().get_width(),
- MAIN_WINDOW_PREFERRED_WIDTH),
- min(Gdk.Screen.get_default().get_height(),
- MAIN_WINDOW_PREFERRED_HEIGHT))
-
- # Add our icon dir to icon theme
- icon_theme = Gtk.IconTheme.get_default()
- icon_theme.prepend_search_path(
- tailsgreeter.config.data_path + ICON_DIR)
-
- # Add placeholder to settings ListBox
- self.listbox_settings.set_placeholder(self.label_settings_default)
-
- # Settings view
- self.settings = GreeterSettingsCollection(self.greeter, builder)
-
- # Persistent storage
- self.persistent_storage = PersistentStorage(self.greeter, builder)
-
- # Add children to ApplicationWindow
- self.add(self.box_main)
- self.set_titlebar(self._build_headerbar())
-
- # Set keyboard focus chain
- self.__set_focus_chain()
-
- # Setup keyboard accelerators
- self._build_accelerators()
-
- # Adapt CheckButtons direction to the mockups
- self.__align_checkbuttons()
-
- # Add settings dialog
- self.dialog_add_setting = DialogAddSetting(builder, self.settings)
- self.dialog_add_setting.set_transient_for(self)
- self.store_translations(self.dialog_add_setting)
-
- # Settings popovers
- self.switch_camouflage.connect('notify::active',
- self.cb_switch_camouflage_active)
-
- def __set_focus_chain(self):
- self.box_language.set_focus_chain([
- self.frame_language,
- self.box_language_header])
- self.box_storage.set_focus_chain([
- self.box_storage_unlock,
- self.box_storage_unlocked,
- self.button_storage_configure,
- self.checkbutton_storage_show_passphrase])
- self.box_settings.set_focus_chain([
- self.box_settings_values,
- self.box_settings_header])
-
- # TranslatableWindow implementation
- def translate_to(self, lang):
- TranslatableWindow.translate_to(self, lang)
- self.__align_checkbuttons()
-
- # Actions
-
- def check_and_login(self):
- if (self.greeter.persistence.has_persistence() and
- self.entry_storage_passphrase.get_text() and
- not self.greeter.persistence.is_unlocked):
- logging.debug("Unlocking persistent storage before login")
- self.persistent_storage.unlock(unlocked_cb=self.finish_login)
- else:
- self.finish_login()
-
- def finish_login(self):
- logging.info("Starting the session")
- self.greeter.login()
- return False
-
- def setting_add(self, setting_id=None):
- response = self.dialog_add_setting.run(setting_id)
- if response == Gtk.ResponseType.YES:
- row = self.listbox_add_setting.get_selected_row()
- setting_id = tailsgreeter.utils.setting_id_from_row(row)
- box = self.__getattribute__("box_{}_popover".format(setting_id))
-
- self.listbox_add_setting.remove(row)
- self.listbox_settings.add(row)
- self.dialog_add_setting.set_visible(False)
- self.dialog_add_setting.stack.remove(box)
- self.settings[setting_id].build_popover()
-
- self.listbox_settings.unselect_all()
- if True not in [c.get_visible() for c in
- self.listbox_add_setting.get_children()]:
- self.toolbutton_settings_add.set_sensitive(False)
- self.dialog_add_setting.set_visible(False)
- else:
- old_details = self.dialog_add_setting.stack.get_child_by_name(
- 'setting-details')
- if old_details:
- self.dialog_add_setting.stack.remove(old_details)
- self.dialog_add_setting.set_visible(False)
-
- def setting_edit(self, setting_id):
- if self.settings[setting_id].has_popover():
- self.settings[setting_id].listboxrow.emit("activate")
- else:
- self.setting_add(setting_id)
-
- def setting_admin_check(self):
- match = self.settings.admin.check()
- self.dialog_add_setting.button_add.set_sensitive(match)
-
- def setting_admin_apply(self):
- if (self.settings.admin.apply() and
- not self.settings.admin.close_popover_if_any()):
- # There is no popover, because we are in the add setting dialog
- self.dialog_add_setting.response(Gtk.ResponseType.YES)
-
- def setting_admin_disable(self):
- self.settings.admin.disable()
- self.settings.admin.close_popover_if_any()
-
- def setting_network_close(self, only_if_popover=False):
- if self.settings.network.close_popover_if_any():
- # we are in the popover
- self.settings.network.show_bridge_info_if_needed()
- elif not only_if_popover:
- # We are in the "Add Additional Setting" dialog
- self.dialog_add_setting.response(Gtk.ResponseType.YES)
-
- def show(self):
- super().show()
- self.button_start.grab_focus()
- self.get_root_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.ARROW))
-
- # Callbacks
-
- # XXX-refactor: some of these callbacks could be totally moved out of this
- # class
-
- def cb_accelgroup_setting_activated(self, accel_group, accelerable,
- keyval, modifier):
- for setting in self.settings:
- if setting.accel_key == keyval:
- self.setting_edit(setting.setting_id)
- return False
-
- def cb_button_admin_disable_clicked(self, widget, user_data=None):
- self.setting_admin_disable()
-
- def cb_linkbutton_help_activate(self, linkbutton, user_data=None):
- linkbutton.set_sensitive(False)
- # Display progress cursor and update the UI
- self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
- while Gtk.events_pending():
- Gtk.main_iteration()
- # Note that we add the "file://" part here, not in the URI.
- # We're forced to add this
- # callback *in addition* to the standard one (Gtk.show_uri),
- # which will do nothing for uri:s without a protocol
- # part. This is critical since we otherwise would open the
- # default browser (iceweasel) in T-G. If pygtk had a mechanism
- # like gtk's g_signal_handler_find() this could be dealt with
- # in a less messy way by just removing the default handler.
- page = linkbutton.get_uri()
- uri = "file:///usr/share/doc/tails/website/" + page
- logging.debug("Opening help window for {}".format(uri))
- helpwindow = GreeterHelpWindow(uri)
- helpwindow.show()
-
- def restore_linkbutton_status(widget, event, linkbutton):
- linkbutton.set_sensitive(True)
- return False
-
- helpwindow.connect('delete-event', restore_linkbutton_status,
- linkbutton)
- # Restore default cursor
- self.get_window().set_cursor(None)
-
- def cb_button_shutdown_clicked(self, widget, user_data=None):
- self.greeter.shutdown()
- return False
-
- def cb_button_start_clicked(self, widget, user_data=None):
- self.check_and_login()
- return False
-
- def cb_button_storage_configure_clicked(self, user_data=None):
- self.persistent_storage.configure()
- return False
-
- def cb_button_tour_clicked(self, user_data=None):
- # XXX-future: the button Take a tour is for phase 2
- raise NotImplementedError
- return False
-
- def cb_button_storage_lock_clicked(self, widget, user_data=None):
- self.persistent_storage.lock()
- return False
-
- def cb_button_storage_unlock_clicked(self, widget, user_data=None):
- self.persistent_storage.unlock()
- return False
-
- def cb_checkbutton_storage_show_passphrase_toggled(self, widget,
- user_data=None):
- self.entry_storage_passphrase.set_visibility(widget.get_active())
-
- def cb_entry_admin_changed(self, editable, user_data=None):
- self.setting_admin_check()
- return False
-
- def cb_entry_admin_focus_out_event(self, widget, event, user_data=None):
- self.setting_admin_apply()
- return False
-
- def cb_entry_admin_password_activate(self, widget, user_data=None):
- self.entry_admin_verify.grab_focus()
- return False
-
- def cb_entry_admin_verify_activate(self, widget, user_data=None):
- self.setting_admin_apply()
- return False
-
- def cb_entry_storage_passphrase_activated(self, entry, user_data=None):
- self.persistent_storage.unlock()
- return False
-
- def cb_entry_storage_passphrase_changed(self, editable, user_data=None):
- self.persistent_storage.passphrase_changed(editable)
- return False
-
- def cb_infobar_close(self, infobar, user_data=None):
- infobar.set_visible(False)
- return False
-
- def cb_infobar_response(self, infobar, response_id, user_data=None):
- infobar.set_visible(False)
- return False
-
- def cb_listbox_add_setting_focus(self, widget, direction, user_data=None):
- self.dialog_add_setting.listbox_focus()
- return False
-
- def cb_listbox_add_setting_row_activated(self, listbox, row,
- user_data=None):
- self.dialog_add_setting.listbox_row_activated(row)
- return False
-
- # XXX-refactor: an object could wrap the whole RegionSettings box
- def cb_listbox_language_row_activated(self, listbox, row, user_data=None):
- setting_id = tailsgreeter.utils.setting_id_from_row(row)
- tailsgreeter.utils.popover_toggle(self.settings[setting_id].popover)
- return False
-
- def cb_listbox_network_button_press(self, widget, event, user_data=None):
- if event.type == Gdk.EventType._2BUTTON_PRESS:
- self.setting_network_close()
- return False
-
- def cb_listbox_macspoof_row_activated(self, listbox, row, user_data=None):
- self.settings.macspoof.row_activated(row)
- self.settings.macspoof.close_popover_if_any()
-
- def cb_listbox_network_row_activated(self, listbox, row, user_data=None):
- self.settings.network.row_activated(row)
- self.setting_network_close(only_if_popover=True)
- return False
-
- def cb_listbox_settings_row_activated(self, listbox, row, user_data=None):
- setting_id = tailsgreeter.utils.setting_id_from_row(row)
- tailsgreeter.utils.popover_toggle(self.settings[setting_id].popover)
- return False
-
- def cb_switch_camouflage_active(self, switch, pspec, user_data=None):
- self.settings.camouflage.switch_active(switch)
- self.settings.camouflage.close_popover_if_any()
-
- def cb_toolbutton_settings_add_clicked(self, user_data=None):
- self.setting_add()
- return False
-
- def cb_toolbutton_settings_mnemonic_activate(self, widget, group_cycling):
- self.setting_add()
- return False
-
- def cb_window_delete_event(self, widget, event, user_data=None):
- # Don't close the toplevel window on user request (e.g. pressing
- # Alt+F4)
- return True
-
-
-class GreeterHelpWindow(Gtk.Window, TranslatableWindow):
- """Displays a modal HTML help window"""
-
- def __init__(self, uri):
- Gtk.Window.__init__(self, title=_(tailsgreeter.APPLICATION_TITLE))
- TranslatableWindow.__init__(self, self)
-
- self._build_ui()
- self.store_translations(self)
-
- self.load_uri(uri)
- # Replace the busy cursor set by the tails-greeter startup script with
- # the default cursor.
- self.get_window().set_cursor(None)
-
- def _build_ui(self):
- self.set_position(Gtk.WindowPosition.CENTER)
-
- # Create HeaderBar
- headerbar = Gtk.HeaderBar()
- headerbar.set_show_close_button(True)
- headerbar.show_all()
-
- # Create webview with custom stylesheet
- css = WebKit2.UserStyleSheet(
- ".sidebar, .banner { display: none; }",
- WebKit2.UserContentInjectedFrames.ALL_FRAMES,
- WebKit2.UserStyleLevel.USER,
- None,
- None)
- content_manager = WebKit2.UserContentManager()
- content_manager.add_style_sheet(css)
- self.webview = WebKit2.WebView.new_with_user_content_manager(
- content_manager)
- self.webview.connect("resource-load-started",
- self.cb_load_started)
- self.webview.show()
-
- scrolledwindow = Gtk.ScrolledWindow()
- scrolledwindow.add(self.webview)
- scrolledwindow.show()
-
- # Add children to ApplicationWindow
- self.add(scrolledwindow)
- self.set_titlebar(headerbar)
-
- def load_uri(self, uri):
- self.webview.load_uri(uri)
- self.resize(
- min(HELP_WINDOW_PREFERRED_WIDTH,
- self.get_screen().get_width()),
- self.get_screen().get_height())
- self.present()
-
- def cb_load_started(self, web_view, ressource, request):
- if not request.get_uri().startswith("file://"):
- webbrowser.open_new(request.get_uri())
- request.set_uri(web_view.get_uri())
-
-
-class GreeterBackgroundWindow(Gtk.ApplicationWindow):
-
- def __init__(self, app):
- Gtk.Window.__init__(self, title=_(tailsgreeter.APPLICATION_TITLE),
- application=app)
- self.override_background_color(
- Gtk.StateFlags.NORMAL, Gdk.RGBA(0, 0, 0, 1))
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/language.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/language.py
deleted file mode 100644
index 68bb76d..0000000
--- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/language.py
+++ /dev/null
@@ -1,861 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Copyright 2012-2016 Tails developers <tails@boum.org>
-# Copyright 2011 Max <govnototalitarizm@gmail.com>
-# Copyright 2011 Martin Owens
-#
-# This program 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.
-#
-# This program 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 this program. If not, see <http://www.gnu.org/licenses/>
-#
-"""Localization handling
-
-"""
-
-import logging
-import gettext
-import os
-import locale
-
-import gi
-import pycountry
-import pytz
-
-gi.require_version('Gio', '2.0')
-from gi.repository import Gio # NOQA: E402
-gi.require_version('GLib', '2.0')
-from gi.repository import GLib # NOQA: E402
-gi.require_version('GObject', '2.0')
-from gi.repository import GObject # NOQA: E402
-gi.require_version('GnomeDesktop', '3.0')
-from gi.repository import GnomeDesktop # NOQA: E402
-gi.require_version('Gtk', '3.0')
-from gi.repository import Gtk # NOQA: E402
-gi.require_version('AccountsService', '1.0')
-from gi.repository import AccountsService # NOQA: E402
-
-import tailsgreeter.config # NOQA: E402
-
-from tailsgreeter import TRANSLATION_DOMAIN
-
-
-def ln_iso639_tri(ln_CC):
- """get iso639 3-letter code from a language code
-
- example: en -> eng"""
- return pycountry.languages.get(
- alpha2=language_from_locale(ln_CC)).terminology
-
-
-def ln_iso639_2_T_to_B(lng):
- """Convert a ISO-639-2/T code (e.g. deu for German) to a 639-2/B one
- (e.g. ger for German)"""
- return pycountry.languages.get(terminology=lng).bibliographic
-
-
-def language_from_locale(locale):
- """Obtain the language code from a locale code
-
- example: fr_FR -> fr"""
- return locale.split('_')[0]
-
-
-def languages_from_locales(locales):
- """Obtain a language code list from a locale code list
-
- example: [fr_FR, en_GB] -> [fr, en]"""
- language_codes = []
- for l in locales:
- language_code = language_from_locale(l)
- if language_code not in language_codes:
- language_codes.append(language_code)
- return language_codes
-
-
-def country_from_locale(locale):
- """Obtain the country code from a locale code
-
- example: fr_FR -> FR"""
- return locale.split('_')[1]
-
-
-def countries_from_locales(locales):
- """Obtain a country code list from a locale code list
-
- example: [fr_FR, en_GB] -> [FR, GB]"""
- country_codes = []
- for l in locales:
- country_code = country_from_locale(l)
- if country_code not in country_codes:
- country_codes.append(country_code)
- return country_codes
-
-
-class TranslatableWindow(object):
- """Interface providing functions to translate a window on the fly
- """
- retain_focus = True
- registered_windows = []
-
- def __init__(self, window):
- self.window = window
- self.translation = gettext.translation(
- TRANSLATION_DOMAIN,
- tailsgreeter.config.locales_path,
- fallback=True
- )
-
- self.containers = []
- self.labels = {}
- self.placeholder_texts = {}
- self.titles = {}
- self.tooltips = {}
-
- TranslatableWindow.registered_windows.append(window)
-
- @staticmethod
- def get_locale_direction(lang):
- """Return Gtk.TextDirection for lang
-
- This method in basically the same as Gtk.get_locale_direction
- (gtk_get_locale_direction in gtk/gtkmain.c), but it accepts a lang
- parameter rather than using current locale.
- """
- gtk_translation = gettext.translation("gtk30",
- languages=[str(lang)],
- fallback=True)
- logging.debug("%s has GTK translation: %s" % (lang, gtk_translation))
- # Translators: please do not translate this string (it is read from
- # Gtk translation)
- default_dir = gtk_translation.gettext("default:LTR")
- logging.debug("translation for direction is %s" % (default_dir))
- if default_dir == "default:RTL":
- logging.debug("%s is RTL" % lang)
- return Gtk.TextDirection.RTL
- else:
- return Gtk.TextDirection.LTR
-
- def store_translations(self, widget):
- """Store the elements that should be localised inside widget
-
- Go through all children of widget and store the translations
- of labels, tooltips and titles and the containers whose text direction
- should be updated when switching between LTR and RTL.
-
- This method should be called once the widgets are created"""
- if not isinstance(widget, Gtk.Widget):
- logging.debug("%s is not a Gtk.Widget" % widget)
- return None
- if isinstance(widget, Gtk.Label) or isinstance(widget, Gtk.Button):
- if widget not in self.labels:
- self.labels[widget] = widget.get_label()
- # Wrap set_label to get notified about string changes
- widget.original_set_label = widget.set_label
-
- def wrapped_set_label(text):
- self.labels[widget] = text
- widget.original_set_label(self.gettext(text))
- widget.set_label = wrapped_set_label
- elif isinstance(widget, Gtk.Entry):
- if widget not in self.placeholder_texts:
- self.placeholder_texts[widget] = widget.get_placeholder_text()
- elif isinstance(widget, Gtk.Container):
- self.containers.append(widget)
- if ((isinstance(widget, Gtk.HeaderBar) or
- isinstance(widget, Gtk.Window)) and
- widget not in self.titles and
- widget.get_title()):
- self.titles[widget] = widget.get_title()
- for child in widget.get_children():
- self.store_translations(child)
- else:
- logging.debug("W: unhandled widget: %s" % widget)
- if widget.get_has_tooltip():
- if widget not in self.tooltips:
- self.tooltips[widget] = widget.get_tooltip_text()
-
- def gettext(self, text):
- """Return text, translated if possible"""
- if self.translation and text:
- text = self.translation.gettext(text)
- return text
-
- def translate_to(self, lang):
- """Translate registered widgets on the fly
-
- Loop through widgets registered with store_translations and translate
- them on the fly"""
- logging.debug("translating %s to %s" % (self, lang))
- try:
- self.translation = gettext.translation(
- TRANSLATION_DOMAIN,
- tailsgreeter.config.locales_path, [str(lang)])
- except IOError:
- self.translation = None
-
- text_direction = self.get_locale_direction(lang)
- for container in self.containers:
- container.set_default_direction(text_direction)
- for widget, label in self.labels.items():
- if label:
- widget.original_set_label(self.gettext(label))
- for widget in self.placeholder_texts.keys():
- widget.set_placeholder_text(self.gettext(self.placeholder_texts[widget]))
- for widget in self.titles.keys():
- widget.set_title(self.gettext(self.titles[widget]))
- for widget in self.tooltips.keys():
- widget.set_tooltip_markup(self.gettext(self.tooltips[widget]))
- if (self.window.get_sensitive() and
- self.window.get_visible() and
- self.retain_focus):
- self.window.present()
-
- @staticmethod
- def translate_all(lang):
- for widget in TranslatableWindow.registered_windows:
- widget.translate_to(lang)
-
-
-class RegionSetting(GObject.Object):
-
- value = GObject.property(type=str)
- is_default = GObject.property(type=bool, default=True)
-
- def __init__(self, settings_object):
- super().__init__()
- self._settings = settings_object
-
- def get_value(self):
- return self.value
-
- # is_default will be used by subclasses to register default value
- def set_value(self, value, is_default=False):
- self.value = value
- if not is_default:
- self.is_default = False
- self._settings._apply_settings_to_upcoming_session()
-
- def get_name(self):
- raise NotImplementedError
-
- def get_tree(self):
- raise NotImplementedError
-
- def set_default(self):
- raise NotImplementedError
-
- def set_default_if_needed(self):
- """Update default value if it was not user choosen"""
- if self.is_default:
- self.set_default()
-
-
-class TextSetting(RegionSetting):
-
- def __init__(self, settings_object):
- super().__init__(settings_object)
- super().set_value('en_US', is_default=True)
-
- def get_tree(self, locale_codes=None):
- if not locale_codes:
- locale_codes = self._settings._system_locales_list
-
- treestore = Gtk.TreeStore(GObject.TYPE_STRING, # id
- GObject.TYPE_STRING) # name
-
- lang_codes = languages_from_locales(
- self._settings._system_locales_list)
- lang_codes.sort(key=lambda x: self._language_name(x).lower())
- for lang_code in lang_codes:
- language_name = self._language_name(lang_code)
- if not language_name:
- # Don't display languages without a name
- continue
- treeiter_language = treestore.append(parent=None)
- treestore.set(treeiter_language,
- 0, self.get_default_locale(lang_code))
- treestore.set(treeiter_language, 1, language_name)
- locale_codes = sorted(
- self.get_default_locales(lang_code),
- key=lambda x: self._locale_name(x).lower())
- if len(locale_codes) > 1:
- for locale_code in locale_codes:
- treeiter_locale = treestore.append(
- parent=treeiter_language)
- treestore.set(treeiter_locale, 0, locale_code)
- treestore.set(treeiter_locale, 1,
- self._locale_name(locale_code))
- return treestore
-
- def get_name(self):
- return self._locale_name(self.get_value())
-
- def get_default_locales(self, lang_code):
- """Return available locales for given language
-
- """
- if lang_code in self._settings._system_languages_dict:
- return self._settings._system_languages_dict[lang_code]
-
- def get_default_locale(self, lang_code=None):
- """Return default locale for given language
-
- Returns the 1st locale among:
- - the locale whose country name matches language name
- - the 1st locale for the language
- - en_US
- """
- default_locales = self.get_default_locales(lang_code)
- if default_locales:
- for locale_code in default_locales:
- if (country_from_locale(locale_code).lower() ==
- language_from_locale(locale_code)):
- return locale_code
- return default_locales[0]
- else:
- return 'en_US'
-
- def set_value(self, locale, is_default=False):
- super().set_value(locale, is_default)
- self.__apply_locale()
- self._settings.formats.set_default_if_needed() # XXX: notify
- self._settings.layout.set_default_if_needed() # XXX: notify
- if self._settings._locale_selected_cb:
- self._settings._locale_selected_cb(locale)
-
- def _language_name(self, lang_code):
- default_locale = 'C'
- local_locale = self.get_default_locale(lang_code)
- try:
- native_name = GnomeDesktop.get_language_from_code(
- lang_code, local_locale).capitalize()
- except AttributeError:
- return ""
- localized_name = GnomeDesktop.get_language_from_code(
- lang_code, default_locale).capitalize()
- if native_name == localized_name:
- return native_name
- else:
- return "{native} ({localized})".format(
- native=native_name, localized=localized_name)
-
- def _locale_name(self, locale_code):
- lang_code = language_from_locale(locale_code)
- country_code = country_from_locale(locale_code)
- language_name_locale = GnomeDesktop.get_language_from_code(lang_code)
- language_name_native = GnomeDesktop.get_language_from_code(
- lang_code, locale_code)
- country_name_locale = GnomeDesktop.get_country_from_code(country_code)
- country_name_native = GnomeDesktop.get_country_from_code(
- country_code, locale_code)
- try:
- if (language_name_native == language_name_locale and
- country_name_native == country_name_locale):
- return "{language} - {country}".format(
- language=language_name_native.capitalize(),
- country=country_name_native)
- else:
- return "{language} - {country} " \
- "({local_language} - {local_country})".format(
- language=language_name_native.capitalize(),
- country=country_name_native,
- local_language=language_name_locale.capitalize(),
- local_country=country_name_locale)
- except AttributeError:
- return locale_code
-
- def __apply_locale(self):
- locale_code = locale.normalize(
- self.get_value() + '.' + locale.getpreferredencoding())
- logging.debug("Setting session language to %s", locale_code)
- if self._settings._act_user:
- GLib.idle_add(
- lambda: self._settings._act_user.set_language(locale_code))
- else:
- logging.warning("AccountsManager not ready")
-
-
-class FormatSetting(RegionSetting):
- def __init__(self, settings_object):
- super().__init__(settings_object)
- super().set_value('en_US', is_default=True)
-
- def get_tree(self, format_codes=None):
- if not format_codes:
- format_codes = self._settings._system_locales_list
-
- treestore = Gtk.TreeStore(GObject.TYPE_STRING, # id
- GObject.TYPE_STRING) # name
-
- format_codes = countries_from_locales(
- self._settings._system_locales_list)
- format_codes.sort(key=lambda x: self._country_name(x).lower())
- logging.debug("format_codes=%s" % format_codes)
- for format_code in format_codes:
- format_name = self._country_name(format_code)
- if not format_name:
- # Don't display languages without a name
- continue
- treeiter_format = treestore.append(parent=None)
- treestore.set(treeiter_format,
- 0, self.get_default_locale(format_code))
- treestore.set(treeiter_format, 1, format_name)
- locale_codes = sorted(
- self.get_default_locales(format_code),
- key=lambda x: self._locale_name(x).lower())
- if len(locale_codes) > 1:
- for locale_code in locale_codes:
- treeiter_locale = treestore.append(
- parent=treeiter_format)
- treestore.set(treeiter_locale, 0, locale_code)
- treestore.set(treeiter_locale, 1,
- self._locale_name(locale_code))
- return treestore
-
- def get_name(self):
- return self._locale_name(self.get_value())
-
- def get_default_locales(self, country_code):
- """Return available locales for given country
-
- """
- if country_code in self._settings._system_formats_dict:
- return self._settings._system_formats_dict[country_code]
-
- def get_default_locale(self, country_code=None):
- """Return default locale for given country
-
- Returns the 1st locale among:
- - the locale whose country name matches country name
- - the 1st locale for the language
- - en_US
- """
- default_locales = self.get_default_locales(country_code)
- if default_locales:
- for locale_code in default_locales:
- if (country_from_locale(locale_code).lower() ==
- language_from_locale(locale_code)):
- return locale_code
- return default_locales[0]
- else:
- return 'en_US'
-
- def _country_name(self, country_code):
- default_locale = 'C'
- local_locale = self.get_default_locale(country_code)
- native_name = GnomeDesktop.get_country_from_code(
- country_code, local_locale)
- if not native_name:
- return ""
- localized_name = GnomeDesktop.get_country_from_code(
- country_code, default_locale)
- if native_name == localized_name:
- return native_name
- else:
- return "{native} ({localized})".format(
- native=native_name, localized=localized_name)
-
- def _locale_name(self, locale_code):
- lang_code = language_from_locale(locale_code)
- country_code = country_from_locale(locale_code)
- language_name_locale = GnomeDesktop.get_language_from_code(lang_code)
- language_name_native = GnomeDesktop.get_language_from_code(
- lang_code, locale_code)
- country_name_locale = GnomeDesktop.get_country_from_code(country_code)
- country_name_native = GnomeDesktop.get_country_from_code(
- country_code, locale_code)
- try:
- if (language_name_native == language_name_locale and
- country_name_native == country_name_locale):
- return "{country} - {language}".format(
- language=language_name_native.capitalize(),
- country=country_name_native)
- else:
- return "{country} - {language} " \
- "({local_country} - {local_language})".format(
- language=language_name_native.capitalize(),
- country=country_name_native,
- local_language=language_name_locale.capitalize(),
- local_country=country_name_locale)
- except AttributeError:
- return locale_code
-
- def set_default(self):
- """Set default format for current language
-
- Select the same locale for formats that the language
- """
- default_format = self._settings.text.get_value()
- logging.debug("setting default formats to %s" % default_format)
- self.set_value(default_format, is_default=True)
-
-
-class LayoutSetting(RegionSetting):
-
- def __init__(self, settings_object):
- super().__init__(settings_object)
- super().set_value('en+us', is_default=True)
- self.__xklinfo = GnomeDesktop.XkbInfo()
-
- def get_tree(self, layout_codes=None):
- if not layout_codes:
- layout_codes = self.get_all()
-
- treestore = Gtk.TreeStore(GObject.TYPE_STRING, # id
- GObject.TYPE_STRING) # name
- layouts = self._layouts_split_names(layout_codes)
- for group_name in sorted(layouts.keys()):
- layout_codes = sorted(
- layouts[group_name],
- key=lambda x: self._layout_name(x).lower())
- treeiter_group = treestore.append(parent=None)
- # we fill the title with the 1st layout of the group
- treestore.set(treeiter_group, 0, layout_codes[0])
- treestore.set(treeiter_group, 1, group_name)
- if len(layout_codes) > 1:
- for layout_code in layout_codes:
- treeiter_layout = treestore.append(parent=treeiter_group)
- treestore.set(treeiter_layout, 0, layout_code)
- treestore.set(treeiter_layout, 1,
- self._layout_name(layout_code))
- return treestore
-
- def get_name(self):
- return self._layout_name(self.get_value())
-
- def get_all(self):
- """Return a list of all keyboard layout codes
-
- """
- return self.__xklinfo.get_all_layouts()
-
- def get_defaults(self):
- """Return list of supported keyboard layouts for current language
-
- """
- lang_code = language_from_locale(self._settings.text.get_value())
- layouts = self._layouts_for_language(lang_code)
- if not layouts:
- country_code = country_from_locale(self._settings.text.get_value())
- layouts = self._layouts_for_country(country_code)
- if not layouts:
- layouts = ['us']
- return layouts
-
- def set_value(self, layout, is_default=False):
- super().set_value(layout, is_default)
- self._apply_layout_to_current_screen()
-
- def _layout_name(self, layout_code):
- id, display_name, short_name, xkb_layout, xkb_variant = \
- self.__xklinfo.get_layout_info(layout_code)
- return display_name
-
- def _layouts_split_names(self, layout_codes):
- layouts_names = {}
- for layout_code in layout_codes:
- layout_name = self._layout_name(layout_code)
- country_name, s, v = layout_name.partition(' (')
- if country_name not in layouts_names:
- layouts_names[country_name] = set([layout_code])
- else:
- layouts_names[country_name].add(layout_code)
- return layouts_names
-
- def _layouts_for_language(self, lang_code):
- """Return the list of available layouts for given language
- """
- layouts = []
- try:
- t_code = ln_iso639_tri(lang_code)
- except KeyError:
- t_code = lang_code
- if t_code == 'nno' or t_code == 'nob':
- t_code = 'nor'
-
- layouts = self.__xklinfo.get_layouts_for_language(t_code)
-
- if t_code == 'hrv':
- layouts.append('hr')
-
- if len(layouts) == 0:
- b_code = ln_iso639_2_T_to_B(t_code)
- logging.debug(
- "got no layout for ISO-639-2/T code %s, "
- "trying with ISO-639-2/B code %s",
- t_code, b_code)
-
- layouts = self.__xklinfo.get_layouts_for_language(b_code)
-
- logging.debug('got %d layouts for %s', len(layouts), lang_code)
- return layouts
-
- def _layouts_for_country(self, country):
- """Return the list of available layouts for given country
- """
- # XXX: it would be logical to use:
- # self.__xklinfo.get_layouts_for_language(country)
- # but it doesn't actually return the list of all layouts matching a
- # country.
- def country_filter(layout):
- cc = country.lower()
- return ((layout == cc)
- or ('+' in layout) and (layout.split('+')[0] == cc))
-
- layouts = list(filter(country_filter, self.get_all()))
-
- logging.debug('got %d layouts for %s', len(layouts), country)
- return layouts
-
- @staticmethod
- def _split_variant(layout_code):
- if '+' in layout_code:
- return layout_code.split('+')
- else:
- return (layout_code, None)
-
- def _filter_layouts(self, layouts, country, language):
- """Try to select the best layout in a layout list
- """
- if len(layouts) > 1:
- def variant_filter(layout):
- layout_name, layout_variant = self._split_variant(layout)
- return layout_variant is None
- filtered_layouts = list(filter(variant_filter, layouts))
- logging.debug("Filter by variant: %s", filtered_layouts)
- if len(filtered_layouts) > 0:
- layouts = filtered_layouts
- if len(layouts) > 1:
- def country_filter(layout):
- layout_name, layout_variant = self._split_variant(layout)
- return layout_variant == country.lower()
- filtered_layouts = list(filter(country_filter, layouts))
- logging.debug("Filter by country %s: %s", country,
- filtered_layouts)
- if len(filtered_layouts) > 0:
- layouts = filtered_layouts
- if len(layouts) > 1:
- def language_filter(layout):
- layout_name, layout_variant = self._split_variant(layout)
- return layout_variant == language
- filtered_layouts = list(filter(language_filter, layouts))
- logging.debug("Filter by language %s: %s", language,
- filtered_layouts)
- if len(filtered_layouts) > 0:
- layouts = filtered_layouts
- return layouts
-
- def set_default(self):
- """Sets the best default layout for the current locale
- """
- default_layout = False
-
- language = language_from_locale(self._settings.text.get_value())
- country = country_from_locale(self._settings.text.get_value())
-
- # First, build a list of layouts to consider for the language
- language_layouts = self._layouts_for_language(language)
- logging.debug("Language %s layouts: %s", language, language_layouts)
- country_layouts = self._layouts_for_country(country)
- logging.debug("Country %s layouts: %s", country, country_layouts)
- layouts = set(language_layouts).intersection(country_layouts)
- logging.debug("Intersection of language %s and country %s: %s",
- language, country, layouts)
- if not len(layouts) > 0:
- def country_filter(layout):
- layout_name, layout_variant = self._split_variant(layout)
- return layout_name == country.lower()
- layouts = list(filter(country_filter, language_layouts))
- logging.debug("Empty intersection of language and country, filter "
- "by country %s only: %s", country, layouts)
- if not len(layouts) > 0:
- def language_filter(layout):
- layout_name, layout_variant = self._split_variant(layout)
- return layout_name == language
- layouts = list(filter(language_filter, language_layouts))
- logging.debug("List still empty, filter by language %s only: %s",
- language, layouts)
- if not len(layouts) > 0:
- layouts = language_layouts
- logging.debug("List still empty, use all language %s layouts: %s",
- language, layouts)
-
- # Then, filter the list
- layouts = self._filter_layouts(layouts, country, language)
- if len(layouts) != 1:
- # Can't find a single result, build a new list for the country
- layouts = country_layouts
- logging.debug("Still not 1 layouts. Try again using all country "
- "%s layouts: %s", country, layouts)
- layouts = self._filter_layouts(layouts, country, language)
- if len(layouts) == 1:
- default_layout = layouts.pop()
- logging.debug("Selecting single matching layout %s",
- default_layout)
- elif len(layouts) > 1:
- default_layout = layouts.pop()
- logging.debug("No good layout, arbitrary using layout %s",
- default_layout)
- else:
- default_layout = 'us'
- logging.debug("Using us as fallback default layout")
- self.set_value(default_layout, is_default=True)
-
- def _apply_layout_to_current_screen(self):
- layout = self.get_value()
- logging.debug("layout=%s" % layout)
-
- settings = Gio.Settings('org.gnome.desktop.input-sources')
- settings.set_value('sources', GLib.Variant('a(ss)', [('xkb', layout)]))
-
-
-class TimezoneSetting(RegionSetting):
-
- def get_tree(self):
- timezones = self.get_all()
- treestore = Gtk.TreeStore(GObject.TYPE_STRING, # id
- GObject.TYPE_STRING) # name
- areas = self._timezone_split_area(timezones)
- for area in sorted(areas.keys()):
- locations = sorted(
- areas[area],
- key=lambda x: self._timezone_name(x).lower())
- treeiter_area = treestore.append(parent=None)
- # we fill the title with the 1st layout of the group
- treestore.set(treeiter_area, 0, locations[0])
- treestore.set(treeiter_area, 1, area)
- if len(locations) > 1:
- for location in locations:
- treeiter_location = treestore.append(parent=treeiter_area)
- treestore.set(treeiter_location, 0, location)
- treestore.set(treeiter_location, 1,
- self._timezone_name(location))
- return treestore
-
- def get_name(self):
- return self._timezone_name(self.get_value())
-
- def get_all(self):
- """Return a list of all timezones
-
- """
- return pytz.common_timezones
-
- def _timezone_name(self, timezone):
- if '/' in timezone:
- area, s, location = timezone.partition('/')
- return location
- else:
- return timezone
-
- def _timezone_split_area(self, timezones):
- timezone_areas = {}
- for timezone in timezones:
- area, s, v = timezone.partition('/')
- if area not in timezone_areas:
- timezone_areas[area] = set([timezone])
- else:
- timezone_areas[area].add(timezone)
- return timezone_areas
-
-
-class LocalisationSettings(object):
- """Controller for localisation settings
-
- """
- def __init__(self, usermanager_loaded_cb=None, locale_selected_cb=None):
- self._usermanager_loaded_cb = usermanager_loaded_cb
- self._locale_selected_cb = locale_selected_cb
-
- self._act_user = None
- self.__actusermanager_loadedid = None
-
- self._system_locales_list = self.__get_langcodes()
- self._system_languages_dict = self.__fill_languages_dict(
- self._system_locales_list)
- self._system_formats_dict = self.__fill_formats_dict(
- self._system_locales_list)
-
- actusermanager = AccountsService.UserManager.get_default()
- self.__actusermanager_loadedid = actusermanager.connect(
- "notify::is-loaded", self.__on_usermanager_loaded)
-
- self.text = TextSetting(self)
- self.formats = FormatSetting(self)
- self.layout = LayoutSetting(self)
- self.timezone = TimezoneSetting(self)
-
- def __del__(self):
- if self.__actusermanager_loadedid:
- self.__actusermanager.disconnect(self.__actusermanager_loadedid)
-
- def __get_langcodes(self):
- with open(tailsgreeter.config.default_langcodes_path, 'r') as f:
- defcodes = [line.rstrip('\n') for line in f.readlines()]
- with open(tailsgreeter.config.language_codes_path, 'r') as f:
- langcodes = [line.rstrip('\n') for line in f.readlines()]
- logging.debug('%s languages found', len(langcodes))
- return defcodes + langcodes
-
- def __on_usermanager_loaded(self, manager, pspec, data=None):
- logging.debug("Received AccountsManager signal is-loaded")
- act_user = manager.get_user(tailsgreeter.config.LUSER)
- if not act_user.is_loaded():
- raise RuntimeError("User manager for %s not loaded"
- % tailsgreeter.config.LUSER)
- self._act_user = act_user
- if self._usermanager_loaded_cb:
- self._usermanager_loaded_cb()
-
- def __fill_languages_dict(self, locale_codes):
- """assemble dictionary of language codes to corresponding locales list
-
- example {en: [en_US, en_GB], ...}"""
- languages_dict = {}
- for locale_code in locale_codes:
- lang_code = language_from_locale(locale_code)
- if lang_code not in languages_dict:
- languages_dict[lang_code] = []
- if locale_code not in languages_dict[lang_code]:
- languages_dict[lang_code].append(locale_code)
- return languages_dict
-
- def __fill_formats_dict(self, locale_codes):
- """assemble dictionary of country codes to corresponding locales list
-
- example {FR: [fr_FR, en_FR], ...}"""
- formats_dict = {}
- for locale_code in locale_codes:
- country_code = country_from_locale(locale_code)
- if country_code not in formats_dict:
- formats_dict[country_code] = []
- if locale_code not in formats_dict[country_code]:
- formats_dict[country_code].append(locale_code)
- return formats_dict
-
- def _apply_settings_to_upcoming_session(self):
- with open(tailsgreeter.config.locale_output_path, 'w') as f:
- os.chmod(tailsgreeter.config.locale_output_path, 0o600)
- if hasattr(self, "text"):
- f.write('TAILS_LOCALE_NAME=%s\n' % self.text.get_value())
- if hasattr(self, "formats"):
- f.write('TAILS_FORMATS=%s\n' % self.formats.get_value())
- if hasattr(self, "layout"):
- try:
- layout, variant = self.layout.get_value().split('+')
- except ValueError:
- layout = self.layout.get_value()
- variant = ''
- # XXX: use default value from /etc/default/keyboard
- f.write('TAILS_XKBMODEL=%s\n' % 'pc105')
- f.write('TAILS_XKBLAYOUT=%s\n' % layout)
- f.write('TAILS_XKBVARIANT=%s\n' % variant)
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/physicalsecurity.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/physicalsecurity.py
deleted file mode 100644
index 75b744b..0000000
--- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/physicalsecurity.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright 2013-2016 Tails developers <tails@boum.org>
-#
-# This program 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.
-#
-# This program 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 this program. If not, see <http://www.gnu.org/licenses/>
-#
-"""Physical security settings
-
-"""
-import os
-import logging
-import pipes
-
-import tailsgreeter.config
-
-
-class PhysicalSecuritySettings(object):
- """Model storing settings related to physical security
-
- """
-
- NETCONF_DIRECT = "direct"
- NETCONF_OBSTACLE = "obstacle"
- NETCONF_DISABLED = "disabled"
-
- def __init__(self):
- # Whether to run macspoof
- self._netconf = self.NETCONF_DIRECT
- self._macspoof = True
- self.write_settings()
-
- def write_settings(self):
- physical_security_settings_file = \
- tailsgreeter.config.physical_security_settings
- with open(physical_security_settings_file, 'w') as f:
- os.chmod(physical_security_settings_file, 0o600)
- f.write('TAILS_NETCONF={0}\n'.format(
- pipes.quote(self.netconf)))
- f.write('TAILS_MACSPOOF_ENABLED={0}\n'.format(
- pipes.quote(str(self.macspoof).lower())))
- logging.debug('physical security settings written to %s',
- physical_security_settings_file)
-
- @property
- def netconf(self):
- return self._netconf
-
- @property
- def macspoof(self):
- return self._macspoof
-
- @netconf.setter
- def netconf(self, new_state):
- self._netconf = new_state
- self.write_settings()
-
- @macspoof.setter
- def macspoof(self, new_state):
- self._macspoof = new_state
- self.write_settings()
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/rootaccess.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/rootaccess.py
deleted file mode 100644
index 057f8be..0000000
--- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/rootaccess.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright 2012-2016 Tails developers <tails@boum.org>
-# Copyright 2011 Max <govnototalitarizm@gmail.com>
-# Copyright 2011 Martin Owens
-#
-# This program 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.
-#
-# This program 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 this program. If not, see <http://www.gnu.org/licenses/>
-#
-"""Root access handling
-
-"""
-import os
-import os.path
-import logging
-import pipes
-
-import tailsgreeter.config
-
-
-class RootAccessSettings(object):
- """Model storing settings related to root access
-
- """
- def __init__(self):
- # Root password
- self.password = None
- # XXX: this should read the content of the setting file
-
- @property
- def password(self):
- return self._password
-
- @password.setter
- def password(self, password):
- self._password = password
- if password:
- with open(tailsgreeter.config.rootpassword_output_path, 'w') as f:
- os.chmod(tailsgreeter.config.rootpassword_output_path, 0o600)
- f.write('TAILS_USER_PASSWORD=%s\n'
- % pipes.quote(self.password))
- logging.debug('password written to %s',
- tailsgreeter.config.rootpassword_output_path)
- else:
- try:
- os.unlink(tailsgreeter.config.rootpassword_output_path)
- logging.debug('removed %s',
- tailsgreeter.config.rootpassword_output_path)
- except OSError:
- if not os.path.exists(
- tailsgreeter.config.rootpassword_output_path):
- pass
- else:
- raise
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/__init__.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/__init__.py
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/admin.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/admin.py
new file mode 100644
index 0000000..ae85d34
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/admin.py
@@ -0,0 +1,34 @@
+
+import os
+import os.path
+import logging
+import pipes
+
+import tailsgreeter.config
+
+
+class AdminSetting(object):
+ """Setting controlling the sudo password"""
+
+ def __init__(self):
+ self.password = None
+
+ def apply_to_upcoming_session(self):
+ setting_file = tailsgreeter.config.admin_password_output_path
+
+ if self.password:
+ with open(setting_file, 'w') as f:
+ os.chmod(setting_file, 0o600)
+ f.write('TAILS_USER_PASSWORD=%s\n' % pipes.quote(self.password))
+ logging.debug('password written to %s', setting_file)
+ return
+
+ # Try to remove the password file
+ try:
+ os.unlink(setting_file)
+ logging.debug('removed %s', setting_file)
+ except OSError:
+ # It's bad if the file exists and couldn't be removed, so we
+ # we raise the exception in that case (which prevents the login)
+ if os.path.exists(setting_file):
+ raise
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/formats.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/formats.py
new file mode 100644
index 0000000..b85d205
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/formats.py
@@ -0,0 +1,128 @@
+import logging
+
+import gi
+
+from tailsgreeter.settings.localization import LocalizationSetting, language_from_locale, country_from_locale
+
+gi.require_version('GObject', '2.0')
+gi.require_version('GnomeDesktop', '3.0')
+gi.require_version('Gtk', '3.0')
+from gi.repository import GObject, GnomeDesktop, Gtk
+
+
+class FormatsSetting(LocalizationSetting):
+ def __init__(self, language_codes: [str]):
+ super().__init__()
+ self.value = 'en_US'
+ self.locales_per_country = self._make_locales_per_country_dict(language_codes)
+
+ def get_tree(self) -> Gtk.TreeStore:
+ treestore = Gtk.TreeStore(GObject.TYPE_STRING, # id
+ GObject.TYPE_STRING) # name
+
+ country_codes = list(self.locales_per_country.keys())
+ country_codes.sort(key=lambda x: self._country_name(x).lower())
+ logging.debug("format_codes=%s", country_codes)
+ for country_code in country_codes:
+ country_name = self._country_name(country_code)
+ if not country_name:
+ # Don't display languages without a name
+ continue
+
+ treeiter_format = treestore.append(parent=None)
+ treestore.set(treeiter_format, 0, self.get_default_locale(country_code))
+ treestore.set(treeiter_format, 1, country_name)
+ locales = sorted(self.locales_per_country[country_code],
+ key=lambda x: self._locale_name(x).lower())
+ if len(locales) > 1:
+ for locale in locales:
+ treeiter_locale = treestore.append(parent=treeiter_format)
+ treestore.set(treeiter_locale, 0, locale)
+ treestore.set(treeiter_locale, 1, self._locale_name(locale))
+ return treestore
+
+ def get_name(self) -> str:
+ return self._locale_name(self.get_value())
+
+ def get_default_locale(self, country_code=None) -> str:
+ """Return default locale for given country
+
+ Returns the 1st locale among:
+ - the locale whose country name matches country name
+ - the 1st locale for the language
+ - en_US
+ """
+ locales = self.locales_per_country[country_code]
+ if not locales:
+ return 'en_US'
+
+ # Get the default locale for the country
+ for locale_code in locales:
+ if country_from_locale(locale_code).lower() == language_from_locale(locale_code):
+ return locale_code
+
+ return locales[0]
+
+ def _country_name(self, country_code) -> str:
+ default_locale = 'C'
+ local_locale = self.get_default_locale(country_code)
+ native_name = GnomeDesktop.get_country_from_code(
+ country_code, local_locale)
+ if not native_name:
+ return ""
+ localized_name = GnomeDesktop.get_country_from_code(
+ country_code, default_locale)
+ if native_name == localized_name:
+ return native_name
+ else:
+ return "{native} ({localized})".format(
+ native=native_name, localized=localized_name)
+
+ @staticmethod
+ def _locale_name(locale_code) -> str:
+ lang_code = language_from_locale(locale_code)
+ country_code = country_from_locale(locale_code)
+ language_name_locale = GnomeDesktop.get_language_from_code(lang_code)
+ language_name_native = GnomeDesktop.get_language_from_code(
+ lang_code, locale_code)
+ country_name_locale = GnomeDesktop.get_country_from_code(country_code)
+ country_name_native = GnomeDesktop.get_country_from_code(
+ country_code, locale_code)
+ try:
+ if (language_name_native == language_name_locale and
+ country_name_native == country_name_locale):
+ return "{country} - {language}".format(
+ language=language_name_native.capitalize(),
+ country=country_name_native)
+ else:
+ return "{country} - {language} " \
+ "({local_country} - {local_language})".format(
+ language=language_name_native.capitalize(),
+ country=country_name_native,
+ local_language=language_name_locale.capitalize(),
+ local_country=country_name_locale)
+ except AttributeError:
+ return locale_code
+
+ @staticmethod
+ def _make_locales_per_country_dict(language_codes: [str]) -> {str: [str]}:
+ """assemble dictionary of country codes to corresponding locales list
+
+ example {FR: [fr_FR, en_FR], ...}"""
+ res = {}
+ for language_code in language_codes:
+ country_code = country_from_locale(language_code)
+ if country_code not in res:
+ res[country_code] = []
+ if language_code not in res[country_code]:
+ res[country_code].append(language_code)
+ return res
+
+ def on_language_changed(self, language_code: str):
+ """Set the formats according to the new language"""
+ # Don't overwrite user chosen values
+ if self.value_changed_by_user:
+ return
+
+ logging.debug("setting formats to %s", language_code)
+ self.set_value(language_code)
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/keyboard.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/keyboard.py
new file mode 100644
index 0000000..7be9232
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/keyboard.py
@@ -0,0 +1,214 @@
+import logging
+import gi
+
+from tailsgreeter.settings.localization import LocalizationSetting, ln_iso639_tri, \
+ ln_iso639_2_T_to_B, language_from_locale, country_from_locale
+
+gi.require_version('Gio', '2.0')
+gi.require_version('GLib', '2.0')
+gi.require_version('GnomeDesktop', '3.0')
+gi.require_version('GObject', '2.0')
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gio, GLib, GnomeDesktop, GObject, Gtk
+
+
+class KeyboardSetting(LocalizationSetting):
+
+ def __init__(self):
+ super().__init__()
+ self.xkbinfo = GnomeDesktop.XkbInfo()
+ self.value = 'us'
+
+ def get_tree(self, layout_codes=None) -> Gtk.TreeStore:
+ if not layout_codes:
+ layout_codes = self.get_all()
+
+ treestore = Gtk.TreeStore(GObject.TYPE_STRING, # id
+ GObject.TYPE_STRING) # name
+ layouts = self._layouts_split_names(layout_codes)
+ for group_name in sorted(layouts.keys()):
+ layout_codes = sorted(layouts[group_name],
+ key=lambda x: self._layout_name(x).lower())
+ treeiter_group = treestore.append(parent=None)
+ # we fill the title with the 1st layout of the group
+ treestore.set(treeiter_group, 0, layout_codes[0])
+ treestore.set(treeiter_group, 1, group_name)
+ if len(layout_codes) > 1:
+ for layout_code in layout_codes:
+ treeiter_layout = treestore.append(parent=treeiter_group)
+ treestore.set(treeiter_layout, 0, layout_code)
+ treestore.set(treeiter_layout, 1, self._layout_name(layout_code))
+ return treestore
+
+ def get_name(self) -> str:
+ return self._layout_name(self.get_value())
+
+ def get_all(self) -> [str]:
+ """Return a list of all keyboard layout codes
+
+ """
+ return self.xkbinfo.get_all_layouts()
+
+ def set_value(self, layout, chosen_by_user=False):
+ super().set_value(layout)
+ self.value_changed_by_user = chosen_by_user
+ self._apply_layout_to_current_screen()
+
+ def _layout_name(self, layout_code) -> str:
+ layout_exists, display_name, short_name, xkb_layout, xkb_variant = \
+ self.xkbinfo.get_layout_info(layout_code)
+ if not layout_exists:
+ logging.warning("Layout code '%s' does not exist", layout_code)
+ return display_name
+
+ def _layouts_split_names(self, layout_codes) -> [str]:
+ layouts_names = {}
+ for layout_code in layout_codes:
+ layout_name = self._layout_name(layout_code)
+ country_name, s, v = layout_name.partition(' (')
+ if country_name not in layouts_names:
+ layouts_names[country_name] = {layout_code}
+ else:
+ layouts_names[country_name].add(layout_code)
+ return layouts_names
+
+ def _layouts_for_language(self, lang_code) -> [str]:
+ """Return the list of available layouts for given language
+ """
+ try:
+ t_code = ln_iso639_tri(lang_code)
+ except KeyError:
+ t_code = lang_code
+ if t_code == 'nno' or t_code == 'nob':
+ t_code = 'nor'
+
+ layouts = self.xkbinfo.get_layouts_for_language(t_code)
+
+ if t_code == 'hrv':
+ layouts.append('hr')
+
+ if len(layouts) == 0:
+ b_code = ln_iso639_2_T_to_B(t_code)
+ logging.debug(
+ "got no layout for ISO-639-2/T code %s, "
+ "trying with ISO-639-2/B code %s",
+ t_code, b_code)
+
+ layouts = self.xkbinfo.get_layouts_for_language(b_code)
+
+ logging.debug('got %d layouts for %s', len(layouts), lang_code)
+ return layouts
+
+ def _layouts_for_country(self, country) -> [str]:
+ """Return the list of available layouts for given country
+ """
+ # XXX: it would be logical to use:
+ # self.__xklinfo.get_layouts_for_language(country)
+ # but it doesn't actually return the list of all layouts matching a
+ # country.
+ def country_filter(layout):
+ cc = country.lower()
+ return (layout == cc) or ('+' in layout) and (layout.split('+')[0] == cc)
+
+ layouts = list(filter(country_filter, self.get_all()))
+
+ logging.debug('got %d layouts for %s', len(layouts), country)
+ return layouts
+
+ @staticmethod
+ def _split_variant(layout_code) -> (str, str):
+ if '+' in layout_code:
+ return layout_code.split('+')
+ else:
+ return layout_code, None
+
+ def _filter_layouts(self, layouts, country, language):
+ """Try to select the best layout in a layout list
+ """
+ if len(layouts) > 1:
+ def variant_filter(layout):
+ layout_name, layout_variant = self._split_variant(layout)
+ return layout_variant is None
+ filtered_layouts = list(filter(variant_filter, layouts))
+ logging.debug("Filter by variant: %s", filtered_layouts)
+ if len(filtered_layouts) > 0:
+ layouts = filtered_layouts
+ if len(layouts) > 1:
+ def country_filter(layout):
+ layout_name, layout_variant = self._split_variant(layout)
+ return layout_variant == country.lower()
+ filtered_layouts = list(filter(country_filter, layouts))
+ logging.debug("Filter by country %s: %s", country,
+ filtered_layouts)
+ if len(filtered_layouts) > 0:
+ layouts = filtered_layouts
+ if len(layouts) > 1:
+ def language_filter(layout):
+ layout_name, layout_variant = self._split_variant(layout)
+ return layout_variant == language
+ filtered_layouts = list(filter(language_filter, layouts))
+ logging.debug("Filter by language %s: %s", language,
+ filtered_layouts)
+ if len(filtered_layouts) > 0:
+ layouts = filtered_layouts
+ return layouts
+
+ def on_language_changed(self, locale: str):
+ """Set the keyboard layout according to the new language"""
+
+ # Don't overwrite a user chosen value
+ if self.value_changed_by_user:
+ return
+
+ language = language_from_locale(locale)
+ country = country_from_locale(locale)
+
+ # First, build a list of layouts to consider for the language
+ language_layouts = self._layouts_for_language(language)
+ logging.debug("Language %s layouts: %s", language, language_layouts)
+ country_layouts = self._layouts_for_country(country)
+ logging.debug("Country %s layouts: %s", country, country_layouts)
+ layouts = set(language_layouts).intersection(country_layouts)
+ logging.debug("Intersection of language %s and country %s: %s",
+ language, country, layouts)
+
+ if not layouts:
+ layouts = set(l for l in language_layouts if self._split_variant(l)[0] == country.lower)
+ logging.debug("Empty intersection of language and country, filter "
+ "by country %s only: %s", country, layouts)
+ if not layouts:
+ layouts = set(l for l in language_layouts if self._split_variant(l)[0] == language)
+ logging.debug("List still empty, filter by language %s only: %s",
+ language, layouts)
+ if not layouts:
+ layouts = language_layouts
+ logging.debug("List still empty, use all language %s layouts: %s",
+ language, layouts)
+
+ # Then, filter the list
+ layouts = self._filter_layouts(layouts, country, language)
+ if len(layouts) != 1:
+ # Can't find a single result, build a new list for the country
+ layouts = country_layouts
+ logging.debug("Still not 1 layouts. Try again using all country "
+ "%s layouts: %s", country, layouts)
+ layouts = self._filter_layouts(layouts, country, language)
+ if len(layouts) == 1:
+ default_layout = layouts.pop()
+ logging.debug("Selecting single matching layout %s",
+ default_layout)
+ elif len(layouts) > 1:
+ default_layout = layouts.pop()
+ logging.debug("No good layout, arbitrary using layout %s",
+ default_layout)
+ else:
+ default_layout = 'us'
+ logging.debug("Using us as fallback default layout")
+ self.set_value(default_layout)
+
+ def _apply_layout_to_current_screen(self):
+ layout = self.get_value()
+ logging.debug("layout=%s", layout)
+
+ settings = Gio.Settings('org.gnome.desktop.input-sources')
+ settings.set_value('sources', GLib.Variant('a(ss)', [('xkb', layout)]))
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/language.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/language.py
new file mode 100644
index 0000000..44c3110
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/language.py
@@ -0,0 +1,222 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2012-2019 Tails developers <tails@boum.org>
+# Copyright 2011 Max <govnototalitarizm@gmail.com>
+# Copyright 2011 Martin Owens
+#
+# This program 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.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>
+
+from collections import OrderedDict
+import gi
+import logging
+import locale
+from typing import Callable
+
+from tailsgreeter.settings.localization import LocalizationSetting, \
+ language_from_locale, country_from_locale
+
+gi.require_version('GLib', '2.0')
+gi.require_version('GObject', '2.0')
+gi.require_version('GnomeDesktop', '3.0')
+gi.require_version('Gtk', '3.0')
+from gi.repository import GLib, GObject, GnomeDesktop, Gtk
+
+
+class LanguageSetting(LocalizationSetting):
+
+ def __init__(self, locales: [str], language_changed_cb: Callable):
+ super().__init__()
+ self.value = 'en_US'
+ self.locales = locales
+ self.language_changed_cb = language_changed_cb
+ self._user_account = None
+
+ self.lang_codes = self._languages_from_locales(locales)
+ self.locales_per_language = self._make_language_to_locale_dict(locales)
+ self.language_names_per_language = self._make_language_to_language_name_dict(self.lang_codes)
+
+ def get_tree(self) -> Gtk.TreeStore:
+ treestore = Gtk.TreeStore(GObject.TYPE_STRING, # id
+ GObject.TYPE_STRING) # name
+
+ for lang_code, language_name in self.language_names_per_language.items():
+ print("%s: %s" % (lang_code, language_name))
+ language_name = self._language_name(lang_code)
+ if not language_name:
+ # Don't display languages without a name
+ continue
+ treeiter_language = treestore.append(parent=None)
+ treestore.set(treeiter_language, 0, self.get_default_locale(lang_code))
+ treestore.set(treeiter_language, 1, language_name)
+ locales = sorted(self.locales_per_language[lang_code],
+ key=lambda x: self._locale_name(x).lower())
+ if len(locales) > 1:
+ for locale_code in locales:
+ treeiter_locale = treestore.append(parent=treeiter_language)
+ treestore.set(treeiter_locale, 0, locale_code)
+ treestore.set(treeiter_locale, 1, self._locale_name(locale_code))
+ return treestore
+
+ def get_name(self) -> str:
+ return self._locale_name(self.get_value())
+
+ def get_default_locale(self, lang_code: str) -> str:
+ """Try to find a default locale for the given language
+
+ Returns the 1st locale among:
+ - the locale whose country name matches language name
+ - the 1st locale for the language
+ - en_US
+ """
+ locales = self.locales_per_language[lang_code]
+ if not locales:
+ return 'en_US'
+
+ for locale_code in locales:
+ if (country_from_locale(locale_code).lower() ==
+ self._language_from_locale(locale_code)):
+ return locale_code
+
+ return locales[0]
+
+ def set_value(self, locale_code: str, chosen_by_user=False):
+ super().set_value(locale_code, chosen_by_user)
+ self._apply_language(locale_code)
+ self.language_changed_cb(locale_code)
+
+ def _language_name(self, lang_code: str) -> str:
+ default_locale = 'C'
+
+ if lang_code in ("zhs", "zht"):
+ custom_lang_code = lang_code
+ lang_code = "zh"
+ local_locale = "zh_CN" if custom_lang_code == "zhs" else "zh_TW"
+ else:
+ custom_lang_code = None
+ local_locale = self.get_default_locale(lang_code)
+
+ try:
+ native_name = GnomeDesktop.get_language_from_code(
+ lang_code, local_locale).capitalize()
+ except AttributeError:
+ return ""
+ localized_name = GnomeDesktop.get_language_from_code(
+ lang_code, default_locale).capitalize()
+
+ if custom_lang_code:
+ if custom_lang_code == "zhs":
+ localized_name = "Chinese, simplified"
+ else:
+ localized_name = "Chinese, traditional"
+
+ if native_name == localized_name:
+ return native_name
+ else:
+ return "{native} ({localized})".format(
+ native=native_name, localized=localized_name)
+
+ def _locale_name(self, locale_code: str) -> str:
+ lang_code = self._language_from_locale(locale_code)
+
+ if lang_code in ("zhs", "zht"):
+ custom_lang_code = lang_code
+ lang_code = "zh"
+ else:
+ custom_lang_code = None
+
+ country_code = country_from_locale(locale_code)
+ language_name_locale = GnomeDesktop.get_language_from_code(lang_code)
+ language_name_native = GnomeDesktop.get_language_from_code(
+ lang_code, locale_code)
+ country_name_locale = GnomeDesktop.get_country_from_code(country_code)
+ country_name_native = GnomeDesktop.get_country_from_code(
+ country_code, locale_code)
+
+ try:
+ if (language_name_native == language_name_locale and
+ country_name_native == country_name_locale):
+ return "{language} - {country}".format(
+ language=language_name_native.capitalize(),
+ country=country_name_native)
+
+ if custom_lang_code:
+ if custom_lang_code == "zhs":
+ country_name_locale = "simplified, " + country_name_locale
+ else:
+ country_name_locale = "traditional, " + country_name_locale
+
+ return "{language} - {country} " \
+ "({local_language} - {local_country})".format(
+ language=language_name_native.capitalize(),
+ country=country_name_native,
+ local_language=language_name_locale.capitalize(),
+ local_country=country_name_locale)
+ except AttributeError:
+ return locale_code
+
+ def _apply_language(self, language_code: str):
+ normalized_code = locale.normalize(language_code + '.' + locale.getpreferredencoding())
+ logging.debug("Setting session language to %s", normalized_code)
+ if self._user_account:
+ # For some reason, this produces the following warning, but
+ # the language is actually applied.
+ # AccountsService-WARNING **: 19:29:39.181: SetLanguage for language de_DE.UTF-8 failed:
+ # GDBus.Error:org.freedesktop.Accounts.Error.PermissionDenied: Not authorized
+ GLib.idle_add(lambda: self._user_account.set_language(normalized_code))
+ else:
+ logging.warning("AccountsManager not ready")
+
+ def _make_language_to_locale_dict(self, locale_codes: [str]) -> {str: str}:
+ """assemble dictionary of language codes to corresponding locales list
+
+ example {en: [en_US, en_GB], ...}"""
+ languages_dict = {}
+ for locale_code in locale_codes:
+ lang_code = self._language_from_locale(locale_code)
+ if lang_code not in languages_dict:
+ languages_dict[lang_code] = []
+ if locale_code not in languages_dict[lang_code]:
+ languages_dict[lang_code].append(locale_code)
+ return languages_dict
+
+ def _make_language_to_language_name_dict(self, lang_codes: [str]) -> {str: str}:
+ """assemble dictionary of language code to corresponding language name,
+ sorted by the language name.
+
+ example: {"en": "English", "it": "Italiano (Italian)", ...}"""
+ dict_ = {lang_code: self._language_name(lang_code) for lang_code in lang_codes}
+ # Sort the dictionary
+ sorted_keys = sorted(dict_.keys(), key=lambda x: dict_[x].lower())
+ return OrderedDict([(key, dict_[key]) for key in sorted_keys])
+
+ def _language_from_locale(self, locale_code: str) -> str:
+ lang_code = language_from_locale(locale_code)
+ if lang_code != "zh":
+ return lang_code
+
+ # We treat Chinese differently to have simplified and traditional
+ # Chinese in separate groups
+ if locale_code in ("zh_CN", "zh_SG"):
+ # Our own "language code" for simplified Chinese
+ return "zhs"
+ if locale_code in ("zh_HK", "zh_TW"):
+ # Our own "language code" for traditional Chinese
+ return "zht"
+ return lang_code
+
+ def _languages_from_locales(self, locale_codes: [str]) -> [str]:
+ """Obtain a language code list from a locale code list
+
+ example: [fr_FR, en_GB] -> [fr, en]"""
+ return list({self._language_from_locale(l) for l in locale_codes})
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization.py
new file mode 100644
index 0000000..8b0c6a3
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2012-2019 Tails developers <tails@boum.org>
+# Copyright 2011 Max <govnototalitarizm@gmail.com>
+# Copyright 2011 Martin Owens
+#
+# This program 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.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>
+
+import gi
+import pycountry
+from typing import TYPE_CHECKING
+
+gi.require_version('GObject', '2.0')
+from gi.repository import GObject
+
+if TYPE_CHECKING:
+ from gi.repository import Gtk
+
+
+class LocalizationSetting(GObject.Object, object):
+
+ def __init__(self):
+ GObject.Object.__init__(self)
+ self.value = ""
+ self.value_changed_by_user = False
+
+ def get_value(self) -> str:
+ return self.value
+
+ def set_value(self, value, chosen_by_user=False):
+ self.value = value
+ self.value_changed_by_user = chosen_by_user
+
+ def get_name(self) -> str:
+ raise NotImplementedError
+
+ def get_tree(self) -> "Gtk.Treestore":
+ raise NotImplementedError
+
+
+def ln_iso639_tri(ln_CC):
+ """get iso639 3-letter code from a language code
+
+ example: en -> eng"""
+ return pycountry.languages.get(
+ alpha2=language_from_locale(ln_CC)).terminology
+
+
+def ln_iso639_2_T_to_B(lng):
+ """Convert a ISO-639-2/T code (e.g. deu for German) to a 639-2/B one
+ (e.g. ger for German)"""
+ return pycountry.languages.get(terminology=lng).bibliographic
+
+
+def language_from_locale(locale):
+ """Obtain the language code from a locale code
+
+ example: fr_FR -> fr"""
+ return locale.split('_')[0]
+
+
+def country_from_locale(locale):
+ """Obtain the country code from a locale code
+
+ example: fr_FR -> FR"""
+ return locale.split('_')[1]
+
+
+def countries_from_locales(locales) -> [str]:
+ """Obtain a country code list from a locale code list
+
+ example: [fr_FR, en_GB] -> [FR, GB]"""
+ return list({country_from_locale(l) for l in locales})
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization_settings.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization_settings.py
new file mode 100644
index 0000000..0c25ba4
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/localization_settings.py
@@ -0,0 +1,70 @@
+import gi
+import logging
+import os
+from typing import Callable
+
+import tailsgreeter.config
+from tailsgreeter.settings.formats import FormatsSetting
+from tailsgreeter.settings.keyboard import KeyboardSetting
+from tailsgreeter.settings.language import LanguageSetting
+
+gi.require_version('AccountsService', '1.0')
+from gi.repository import AccountsService
+
+
+class LocalisationSettings(object):
+ """Controller for localisation settings
+
+ """
+ def __init__(self, usermanager_loaded_cb: Callable, locale_selected_cb: Callable):
+ self._usermanager_loaded_cb = usermanager_loaded_cb
+
+ self._user_account = None
+ self._actusermanager_loadedid = None
+
+ locales = self._get_locales()
+
+ self._actusermanager = AccountsService.UserManager.get_default()
+ self._actusermanager_loadedid = self._actusermanager.connect(
+ "notify::is-loaded", self.__on_usermanager_loaded)
+
+ self.language = LanguageSetting(locales, locale_selected_cb)
+ self.keyboard = KeyboardSetting()
+ self.formats = FormatsSetting(locales)
+
+ def __del__(self):
+ if self._actusermanager_loadedid:
+ self._actusermanager.disconnect(self._actusermanager_loadedid)
+
+ @staticmethod
+ def _get_locales() -> [str]:
+ with open(tailsgreeter.config.supported_locales_path, 'r') as f:
+ return [line.rstrip('\n') for line in f.readlines()]
+
+ def __on_usermanager_loaded(self, manager, pspec, data=None):
+ logging.debug("Received AccountsManager signal is-loaded")
+ user_account = manager.get_user(tailsgreeter.config.LUSER)
+ if not user_account.is_loaded():
+ raise RuntimeError("User manager for %s not loaded"
+ % tailsgreeter.config.LUSER)
+ self.language._user_account = user_account
+
+ if self._usermanager_loaded_cb:
+ self._usermanager_loaded_cb()
+
+ def apply_to_upcoming_session(self):
+ with open(tailsgreeter.config.locale_output_path, 'w') as f:
+ os.chmod(tailsgreeter.config.locale_output_path, 0o600)
+
+ f.write('TAILS_LOCALE_NAME=%s\n' % self.language.get_value())
+ f.write('TAILS_FORMATS=%s\n' % self.formats.get_value())
+
+ try:
+ layout, variant = self.keyboard.get_value().split('+')
+ except ValueError:
+ layout = self.keyboard.get_value()
+ variant = ''
+ # XXX: use default value from /etc/default/keyboard
+ f.write('TAILS_XKBMODEL=%s\n' % 'pc105')
+ f.write('TAILS_XKBLAYOUT=%s\n' % layout)
+ f.write('TAILS_XKBVARIANT=%s\n' % variant)
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/macspoof.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/macspoof.py
new file mode 100644
index 0000000..4132e39
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/macspoof.py
@@ -0,0 +1,19 @@
+import os
+import logging
+import pipes
+
+import tailsgreeter.config
+
+
+class MacSpoofSetting(object):
+ """Setting controlling whether the MAC address is spoofed or not"""
+
+ def __init__(self):
+ self.value = True
+
+ def apply_to_upcoming_session(self):
+ setting_file = tailsgreeter.config.macspoof_setting
+ with open(setting_file, 'w') as f:
+ os.chmod(setting_file, 0o600)
+ f.write("TAILS_MACSPOOF_ENABLED=%s\n" % pipes.quote(str(self.value)).lower())
+ logging.debug('macspoof setting written to %s', setting_file)
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/network.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/network.py
new file mode 100644
index 0000000..ba257d3
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/network.py
@@ -0,0 +1,23 @@
+import os
+import logging
+import pipes
+
+import tailsgreeter.config
+
+
+class NetworkSetting(object):
+ """Setting controlling how Tails connects to Tor"""
+
+ NETCONF_DIRECT = "direct"
+ NETCONF_OBSTACLE = "obstacle"
+ NETCONF_DISABLED = "disabled"
+
+ def __init__(self):
+ self.value = self.NETCONF_DIRECT
+
+ def apply_to_upcoming_session(self):
+ setting_file = tailsgreeter.config.network_setting
+ with open(setting_file, 'w') as f:
+ os.chmod(setting_file, 0o600)
+ f.write("TAILS_NETCONF=%s\n" % pipes.quote(self.value))
+ logging.debug('network setting written to %s', setting_file)
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/persistence.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/persistence.py
index cabefd6..e9bf9a2 100644
--- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/persistence.py
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/settings/persistence.py
@@ -77,7 +77,8 @@ class PersistenceSettings(object):
logging.exception(e)
return False
- def list_containers(self):
+ @staticmethod
+ def list_containers():
"""Returns a list of persistence containers we might want to unlock."""
args = [
"/usr/bin/sudo", "-n", "/usr/local/sbin/live-persist",
@@ -143,7 +144,8 @@ class PersistenceSettings(object):
"{stdout}\n{stderr}")
)
- def setup_persistence(self, cleartext_device, readonly):
+ @staticmethod
+ def setup_persistence(cleartext_device, readonly):
args = ["/usr/bin/sudo", "-n", "/usr/local/sbin/live-persist"]
if readonly:
args.append('--read-only')
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/translatable_window.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/translatable_window.py
new file mode 100644
index 0000000..a9577c3
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/translatable_window.py
@@ -0,0 +1,155 @@
+#!/usr/bin/python3
+#
+# Copyright 2012-2019 Tails developers <tails@boum.org>
+# Copyright 2011 Max <govnototalitarizm@gmail.com>
+# Copyright 2011 Martin Owens
+#
+# This program 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.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>
+#
+
+import gettext
+import logging
+
+from gi.repository import Gtk
+
+import tailsgreeter.config
+from tailsgreeter import TRANSLATION_DOMAIN
+
+
+class TranslatableWindow(object):
+ """Interface providing functions to translate a window on the fly
+ """
+ retain_focus = True
+ registered_windows = []
+
+ def __init__(self, window):
+ self.window_ = window
+ self.translation = gettext.translation(
+ TRANSLATION_DOMAIN,
+ tailsgreeter.config.system_locale_dir,
+ fallback=True
+ )
+
+ self.containers = []
+ self.labels = {}
+ self.placeholder_texts = {}
+ self.titles = {}
+ self.tooltips = {}
+
+ TranslatableWindow.registered_windows.append(window)
+
+ @staticmethod
+ def get_locale_direction(lang):
+ """Return Gtk.TextDirection for lang
+
+ This method in basically the same as Gtk.get_locale_direction
+ (gtk_get_locale_direction in gtk/gtkmain.c), but it accepts a lang
+ parameter rather than using current locale.
+ """
+ gtk_translation = gettext.translation("gtk30",
+ languages=[str(lang)],
+ fallback=True)
+ logging.debug("%s has GTK translation: %s", lang, gtk_translation)
+ # Translators: please do not translate this string (it is read from
+ # Gtk translation)
+ default_dir = gtk_translation.gettext("default:LTR")
+ logging.debug("translation for direction is %s", default_dir)
+ if default_dir == "default:RTL":
+ logging.debug("%s is RTL", lang)
+ return Gtk.TextDirection.RTL
+ else:
+ return Gtk.TextDirection.LTR
+
+ def store_translations(self, widget):
+ """Store the elements that should be localised inside widget
+
+ Go through all children of widget and store the translations
+ of labels, tooltips and titles and the containers whose text direction
+ should be updated when switching between LTR and RTL.
+
+ This method should be called once the widgets are created"""
+ if not isinstance(widget, Gtk.Widget):
+ logging.debug("%s is not a Gtk.Widget", widget)
+ return None
+ if isinstance(widget, Gtk.Label) or isinstance(widget, Gtk.Button):
+ if widget not in self.labels:
+ logging.debug("Storing translation for label/button '%s'", widget.get_label())
+ self.labels[widget] = widget.get_label()
+ # Wrap set_label to get notified about string changes
+ widget.original_set_label = widget.set_label
+
+ def wrapped_set_label(text):
+ self.labels[widget] = text
+ widget.original_set_label(self.gettext(text))
+ widget.set_label = wrapped_set_label
+ elif isinstance(widget, Gtk.Entry):
+ if widget not in self.placeholder_texts:
+ logging.debug("Storing translation for entry '%s'", widget.get_placeholder_text())
+ self.placeholder_texts[widget] = widget.get_placeholder_text()
+ elif isinstance(widget, Gtk.Container):
+ logging.debug("Handling container '%s'", widget.get_name())
+ self.containers.append(widget)
+ if ((isinstance(widget, Gtk.HeaderBar) or
+ isinstance(widget, Gtk.Window)) and
+ widget not in self.titles and
+ widget.get_title()):
+ self.titles[widget] = widget.get_title()
+ for child in widget.get_children():
+ self.store_translations(child)
+ else:
+ logging.debug("W: unhandled widget: %s", widget)
+ if widget.get_has_tooltip():
+ if widget not in self.tooltips:
+ self.tooltips[widget] = widget.get_tooltip_text()
+
+ def gettext(self, text):
+ """Return text, translated if possible"""
+ if self.translation and text:
+ text = self.translation.gettext(text)
+ return text
+
+ def translate_to(self, lang):
+ """Translate registered widgets on the fly
+
+ Loop through widgets registered with store_translations and translate
+ them on the fly"""
+ logging.debug("translating %s to %s", self, lang)
+ try:
+ self.translation = gettext.translation(
+ TRANSLATION_DOMAIN,
+ tailsgreeter.config.system_locale_dir, [str(lang)])
+ except IOError:
+ self.translation = None
+
+ text_direction = self.get_locale_direction(lang)
+ for container in self.containers:
+ container.set_default_direction(text_direction)
+ for widget, label in self.labels.items():
+ if label:
+ widget.original_set_label(self.gettext(label))
+ for widget in self.placeholder_texts.keys():
+ widget.set_placeholder_text(self.gettext(self.placeholder_texts[widget]))
+ for widget in self.titles.keys():
+ widget.set_title(self.gettext(self.titles[widget]))
+ for widget in self.tooltips.keys():
+ widget.set_tooltip_markup(self.gettext(self.tooltips[widget]))
+ if (self.window_.get_sensitive() and
+ self.window_.get_visible() and
+ self.retain_focus):
+ self.window_.present()
+
+ @staticmethod
+ def translate_all(lang):
+ for widget in TranslatableWindow.registered_windows:
+ widget.translate_to(lang)
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/__init__.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/__init__.py
new file mode 100644
index 0000000..33e4895
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/__init__.py
@@ -0,0 +1,3 @@
+# Mark translatable strings, but don't actually translate them, as we
+# delegate this to TranslatableWindow that handles on-the-fly language changes
+_ = lambda text: text
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/add_settings_dialog.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/add_settings_dialog.py
new file mode 100644
index 0000000..4fda49c
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/add_settings_dialog.py
@@ -0,0 +1,142 @@
+import logging
+from gettext import gettext
+import gi
+from typing import TYPE_CHECKING
+
+from tailsgreeter.translatable_window import TranslatableWindow
+
+gi.require_version('Gdk', '3.0')
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gdk, Gtk
+
+if TYPE_CHECKING:
+ from tailsgreeter.ui.settings_collection import GreeterSettingsCollection
+
+_ = gettext
+
+PREFERRED_WIDTH = 400
+
+
+class AddSettingsDialog(Gtk.Dialog, TranslatableWindow):
+ def __init__(self, builder, settings: "GreeterSettingsCollection"):
+ Gtk.Dialog.__init__(self, use_header_bar=True)
+ TranslatableWindow.__init__(self, self)
+ self.settings = settings
+ self.listbox = builder.get_object('listbox_add_setting')
+
+ for setting in self.settings.additional_settings:
+ logging.debug("Adding '%s' to additional settings listbox", setting.id)
+ self.listbox.add(setting.listboxrow)
+
+ self.set_transient_for(self)
+ self.set_title(_("Additional Settings"))
+ self.set_default_size(-1, PREFERRED_WIDTH)
+
+ sizegroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)
+
+ accelgroup = Gtk.AccelGroup()
+ self.add_accel_group(accelgroup)
+
+ self.button_cancel = self.add_button(_("Cancel"),
+ Gtk.ResponseType.CANCEL)
+ accelgroup.connect(Gdk.KEY_Escape, 0, 0,
+ self.cb_accelgroup_cancel_activated)
+ sizegroup.add_widget(self.button_cancel)
+
+ self.button_add = self.add_button(_("Add"), Gtk.ResponseType.YES)
+ Gtk.StyleContext.add_class(self.button_add.get_style_context(),
+ 'suggested-action')
+ sizegroup.add_widget(self.button_add)
+ accelgroup.connect(Gdk.KEY_Return, 0, 0,
+ self.cb_accelgroup_add_activated)
+ self.button_add.set_visible(False)
+
+ self.button_back = Gtk.Button.new_with_label(_("Back"))
+ self.button_back.set_visible(False)
+ self.button_back.connect('clicked', self.cb_button_back_clicked, None)
+ sizegroup.add_widget(self.button_back)
+ accelgroup.connect(Gdk.KEY_Back, 0, 0,
+ self.cb_accelgroup_back_activated)
+ # These key bindings are copied from Firefox, and are the same with
+ # right-to-left languages.
+ accelgroup.connect(Gdk.KEY_Left, Gdk.ModifierType.MOD1_MASK, 0,
+ self.cb_accelgroup_back_activated)
+ accelgroup.connect(Gdk.KEY_KP_Left, Gdk.ModifierType.MOD1_MASK, 0,
+ self.cb_accelgroup_back_activated)
+ self.get_header_bar().pack_end(self.button_back)
+
+ self.stack = Gtk.Stack()
+ self.stack.add_named(self.listbox, "setting-type")
+ self.listbox.set_valign(Gtk.Align.FILL)
+ self.listbox.set_vexpand(True)
+ self.stack.set_visible(True)
+ # XXX: is SLIDE_LEFT_RIGHT automatically inversed in RTL mode?
+ self.stack.set_transition_type(
+ Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
+ self.get_content_area().add(self.stack)
+
+ # Store translations
+ self.store_translations(self)
+ for setting in self.settings.additional_settings:
+ self.store_translations(setting.box)
+
+ def go_back(self):
+ self.stack.set_visible_child_name('setting-type')
+ self.button_back.set_visible(False)
+ self.button_add.set_visible(False)
+ self.stack.remove(self.stack.get_child_by_name('setting-details'))
+
+ def listbox_focus(self):
+ # Workaround autoselection of 1st item on focus
+ self.listbox.unselect_all()
+
+ def listbox_row_activated(self, row) -> bool:
+ if not row: # this happens when the row gets unselected
+ return False
+
+ # Show the selected setting
+ id_ = self.settings.id_from_row(row)
+ setting = self.settings.additional_settings[id_]
+ self.stack.add_named(setting.box, 'setting-details')
+ self.stack.set_visible_child_name('setting-details')
+ self.button_add.set_sensitive(True)
+ self.button_back.set_visible(True)
+ self.button_add.set_visible(True)
+ setting.on_opened_in_dialog()
+
+ def run(self, id_=None) -> int:
+ # Set the dialog attribute for the additional settings.
+ # This is required in order to allow the interactions with the
+ # setting's UI elements to change the dialog UI elements, for
+ # example the sensitivity of the "Add" button.
+ for setting in self.settings.additional_settings:
+ setting.dialog = self
+
+ if id_:
+ row = self.settings[id_].listboxrow
+ row.emit("activate")
+ else:
+ self.stack.set_visible_child_name('setting-type')
+ self.button_back.set_visible(False)
+ self.button_add.set_visible(False)
+ return super().run()
+
+ def cb_accelgroup_add_activated(self, accel_group, accelerable, keyval,
+ modifier, user_data=None):
+ if self.button_add.get_visible() and self.button_add.get_sensitive():
+ self.response(Gtk.ResponseType.YES)
+ return False
+
+ def cb_accelgroup_back_activated(self, accel_group, accelerable, keyval,
+ modifier, user_data=None):
+ self.go_back()
+ return False
+
+ def cb_accelgroup_cancel_activated(self, accel_group, accelerable, keyval,
+ modifier, user_data=None):
+ self.response(Gtk.ResponseType.CANCEL)
+ return True # disable the default callbacks that destroys the dialog
+
+ def cb_button_back_clicked(self, widget, user_data=None):
+ self.go_back()
+ return False
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/additional_settings.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/additional_settings.py
new file mode 100644
index 0000000..6a2883f
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/additional_settings.py
@@ -0,0 +1,276 @@
+import gi
+
+from tailsgreeter import TRANSLATION_DOMAIN
+import tailsgreeter.config
+import tailsgreeter.utils
+from tailsgreeter.ui import _
+from tailsgreeter.ui.setting import GreeterSetting
+from tailsgreeter.ui.popover import Popover
+from typing import TYPE_CHECKING
+
+gi.require_version('Gdk', '3.0')
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gdk, Gtk
+
+if TYPE_CHECKING:
+ from tailsgreeter.settings.admin import AdminSetting
+ from tailsgreeter.settings.macspoof import MacSpoofSetting
+ from tailsgreeter.settings.network import NetworkSetting
+
+ADDITIONAL_SETTINGS_UI_FILE = "additional_settings.ui"
+
+
+class AdditionalSetting(GreeterSetting):
+ def __init__(self):
+ super().__init__()
+ self.dialog = None
+
+ self.builder = Gtk.Builder()
+ self.builder.set_translation_domain(TRANSLATION_DOMAIN)
+ self.builder.add_from_file(tailsgreeter.config.data_path + ADDITIONAL_SETTINGS_UI_FILE)
+ self.box = self.builder.get_object("box_{}_popover".format(self.id))
+
+ def build_popover(self):
+ self.popover = Popover(self.listboxrow, self.box)
+
+ def close_window(self, response: Gtk.ResponseType):
+ if self.has_popover() and self.popover.is_open():
+ self.popover.close(response)
+ else:
+ self.dialog.response(response)
+
+ def apply(self):
+ pass
+
+ def on_opened_in_dialog(self):
+ pass
+
+
+class AdminSettingUI(AdditionalSetting):
+ @property
+ def id(self) -> str:
+ return "admin"
+
+ @property
+ def title(self) -> str:
+ return _("_Administration Password")
+
+ @property
+ def icon_name(self) -> str:
+ return "tails-admin"
+
+ @property
+ def value_for_display(self) -> str:
+ return get_on_off_string(self.password, default=None)
+
+ def update_check_icon(self):
+ password = self.password_entry.get_text()
+ password_verify = self.password_verify_entry.get_text()
+ if not password_verify:
+ icon = None
+ elif password_verify == password:
+ icon = 'emblem-ok-symbolic'
+ else:
+ icon = 'dialog-warning-symbolic'
+ self.password_verify_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon)
+
+ def on_opened_in_dialog(self):
+ self.update_check_icon()
+ self.dialog.button_add.set_sensitive(self.passwords_match())
+ self.password_entry.grab_focus()
+
+ def __init__(self, admin_setting: "AdminSetting"):
+ self._admin_setting = admin_setting
+ self.password = None
+ super().__init__()
+ self.accel_key = Gdk.KEY_a
+
+ self.password_entry = self.builder.get_object('entry_admin_password')
+ self.password_entry.connect('changed', self.cb_entry_admin_changed)
+ self.password_entry.connect('activate', self.cb_entry_admin_activate)
+ self.password_verify_entry = self.builder.get_object('entry_admin_verify')
+ self.password_verify_entry.connect('changed', self.cb_entry_admin_changed)
+ self.password_verify_entry.connect('activate', self.cb_entry_admin_activate)
+ self.box_admin_password = self.builder.get_object('box_admin_password')
+ self.box_admin_verify = self.builder.get_object('box_admin_verify')
+ self.button_admin_disable = self.builder.get_object('button_admin_disable')
+ self.button_admin_disable.connect('clicked', self.cb_button_admin_disable_clicked)
+
+ def build_popover(self):
+ super().build_popover()
+ self.popover.opened_cb = self.cb_popover_opened
+
+ def cb_popover_opened(self, popover, user_data=None):
+ self.password_verify_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, None)
+ password_already_set = bool(self.password)
+ self.box_admin_password.set_visible(not password_already_set)
+ self.box_admin_verify.set_visible(not password_already_set)
+ self.button_admin_disable.set_visible(password_already_set)
+
+ def passwords_match(self) -> bool:
+ password = self.password_entry.get_text()
+ # Don't accept an empty password
+ if not password:
+ return False
+ return password == self.password_verify_entry.get_text()
+
+ def apply(self):
+ # This writes the password to a file from which it will be set
+ # as the amnesia password when the greeter is closed.
+ self._admin_setting.password = self.password
+
+ def cb_entry_admin_changed(self, editable, user_data=None):
+ self.update_check_icon()
+ passwords_match = self.passwords_match()
+ self.dialog.button_add.set_sensitive(passwords_match)
+ if passwords_match:
+ self.password = self.password_entry.get_text()
+ return False
+
+ def cb_entry_admin_activate(self, widget, user_data=None):
+ if not self.passwords_match():
+ self.dialog.button_add.set_sensitive(False)
+ self.password_verify_entry.grab_focus()
+ return False
+
+ self.password = self.password_entry.get_text()
+ self.close_window(Gtk.ResponseType.YES)
+ return False
+
+ def cb_button_admin_disable_clicked(self, widget, user_data=None):
+ self.password = None
+ self.password_entry.set_text("")
+ self.password_verify_entry.set_text("")
+
+ if self.has_popover() and self.popover.is_open():
+ self.popover.close(Gtk.ResponseType.YES)
+
+
+class MACSpoofSettingUI(AdditionalSetting):
+ @property
+ def id(self) -> str:
+ return "macspoof"
+
+ @property
+ def title(self) -> str:
+ return _("_MAC Address Spoofing")
+
+ @property
+ def icon_name(self) -> str:
+ return "tails-macspoof"
+
+ @property
+ def value_for_display(self) -> str:
+ return get_on_off_string(self.spoofing_enabled, default=True)
+
+ def __init__(self, macspoof_setting: "MacSpoofSetting"):
+ self._macspoof_setting = macspoof_setting
+ self.spoofing_enabled = True
+ super().__init__()
+ self.accel_key = Gdk.KEY_m
+
+ self.image_macspoof_on = self.builder.get_object('image_macspoof_on')
+ self.image_macspoof_off = self.builder.get_object('image_macspoof_off')
+ self.listbox_macspoof_controls = self.builder.get_object('listbox_macspoof_controls')
+ self.listbox_macspoof_controls.connect('row-activated', self.cb_listbox_macspoof_row_activated)
+ self.listbox_macspoof_controls.connect('button-press-event', self.cb_listbox_macspoof_button_press)
+ self.listboxrow_macspoof_on = self.builder.get_object('listboxrow_macspoof_on')
+ self.listboxrow_macspoof_off = self.builder.get_object('listboxrow_macspoof_off')
+
+ def apply(self):
+ self._macspoof_setting.value = self.spoofing_enabled
+
+ def cb_listbox_macspoof_row_activated(self, listbox, row, user_data=None):
+ self.spoofing_enabled = row == self.listboxrow_macspoof_on
+ self.image_macspoof_on.set_visible(self.spoofing_enabled)
+ self.image_macspoof_off.set_visible(not self.spoofing_enabled)
+
+ if self.has_popover() and self.popover.is_open():
+ self.popover.close(Gtk.ResponseType.YES)
+ return False
+
+ def cb_listbox_macspoof_button_press(self, widget, event, user_data=None):
+ # On double-click: Close the window and apply chosen setting
+ if event.type == Gdk.EventType._2BUTTON_PRESS:
+ self.close_window(Gtk.ResponseType.YES)
+ return False
+
+
+class NetworkSettingUI(AdditionalSetting):
+ @property
+ def id(self) -> str:
+ return "network"
+
+ @property
+ def title(self) -> str:
+ return _("_Network Connection")
+
+ @property
+ def icon_name(self) -> str:
+ return "tails-network"
+
+ @property
+ def value_for_display(self) -> str:
+ if self.value == self._network_setting.NETCONF_DIRECT:
+ return _("Direct (default)")
+ if self.value == self._network_setting.NETCONF_OBSTACLE:
+ return _("Bridge & Proxy")
+ if self.value == self._network_setting.NETCONF_DISABLED:
+ return _("Offline")
+
+ def __init__(self, network_setting: "NetworkSetting"):
+ self._network_setting = network_setting
+ self.value = self._network_setting.NETCONF_DIRECT
+ super().__init__()
+ self.accel_key = Gdk.KEY_n
+ self.icon_network_clear_chosen = self.builder.get_object('image_network_clear')
+ self.icon_network_specific_chosen = self.builder.get_object('image_network_specific')
+ self.icon_network_off_chosen = self.builder.get_object('image_network_off')
+ self.listbox_network_controls = self.builder.get_object('listbox_network_controls')
+ self.listbox_network_controls.connect('button-press-event', self.cb_listbox_network_button_press)
+ self.listbox_network_controls.connect('row-activated', self.cb_listbox_network_row_activated)
+ self.listboxrow_network_clear = self.builder.get_object('listboxrow_network_clear')
+ self.listboxrow_network_specific = self.builder.get_object('listboxrow_network_specific')
+ self.listboxrow_network_off = self.builder.get_object('listboxrow_network_off')
+
+ def apply(self):
+ self._network_setting.value = self.value
+ is_bridge = self.value == self._network_setting.NETCONF_OBSTACLE
+ self.main_window.set_bridge_infobar_visibility(is_bridge)
+
+ def cb_listbox_network_button_press(self, widget, event, user_data=None):
+ # On double-click: Close the window and apply chosen setting
+ if event.type == Gdk.EventType._2BUTTON_PRESS:
+ self.close_window(Gtk.ResponseType.YES)
+ return False
+
+ def cb_listbox_network_row_activated(self, listbox, row, user_data=None):
+ self.icon_network_clear_chosen.set_visible(False)
+ self.icon_network_specific_chosen.set_visible(False)
+ self.icon_network_off_chosen.set_visible(False)
+
+ if row == self.listboxrow_network_clear:
+ self.value = self._network_setting.NETCONF_DIRECT
+ self.icon_network_clear_chosen.set_visible(True)
+ elif row == self.listboxrow_network_specific:
+ self.value = self._network_setting.NETCONF_OBSTACLE
+ self.icon_network_specific_chosen.set_visible(True)
+ elif row == self.listboxrow_network_off:
+ self.value = self._network_setting.NETCONF_DISABLED
+ self.icon_network_off_chosen.set_visible(True)
+
+ if self.has_popover() and self.popover.is_open():
+ self.popover.close(Gtk.ResponseType.YES)
+ return False
+
+
+def get_on_off_string(value, default=None) -> str:
+ """Return "On", "Off", "On (default)", or "Off (default)"""
+ if value and default:
+ return _("On (default)")
+ if value and not default:
+ return _("On")
+ if not value and default:
+ return _("Off")
+ if not value and not default:
+ return _("Off (default)")
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/help_window.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/help_window.py
new file mode 100644
index 0000000..51fb2f4
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/help_window.py
@@ -0,0 +1,72 @@
+import gi
+import webbrowser
+
+import tailsgreeter
+from tailsgreeter.translatable_window import TranslatableWindow
+from tailsgreeter.ui import _
+
+gi.require_version('Gtk', '3.0')
+gi.require_version('WebKit2', '4.0')
+from gi.repository import Gtk, WebKit2
+
+PREFERRED_WIDTH = 800
+
+
+class GreeterHelpWindow(Gtk.Window, TranslatableWindow):
+ """Displays a modal HTML help window"""
+
+ def __init__(self, uri):
+ Gtk.Window.__init__(self, title=_(tailsgreeter.APPLICATION_TITLE))
+ TranslatableWindow.__init__(self, self)
+
+ self._build_ui()
+ self.store_translations(self)
+
+ self.load_uri(uri)
+ # Replace the busy cursor set by the tails-greeter startup script with
+ # the default cursor.
+ self.get_window().set_cursor(None)
+
+ def _build_ui(self):
+ self.set_position(Gtk.WindowPosition.CENTER)
+
+ # Create HeaderBar
+ headerbar = Gtk.HeaderBar()
+ headerbar.set_show_close_button(True)
+ headerbar.show_all()
+
+ # Create webview with custom stylesheet
+ css = WebKit2.UserStyleSheet(
+ ".sidebar, .banner { display: none; }",
+ WebKit2.UserContentInjectedFrames.ALL_FRAMES,
+ WebKit2.UserStyleLevel.USER,
+ None,
+ None)
+ content_manager = WebKit2.UserContentManager()
+ content_manager.add_style_sheet(css)
+ self.webview = WebKit2.WebView.new_with_user_content_manager(
+ content_manager)
+ self.webview.connect("resource-load-started",
+ self.cb_load_started)
+ self.webview.show()
+
+ scrolledwindow = Gtk.ScrolledWindow()
+ scrolledwindow.add(self.webview)
+ scrolledwindow.show()
+
+ # Add children to ApplicationWindow
+ self.add(scrolledwindow)
+ self.set_titlebar(headerbar)
+
+ def load_uri(self, uri):
+ self.webview.load_uri(uri)
+ self.resize(
+ min(PREFERRED_WIDTH,
+ self.get_screen().get_width()),
+ self.get_screen().get_height())
+ self.present()
+
+ def cb_load_started(self, web_view, ressource, request):
+ if not request.get_uri().startswith("file://"):
+ webbrowser.open_new(request.get_uri())
+ request.set_uri(web_view.get_uri())
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/main_window.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/main_window.py
new file mode 100644
index 0000000..321116b
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/main_window.py
@@ -0,0 +1,422 @@
+# -*- coding: utf-8 -*-/
+#
+# Copyright 2015-2016 Tails developers <tails@boum.org>
+#
+# This program 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.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>
+
+import locale
+import logging
+from typing import TYPE_CHECKING
+import gi
+import os
+
+import tailsgreeter # NOQA: E402
+import tailsgreeter.config # NOQA: E402
+import tailsgreeter.utils # NOQA: E402
+from tailsgreeter.translatable_window import TranslatableWindow
+from tailsgreeter.ui.popover import Popover
+from tailsgreeter.ui import _
+from tailsgreeter.ui.add_settings_dialog import AddSettingsDialog
+from tailsgreeter.ui.additional_settings import AdditionalSetting
+from tailsgreeter.ui.help_window import GreeterHelpWindow
+from tailsgreeter.ui.region_settings import LocalizationSettingUI, LanguageSettingUI
+from tailsgreeter import TRANSLATION_DOMAIN
+from tailsgreeter.ui.persistent_storage import PersistentStorage
+
+
+gi.require_version('Gdk', '3.0')
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gdk, Gtk
+
+if TYPE_CHECKING:
+ from tailsgreeter.settings.persistence import PersistenceSettings
+ from tailsgreeter.ui.settings_collection import GreeterSettingsCollection
+
+
+MAIN_UI_FILE = 'main.ui'
+CSS_FILE = 'greeter.css'
+ICON_DIR = 'icons/'
+PREFERRED_WIDTH = 620
+PREFERRED_HEIGHT = 470
+
+locale.bindtextdomain(TRANSLATION_DOMAIN, tailsgreeter.config.system_locale_dir)
+
+
+class GreeterMainWindow(Gtk.Window, TranslatableWindow):
+ def __init__(self, greeter, persistence_setting: "PersistenceSettings", settings: "GreeterSettingsCollection"):
+ Gtk.Window.__init__(self, title=_(tailsgreeter.APPLICATION_TITLE))
+ TranslatableWindow.__init__(self, self)
+ self.greeter = greeter
+ self.persistence_setting = persistence_setting
+ self.settings = settings
+ self.current_language = "en"
+
+ # Set the main_window attribute for the settings. This is required
+ # in order to allow the settings to trigger changes in the main
+ # window, for example showing an info bar.
+ for setting in self.settings:
+ setting.main_window = self
+
+ self.connect('delete-event', self.cb_window_delete_event, None)
+ self.set_position(Gtk.WindowPosition.CENTER)
+
+ # Load custom CSS
+ css_provider = Gtk.CssProvider()
+ css_provider.load_from_path(tailsgreeter.config.data_path + CSS_FILE)
+ Gtk.StyleContext.add_provider_for_screen(
+ Gdk.Screen.get_default(),
+ css_provider,
+ Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
+
+ # Load UI interface definition
+ builder = Gtk.Builder()
+ builder.set_translation_domain(TRANSLATION_DOMAIN)
+ builder.add_from_file(tailsgreeter.config.data_path + MAIN_UI_FILE)
+ builder.connect_signals(self)
+
+ for widget in builder.get_objects():
+ # Store translations for the builder objects
+ self.store_translations(widget)
+ # Workaround Gtk bug #710888 - GtkInfoBar not shown after calling
+ # gtk_widget_show:
+ # https://bugzilla.gnome.org/show_bug.cgi?id=710888
+ if isinstance(widget, Gtk.InfoBar):
+ revealer = widget.get_template_child(Gtk.InfoBar, 'revealer')
+ revealer.set_transition_type(Gtk.RevealerTransitionType.NONE)
+
+ self.box_language = builder.get_object('box_language')
+ self.box_language_header = builder.get_object('box_language_header')
+ self.box_main = builder.get_object('box_main')
+ self.box_settings = builder.get_object('box_settings')
+ self.box_settings_header = builder.get_object('box_settings_header')
+ self.box_settings_values = builder.get_object('box_settings_values')
+ self.box_storage = builder.get_object('box_storage')
+ self.box_storage_unlock = builder.get_object('box_storage_unlock')
+ self.box_storage_unlocked = builder.get_object('box_storage_unlocked')
+ self.button_storage_configure = builder.get_object('button_storage_configure')
+ self.entry_storage_passphrase = builder.get_object('entry_storage_passphrase')
+ self.frame_language = builder.get_object('frame_language')
+ self.infobar_network = builder.get_object('infobar_network')
+ self.label_settings_default = builder.get_object('label_settings_default')
+ self.listbox_add_setting = builder.get_object('listbox_add_setting')
+ self.listbox_settings = builder.get_object('listbox_settings')
+ self.toolbutton_settings_add = builder.get_object('toolbutton_settings_add')
+ self.listbox_settings = builder.get_object("listbox_settings")
+ self.listbox_region = builder.get_object("listbox_region")
+
+ # Set preferred width
+ self.set_default_size(min(Gdk.Screen.get_default().get_width(),
+ PREFERRED_WIDTH),
+ min(Gdk.Screen.get_default().get_height(),
+ PREFERRED_HEIGHT))
+
+ # Add our icon dir to icon theme
+ icon_theme = Gtk.IconTheme.get_default()
+ icon_theme.prepend_search_path(
+ tailsgreeter.config.data_path + ICON_DIR)
+
+ # Add placeholder to settings ListBox
+ self.listbox_settings.set_placeholder(self.label_settings_default)
+
+ # Persistent storage
+ self.persistent_storage = PersistentStorage(self.persistence_setting, builder)
+
+ # Add children to ApplicationWindow
+ self.add(self.box_main)
+ self.set_titlebar(self._build_headerbar())
+
+ # Set keyboard focus chain
+ self._set_focus_chain()
+
+ # Add settings to region listbox
+ for setting in self.settings.region_settings:
+ logging.debug("Adding '%s' to region listbox", setting.id)
+ self.listbox_region.add(setting.listboxrow)
+
+ # Add settings dialog
+ self.dialog_add_setting = AddSettingsDialog(builder, self.settings)
+ self.dialog_add_setting.set_transient_for(self)
+
+ # Setup keyboard accelerators
+ self._build_accelerators()
+
+ self.store_translations(self)
+
+ # Utility methods
+
+ def _build_accelerators(self):
+ accelgroup = Gtk.AccelGroup()
+ self.add_accel_group(accelgroup)
+ for accel_key in [s.accel_key for s in self.settings if s.accel_key]:
+ accelgroup.connect(
+ accel_key,
+ Gdk.ModifierType.SHIFT_MASK | Gdk.ModifierType.CONTROL_MASK,
+ Gtk.AccelFlags.VISIBLE,
+ self.cb_accelgroup_setting_activated)
+
+ def _build_headerbar(self) -> Gtk.HeaderBar:
+ headerbar = Gtk.HeaderBar()
+ headerbar_sizegroup = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL)
+
+ self.button_shutdown = Gtk.Button.new_with_label(_("Shutdown"))
+ self.button_shutdown.connect('clicked', self.cb_button_shutdown_clicked)
+ headerbar_sizegroup.add_widget(self.button_shutdown)
+ headerbar.pack_start(self.button_shutdown)
+
+ self.button_start = Gtk.Button.new_with_mnemonic(_("_Start Tails"))
+ Gtk.StyleContext.add_class(self.button_start.get_style_context(),
+ 'suggested-action')
+ self.button_start.connect('clicked', self.cb_button_start_clicked)
+ headerbar_sizegroup.add_widget(self.button_start)
+ headerbar.pack_end(self.button_start)
+
+ headerbar.show_all()
+
+ return headerbar
+
+ def _set_focus_chain(self):
+ self.box_language.set_focus_chain([
+ self.frame_language,
+ self.box_language_header])
+ self.box_storage.set_focus_chain([
+ self.box_storage_unlock,
+ self.box_storage_unlocked,
+ self.button_storage_configure])
+ self.box_settings.set_focus_chain([
+ self.box_settings_values,
+ self.box_settings_header])
+
+ # Actions
+
+ def check_and_login(self):
+ if (self.persistence_setting.has_persistence() and
+ self.entry_storage_passphrase.get_text() and
+ not self.persistence_setting.is_unlocked):
+ logging.debug("Unlocking persistent storage before login")
+ self.persistent_storage.unlock(unlocked_cb=self.finish_login)
+ else:
+ self.finish_login()
+
+ def finish_login(self):
+ logging.info("Starting the session")
+ self.greeter.login()
+ return False
+
+ def add_setting(self, id_=None):
+ response = self.dialog_add_setting.run(id_)
+ if response == Gtk.ResponseType.YES:
+ row = self.listbox_add_setting.get_selected_row()
+ id_ = self.settings.id_from_row(row)
+ setting = self.settings.additional_settings[id_]
+
+ # The setting used to be applied by the dialog itself, but there
+ # we don't know the response type in all cases. For example, we
+ # previously didn't apply the admin password in all cases if the
+ # "Add" button was clicked to close the dialog (#13447).
+ setting.apply()
+ setting.update_value_label()
+
+ self.listbox_add_setting.remove(row)
+ self.listbox_settings.add(row)
+ self.dialog_add_setting.set_visible(False)
+ self.dialog_add_setting.stack.remove(setting.box)
+ setting.build_popover()
+
+ self.listbox_settings.unselect_all()
+ if True not in [c.get_visible() for c in
+ self.listbox_add_setting.get_children()]:
+ self.toolbutton_settings_add.set_sensitive(False)
+ self.dialog_add_setting.set_visible(False)
+ else:
+ old_details = self.dialog_add_setting.stack.get_child_by_name(
+ 'setting-details')
+ if old_details:
+ self.dialog_add_setting.stack.remove(old_details)
+ self.dialog_add_setting.set_visible(False)
+
+ def edit_setting(self, id_):
+ if self.settings[id_].has_popover():
+ self.settings[id_].listboxrow.emit("activate")
+ else:
+ self.add_setting(id_)
+
+ def show(self):
+ super().show()
+ self.button_start.grab_focus()
+ self.get_root_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.ARROW))
+
+ def set_bridge_infobar_visibility(self, value: bool):
+ self.infobar_network.set_visible(value)
+
+ # Callbacks
+
+ def cb_accelgroup_setting_activated(self, accel_group, accelerable,
+ keyval, modifier):
+ for setting in self.settings:
+ if setting.accel_key == keyval:
+ self.edit_setting(setting.id)
+ return False
+
+ def cb_linkbutton_help_activate(self, linkbutton, user_data=None):
+
+ def localize_page(page: str) -> str:
+ """Try to get a localized version of the page"""
+ if self.current_language == "en":
+ return page
+
+ localized_page = page.replace(".en.", ".%s." % self.current_language)
+
+ # Strip the fragment identifier
+ index = localized_page.find('#')
+ filename = localized_page[:index] if index > 0 else localized_page
+
+ if os.path.isfile("/usr/share/doc/tails/website/" + filename):
+ return localized_page
+ return page
+
+ linkbutton.set_sensitive(False)
+ # Display progress cursor and update the UI
+ self.get_window().set_cursor(Gdk.Cursor.new(Gdk.CursorType.WATCH))
+ while Gtk.events_pending():
+ Gtk.main_iteration()
+
+ page = linkbutton.get_uri()
+ page = localize_page(page)
+
+ # Note that we add the "file://" part here, not in the URI.
+ # We're forced to add this
+ # callback *in addition* to the standard one (Gtk.show_uri),
+ # which will do nothing for uri:s without a protocol
+ # part. This is critical since we otherwise would open the
+ # default browser (iceweasel) in T-G. If pygtk had a mechanism
+ # like gtk's g_signal_handler_find() this could be dealt with
+ # in a less messy way by just removing the default handler.
+ uri = "file:///usr/share/doc/tails/website/" + page
+ logging.debug("Opening help window for {}".format(uri))
+ helpwindow = GreeterHelpWindow(uri)
+ helpwindow.show()
+
+ def restore_linkbutton_status(widget, event, linkbutton):
+ linkbutton.set_sensitive(True)
+ return False
+
+ helpwindow.connect('delete-event', restore_linkbutton_status,
+ linkbutton)
+ # Restore default cursor
+ self.get_window().set_cursor(None)
+
+ def cb_button_shutdown_clicked(self, widget, user_data=None):
+ self.greeter.shutdown()
+ return False
+
+ def cb_button_start_clicked(self, widget, user_data=None):
+ self.check_and_login()
+ return False
+
+ def cb_button_storage_configure_clicked(self, user_data=None):
+ self.persistent_storage.configure()
+ return False
+
+ def cb_button_storage_lock_clicked(self, widget, user_data=None):
+ self.persistent_storage.lock()
+ return False
+
+ def cb_button_storage_unlock_clicked(self, widget, user_data=None):
+ self.persistent_storage.unlock()
+ return False
+
+ def cb_entry_storage_passphrase_activated(self, entry, user_data=None):
+ self.persistent_storage.unlock()
+ return False
+
+ def cb_entry_storage_passphrase_changed(self, editable, user_data=None):
+ self.persistent_storage.passphrase_changed(editable)
+ return False
+
+ def cb_infobar_close(self, infobar, user_data=None):
+ infobar.set_visible(False)
+ return False
+
+ def cb_infobar_response(self, infobar, response_id, user_data=None):
+ infobar.set_visible(False)
+ return False
+
+ def cb_listbox_add_setting_focus(self, widget, direction, user_data=None):
+ self.dialog_add_setting.listbox_focus()
+ return False
+
+ def cb_listbox_add_setting_row_activated(self, listbox, row, user_data=None):
+ self.dialog_add_setting.listbox_row_activated(row)
+ return False
+
+ def cb_listbox_region_row_activated(self, listbox, row, user_data=None):
+ setting = self.settings[self.settings.id_from_row(row)]
+ if not setting.popover.is_open():
+ setting.popover.open(self.on_region_setting_popover_closed, setting)
+ return False
+
+ def on_region_setting_popover_closed(self, popover: Popover, setting: LocalizationSettingUI):
+ # Unselect the listbox row
+ self.listbox_region.unselect_all()
+
+ if popover.response != Gtk.ResponseType.YES:
+ return
+
+ setting.apply()
+
+ # If the language is changed, the values of the other region settings
+ # are changed as well, so we have to update the value labels for all
+ # region settings in that case.
+ if isinstance(setting, LanguageSettingUI):
+ for s in self.settings.region_settings:
+ s.update_value_label()
+ else:
+ setting.update_value_label()
+
+ def cb_listbox_settings_row_activated(self, listbox, row, user_data=None):
+ setting = self.settings[self.settings.id_from_row(row)]
+ if not setting.popover.is_open():
+ setting.popover.open(self.on_additional_setting_popover_closed, setting)
+ return False
+
+ def on_additional_setting_popover_closed(self, popover: Popover, setting: AdditionalSetting):
+ logging.debug("'%s' popover closed. response: %s", setting.id, popover.response)
+ # Unselect the listbox row
+ self.listbox_settings.unselect_all()
+ if popover.response == Gtk.ResponseType.YES:
+ setting.apply()
+ setting.update_value_label()
+
+ def cb_toolbutton_settings_add_clicked(self, user_data=None):
+ self.add_setting()
+ return False
+
+ def cb_toolbutton_settings_mnemonic_activate(self, widget, group_cycling):
+ self.add_setting()
+ return False
+
+ def cb_window_delete_event(self, widget, event, user_data=None):
+ # Don't close the toplevel window on user request (e.g. pressing
+ # Alt+F4)
+ return True
+
+
+class GreeterBackgroundWindow(Gtk.ApplicationWindow):
+
+ def __init__(self, app):
+ super().__init__(app)
+ Gtk.Window.__init__(self, title=_(tailsgreeter.APPLICATION_TITLE),
+ application=app)
+ self.override_background_color(
+ Gtk.StateFlags.NORMAL, Gdk.RGBA(0, 0, 0, 1))
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/persistent_storage.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/persistent_storage.py
new file mode 100644
index 0000000..7daddef
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/persistent_storage.py
@@ -0,0 +1,128 @@
+import logging
+import gi
+import threading
+from typing import TYPE_CHECKING
+
+from tailsgreeter.ui import _
+
+gi.require_version('GLib', '2.0')
+gi.require_version('Gtk', '3.0')
+from gi.repository import GLib, Gtk
+
+if TYPE_CHECKING:
+ from tailsgreeter.settings.persistence import PersistenceSettings
+
+
+class PersistentStorage(object):
+ def __init__(self, persistence_setting: "PersistenceSettings", builder):
+ self.persistence_setting = persistence_setting
+
+ self.box_storage = builder.get_object('box_storage')
+ self.box_storage_unlock = builder.get_object('box_storage_unlock')
+ self.box_storage_unlocked = builder.get_object('box_storage_unlocked')
+ self.button_storage_configure = builder.get_object('button_storage_configure')
+ self.button_storage_lock = builder.get_object('button_storage_lock')
+ self.button_storage_unlock = builder.get_object('button_storage_unlock')
+ self.entry_storage_passphrase = builder.get_object('entry_storage_passphrase')
+ self.image_storage_state = builder.get_object('image_storage_state')
+ self.infobar_persistence = builder.get_object('infobar_persistence')
+ self.label_infobar_persistence = builder.get_object('label_infobar_persistence')
+ self.spinner_storage_unlock = builder.get_object('spinner_storage_unlock')
+
+ if self.persistence_setting.has_persistence():
+ self.button_storage_configure.set_visible(False)
+ self.box_storage_unlock.set_visible(True)
+ self.image_storage_state.set_visible(True)
+ self.entry_storage_passphrase.set_visible(True)
+ self.spinner_storage_unlock.set_visible(False)
+ else:
+ # XXX-future: We have a nice button to configure the persistence
+ # but nothing is implemented to do so currently. So let's
+ # hide the whole thing for now.
+ self.box_storage.set_visible(False)
+
+ def configure(self):
+ # XXX-future: this should launch the configuration of the persistence.
+ logging.warning("User would be able to set up an encrypted storage.")
+ raise NotImplementedError
+
+ def lock(self):
+ if self.persistence_setting.lock():
+ self.button_storage_lock.set_visible(False)
+ self.box_storage_unlock.set_visible(True)
+ self.image_storage_state.set_visible(True)
+ self.image_storage_state.set_from_icon_name(
+ 'tails-locked', Gtk.IconSize.BUTTON)
+ self.entry_storage_passphrase.set_visible(True)
+ self.entry_storage_passphrase.set_sensitive(True)
+ self.button_storage_unlock.set_visible(True)
+ self.button_storage_unlock.set_sensitive(True)
+ self.button_storage_unlock.set_label(_("Unlock"))
+ else:
+ self.label_infobar_persistence.set_label(
+ _("Failed to relock persistent storage."))
+ self.infobar_persistence.set_visible(True)
+
+ @staticmethod
+ def passphrase_changed(editable):
+ # Remove warning icon
+ editable.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, None)
+
+ def unlock(self, unlocked_cb=None, failed_cb=None):
+ if not unlocked_cb:
+ unlocked_cb = self.cb_unlocked
+ if not failed_cb:
+ failed_cb = self.cb_unlock_failed
+
+ self.entry_storage_passphrase.set_sensitive(False)
+ self.button_storage_unlock.set_sensitive(False)
+ self.button_storage_unlock.set_label(_("Unlocking…"))
+ self.image_storage_state.set_visible(False)
+ self.spinner_storage_unlock.set_visible(True)
+
+ passphrase = self.entry_storage_passphrase.get_text()
+
+ # Let's execute the unlocking in a thread
+ def do_unlock_storage(unlock_method, passphrase, unlocked_cb,
+ failed_cb):
+ if unlock_method(passphrase):
+ GLib.idle_add(unlocked_cb)
+ else:
+ GLib.idle_add(failed_cb)
+
+ unlocking_thread = threading.Thread(
+ target=do_unlock_storage,
+ args=(self.persistence_setting.unlock,
+ passphrase,
+ unlocked_cb,
+ failed_cb)
+
+ )
+ unlocking_thread.start()
+
+ def cb_unlock_failed(self):
+ logging.debug("Storage unlock failed")
+ self.entry_storage_passphrase.set_sensitive(True)
+ self.button_storage_unlock.set_sensitive(True)
+ self.button_storage_unlock.set_label(_("Unlock"))
+ self.image_storage_state.set_visible(True)
+ self.spinner_storage_unlock.set_visible(False)
+ self.label_infobar_persistence.set_label(
+ _("Cannot unlock encrypted storage with this passphrase."))
+ self.infobar_persistence.set_visible(True)
+ self.entry_storage_passphrase.select_region(0, -1)
+ self.entry_storage_passphrase.set_icon_from_icon_name(
+ Gtk.EntryIconPosition.SECONDARY,
+ 'dialog-warning-symbolic')
+ self.entry_storage_passphrase.grab_focus()
+
+ def cb_unlocked(self):
+ logging.debug("Storage unlocked")
+ self.spinner_storage_unlock.set_visible(False)
+ self.entry_storage_passphrase.set_visible(False)
+ self.button_storage_unlock.set_visible(False)
+ self.infobar_persistence.set_visible(False)
+ self.image_storage_state.set_from_icon_name('tails-unlocked',
+ Gtk.IconSize.BUTTON)
+ self.image_storage_state.set_visible(True)
+ self.box_storage_unlocked.set_visible(True)
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/popover.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/popover.py
new file mode 100644
index 0000000..8650ca3
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/popover.py
@@ -0,0 +1,40 @@
+import gi
+from typing import Callable, Union
+
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+
+
+class Popover(object):
+ def __init__(self, relative_widget, content_widget: Gtk.Popover):
+ self.widget = Gtk.Popover.new(relative_widget)
+ self.widget.set_position(Gtk.PositionType.BOTTOM)
+ self.widget.add(content_widget)
+ self.closed_cb = None # type: Union[None, Callable]
+ self.closed_cb_user_data = None
+ self.opened_cb = None # type: Union[None, Callable]
+ self.opened_cb_user_data = None
+ self.closed_signal_handler = None
+ self.response = None # type: Union[None, Gtk.ResponseType]
+
+ def on_closed(self, widget):
+ if self.closed_cb:
+ self.closed_cb(self, self.closed_cb_user_data)
+ # Make sure we only call the callback once
+ self.closed_cb = None
+ self.widget.disconnect(self.closed_signal_handler)
+
+ def open(self, closed_cb: Callable, user_data=None):
+ self.closed_cb = closed_cb
+ self.closed_cb_user_data = user_data
+ self.closed_signal_handler = self.widget.connect('closed', self.on_closed)
+ self.widget.set_visible(True)
+ if self.opened_cb:
+ self.opened_cb(self, self.opened_cb_user_data)
+
+ def close(self, response: Gtk.ResponseType):
+ self.response = response
+ self.widget.set_visible(False)
+
+ def is_open(self) -> bool:
+ return self.widget.get_visible()
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/region_settings.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/region_settings.py
new file mode 100644
index 0000000..c396390
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/region_settings.py
@@ -0,0 +1,179 @@
+import logging
+import gi
+
+from tailsgreeter import TRANSLATION_DOMAIN
+import tailsgreeter.config
+from tailsgreeter.ui import _
+from tailsgreeter.ui.setting import GreeterSetting
+from tailsgreeter.ui.popover import Popover
+from typing import TYPE_CHECKING
+
+gi.require_version('Gtk', '3.0')
+gi.require_version('Pango', '1.0')
+from gi.repository import Gtk, Pango
+
+if TYPE_CHECKING:
+ from tailsgreeter.settings.localization import LocalizationSetting
+
+REGION_SETTINGS_UI_FILE = "region_settings.ui"
+
+
+class LocalizationSettingUI(GreeterSetting):
+ def __init__(self, localization_setting: "LocalizationSetting"):
+ self._localization_setting = localization_setting
+ super().__init__()
+ self.selected_code = "" # type: str
+ self.selected_name = "" # type: str
+
+ self._localization_setting.connect("notify::value", self.cb_value_changed)
+
+ self.treestore = self._localization_setting.get_tree()
+
+ self.builder = Gtk.Builder()
+ self.builder.set_translation_domain(TRANSLATION_DOMAIN)
+ self.builder.add_from_file(tailsgreeter.config.data_path + REGION_SETTINGS_UI_FILE)
+ popover_box = self.builder.get_object("box_{}_popover".format(self.id))
+ self.popover = Popover(self.listboxrow, popover_box)
+
+ self.treeview = self.builder.get_object("treeview_{}".format(self.id))
+ self.treeview.connect("row-activated", self.cb_treeview_row_activated)
+
+ # Fill the treeview
+ renderer = Gtk.CellRendererText()
+ renderer.props.ellipsize = Pango.EllipsizeMode.END
+ column = Gtk.TreeViewColumn("", renderer, text=1)
+ self.treeview.append_column(column)
+
+ searchentry = self.builder.get_object("searchentry_{}".format(self.id))
+ searchentry.connect("search-changed", self.cb_searchentry_search_changed)
+ searchentry.connect("activate", self.cb_searchentry_activate)
+
+ self.treestore_filtered = self.treestore.filter_new()
+ self.treestore_filtered.set_visible_func(self.cb_liststore_filtered_visible_func, data=searchentry)
+ self.treeview.set_model(self.treestore_filtered)
+
+ def apply(self):
+ self._localization_setting.set_value(self.selected_code, chosen_by_user=True)
+
+ def cb_searchentry_activate(self, searchentry, user_data=None):
+ """Selects the topmost item in the treeview when pressing Enter"""
+ if searchentry.get_text():
+ self.treeview.row_activated(Gtk.TreePath.new_from_string("0"),
+ self.treeview.get_column(0))
+ else:
+ self.popover.close(Gtk.ResponseType.CANCEL)
+
+ def cb_searchentry_search_changed(self, searchentry, user_data=None):
+ self.treestore_filtered.refilter()
+ if searchentry.get_text():
+ self.treeview.expand_all()
+ self.treeview.scroll_to_point(0, 0) # scroll to top
+ else:
+ self.treeview.collapse_all()
+ return False
+
+ def cb_treeview_row_activated(self, treeview, path, column,
+ user_data=None):
+ treemodel = treeview.get_model()
+ self.selected_code = treemodel.get_value(treemodel.get_iter(path), 0)
+ self.selected_name = treemodel.get_value(treemodel.get_iter(path), 1)
+ self.popover.close(Gtk.ResponseType.YES)
+
+ def cb_value_changed(self, obj, param):
+ logging.debug("refreshing {}".format(self._localization_setting.get_name()))
+
+ def treeview_select_line(model, path, iter_, data):
+ if model.get_value(iter_, 0) == data:
+ self.treeview.get_selection().select_iter(iter_)
+ self.treeview.scroll_to_cell(path, use_align=True,
+ row_align=0.5)
+ return True
+ else:
+ return False
+
+ self.treestore_filtered.foreach(
+ treeview_select_line,
+ self._localization_setting.get_value())
+
+ def cb_liststore_filtered_visible_func(self, model, treeiter, searchentry):
+ search_query = searchentry.get_text().lower()
+ if not search_query:
+ return True
+
+ # Does the current node match the search?
+ value = model.get_value(treeiter, 1).lower()
+ if search_query in value:
+ return True
+
+ # Does the parent node match the search?
+ treepath = model.get_path(treeiter)
+ parent_treepath = treepath.copy()
+ parent_treepath.up()
+ if parent_treepath.get_depth() == 1:
+ # treepath is now the parent
+ parent_value = model.get_value(model.get_iter(parent_treepath), 0)
+ return search_query in parent_value
+
+ # Does any of the children nodes match the search?
+ children_treeiter = model.iter_children(treeiter)
+ while children_treeiter:
+ child_value = model.get_value(children_treeiter, 0)
+ if search_query in child_value:
+ return True
+ children_treeiter = model.iter_next(children_treeiter)
+
+ return False
+
+
+class LanguageSettingUI(LocalizationSettingUI):
+ @property
+ def id(self) -> str:
+ return "language"
+
+ @property
+ def title(self) -> str:
+ return _("_Language")
+
+ @property
+ def icon_name(self):
+ return "tails-language"
+
+ @property
+ def value_for_display(self) -> str:
+ return self._localization_setting.get_name()
+
+
+class KeyboardSettingUI(LocalizationSettingUI):
+ @property
+ def id(self) -> str:
+ return "keyboard"
+
+ @property
+ def title(self) -> str:
+ return _("_Keyboard Layout")
+
+ @property
+ def icon_name(self):
+ return "tails-keyboard-layout"
+
+ @property
+ def value_for_display(self) -> str:
+ return self._localization_setting.get_name()
+
+
+class FormatsSettingUI(LocalizationSettingUI):
+ @property
+ def id(self) -> str:
+ return "formats"
+
+ @property
+ def title(self) -> str:
+ return _("_Formats")
+
+ @property
+ def icon_name(self):
+ return "tails-formats"
+
+ @property
+ def value_for_display(self) -> str:
+ return self._localization_setting.get_name()
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/setting.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/setting.py
new file mode 100644
index 0000000..ae76384
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/setting.py
@@ -0,0 +1,56 @@
+from typing import TYPE_CHECKING
+import gi
+
+from tailsgreeter import TRANSLATION_DOMAIN
+import tailsgreeter.config
+from tailsgreeter.ui.popover import Popover, Union
+
+if TYPE_CHECKING:
+ from tailsgreeter.ui.main_window import GreeterMainWindow
+
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+
+
+SETTING_UI_FILE = "setting.ui"
+
+
+class GreeterSetting(object):
+ """Base class of all settings in the greeter"""
+ @property
+ def id(self) -> str:
+ return str()
+
+ @property
+ def title(self) -> str:
+ return str()
+
+ @property
+ def icon_name(self) -> str:
+ return str()
+
+ @property
+ def value_for_display(self) -> str:
+ return str()
+
+ def __init__(self):
+ self.accel_key = None
+ self.popover = None # type: Union[None, Popover]
+ self.main_window = None # type: Union[None, GreeterMainWindow]
+
+ self.builder = Gtk.Builder()
+ self.builder.set_translation_domain(TRANSLATION_DOMAIN)
+ self.builder.add_from_file((tailsgreeter.config.data_path + SETTING_UI_FILE))
+ self.listboxrow = self.builder.get_object("listboxrow") # type: Gtk.ListBoxRow
+ image = self.builder.get_object("image") # type: Gtk.Image
+ image.set_from_icon_name(self.icon_name, Gtk.IconSize.LARGE_TOOLBAR)
+ self.title_label = self.builder.get_object("label_caption")
+ self.value_label = self.builder.get_object("label_value")
+ self.title_label.set_label(self.title)
+ self.update_value_label()
+
+ def update_value_label(self):
+ self.value_label.set_label(self.value_for_display)
+
+ def has_popover(self) -> bool:
+ return self.popover is not None
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/settings_collection.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/settings_collection.py
new file mode 100644
index 0000000..65b9c5c
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/ui/settings_collection.py
@@ -0,0 +1,36 @@
+import gi
+
+from tailsgreeter.ui.setting import GreeterSetting
+from tailsgreeter.ui.region_settings import LocalizationSettingUI
+from tailsgreeter.ui.additional_settings import AdditionalSetting
+
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+
+
+class GreeterSettingsCollection(object):
+ def __init__(self, *settings: GreeterSetting, no_subclassification=False):
+ self.settings = {setting.id: setting for setting in settings}
+
+ if no_subclassification:
+ return
+
+ self.region_settings = GreeterSettingsCollection(
+ *(s for s in self.settings.values() if isinstance(s, LocalizationSettingUI)),
+ no_subclassification=True,
+ )
+ self.additional_settings = GreeterSettingsCollection(
+ *(s for s in self.settings.values() if isinstance(s, AdditionalSetting)),
+ no_subclassification=True,
+ )
+
+ def __getitem__(self, key) -> GreeterSetting:
+ return self.settings[key]
+
+ def __iter__(self):
+ return iter(self.settings.values())
+
+ def id_from_row(self, row: Gtk.ListBoxRow):
+ for setting in self.settings.values():
+ if setting.listboxrow == row:
+ return setting.id
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/utils.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/utils.py
index 438cd60..383718a 100644
--- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/utils.py
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailsgreeter/utils.py
@@ -18,43 +18,6 @@
import logging
import subprocess
-import gi
-
-gi.require_version('Gtk', '3.0')
-from gi.repository import Gtk # NOQA: E402
-
-# Mark translatable strings, but don't actually translate them, as we
-# delegate this to TranslatableWindow that handles on-the-fly language changes
-_ = lambda text: text # NOQA: E731
-
-
-def popover_toggle(popover):
- """Toggle the visibility of popover"""
- if popover.get_visible():
- popover.set_visible(False)
- else:
- popover.set_visible(True)
-
-
-def get_on_off_string(value, default=None):
- """Return "On"|"Off" [" (default)"] based on value and default"""
- if value == default:
- if value:
- return _("On (default)")
- else:
- return _("Off (default)")
- else:
- if value:
- return _("On")
- else:
- return _("Off")
-
-
-def import_builder_objects(cls, builder, names):
- """Import Gtk.Builder objects with names as attributes of cls"""
- for name in names:
- setattr(cls, name, builder.get_object(name))
-
def check_output_and_error(args, exception, error_message, stdin=None):
"""Launch a process checking its output and raising exception if needed
@@ -80,15 +43,3 @@ def check_output_and_error(args, exception, error_message, stdin=None):
returncode=proc.returncode, stdout=out, stderr=err)
)
return out
-
-
-def setting_id_from_row(row):
- """Return a setting id from a Gtk.ListRow
-
- The Gtk.ListRow should be named listboxrow_settings_<setting_id>.
- """
- if not row:
- return None
- else:
- row_id = Gtk.Buildable.get_name(row)
- return row_id.replace("listboxrow_", "")
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailslib/systemd.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailslib/systemd.py
new file mode 100644
index 0000000..358bb3a
--- /dev/null
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailslib/systemd.py
@@ -0,0 +1,8 @@
+import sh
+
+def tor_has_bootstrapped() -> bool:
+ try:
+ sh.systemctl("is-active", "tails-tor-has-bootstrapped.target")
+ return True
+ except sh.ErrorReturnCode:
+ return False
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailslib/tor.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/tailslib/tor.py
deleted file mode 100644
index 5975ab2..0000000
--- a/config/chroot_local-includes/usr/lib/python3/dist-packages/tailslib/tor.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import stem
-from stem.control import Controller
-
-CONTROL_SOCKET_PATH = '/var/run/tor/control'
-
-
-def tor_has_bootstrapped():
- try:
- c = Controller.from_socket_file(CONTROL_SOCKET_PATH)
- except stem.SocketError:
- # Socket is not available
- return False
- c.authenticate()
- info = c.get_info("status/bootstrap-phase")
- return "PROGRESS=100" in info.split()
diff --git a/config/chroot_local-includes/usr/lib/python3/dist-packages/unlock_veracrypt_volumes/volume.py b/config/chroot_local-includes/usr/lib/python3/dist-packages/unlock_veracrypt_volumes/volume.py
index 513812f..1bfef27 100644
--- a/config/chroot_local-includes/usr/lib/python3/dist-packages/unlock_veracrypt_volumes/volume.py
+++ b/config/chroot_local-includes/usr/lib/python3/dist-packages/unlock_veracrypt_volumes/volume.py
@@ -1,12 +1,18 @@
+import gi
+
from logging import getLogger
from typing import Union
-from gi.repository import Gtk, GLib, Gio, UDisks
-
from unlock_veracrypt_volumes import _
from unlock_veracrypt_volumes.config import TRANSLATION_DOMAIN, VOLUME_UI_FILE
from unlock_veracrypt_volumes.exceptions import UdisksObjectNotFoundError, AlreadyUnlockedError
+gi.require_version('Gtk', '3.0')
+gi.require_version('GLib', '2.0')
+gi.require_version('Gio', '2.0')
+from gi.repository import Gtk, GLib, Gio, UDisks
+
+
logger = getLogger(__name__)
diff --git a/config/chroot_local-includes/usr/local/bin/electrum b/config/chroot_local-includes/usr/local/bin/electrum
index 38dbda9..6c1e9d4 100755
--- a/config/chroot_local-includes/usr/local/bin/electrum
+++ b/config/chroot_local-includes/usr/local/bin/electrum
@@ -16,6 +16,7 @@ goodcrypto.com converted from bash to python and added basic tests.
import os
import sys
+import subprocess
from gettext import gettext
import sh
@@ -31,6 +32,10 @@ def main(*args):
if not verify_start():
return
+ # Disable update checking for all users (even those who made their config
+ # persistent before we changed this value in the default config), because
+ # users can't easily update to a new version anyway if it's not in Debian.
+ subprocess.run(['/usr/bin/electrum', 'setconfig', 'check_updates', 'false'], check=True, stdout=subprocess.DEVNULL)
os.execv('/usr/bin/electrum', ['/usr/bin/electrum'] + list(args))
@@ -56,7 +61,7 @@ def verify_start():
disabled_text = gettext('Persistence is disabled for Electrum')
warning_text = gettext(
- "When you reboot Tails, all of Electrum's data will be lost, including your Bitcoin wallet. It is strongly recommended to only run Electrum when its persistence feature is activated.")
+ "When you reboot Tails, all of Electrum's data will be lost, including your Bitcoin wallet.\nIt is strongly recommended to only run Electrum when its persistence feature is activated.")
question_text = gettext('Do you want to start Electrum anyway?')
dialog_msg = ('<b><big>{}</big></b>\n\n{}\n\n{}\n'.
format(disabled_text, warning_text, question_text))
diff --git a/config/chroot_local-includes/usr/local/bin/replace-su-with-sudo b/config/chroot_local-includes/usr/local/bin/replace-su-with-sudo
index 33e7142..a793364 100755
--- a/config/chroot_local-includes/usr/local/bin/replace-su-with-sudo
+++ b/config/chroot_local-includes/usr/local/bin/replace-su-with-sudo
@@ -21,7 +21,7 @@ def main() -> None:
print(_('su is disabled. Please use sudo instead.'))
sys.exit(0)
else:
- print(open("/usr/share/tails-greeter/no-password-lecture.txt").read())
+ print(open("/usr/share/tails/greeter/no-password-lecture.txt").read())
sys.exit(1)
if __name__ == "__main__":
diff --git a/config/chroot_local-includes/usr/local/bin/tails-documentation b/config/chroot_local-includes/usr/local/bin/tails-documentation
index c65c610..f91598a 100755
--- a/config/chroot_local-includes/usr/local/bin/tails-documentation
+++ b/config/chroot_local-includes/usr/local/bin/tails-documentation
@@ -4,6 +4,8 @@ import os
import os.path
import sys
+from tailslib.systemd import tor_has_bootstrapped
+
# Main
try:
@@ -22,7 +24,7 @@ lang_code = os.getenv('LANG', 'en')[0:2]
# If possible, let's hand-off to our website, which should be the most
# up-to-date option.
-if os.system('/usr/local/sbin/tor-has-bootstrapped') == 0:
+if tor_has_bootstrapped():
if os.path.isfile(os.path.join(
wiki_path, page + '.' + lang_code + ".html")):
uri = tails_homepage + '/' + page + '/index.' + lang_code + '.html'
diff --git a/config/chroot_local-includes/usr/local/bin/tor-browser b/config/chroot_local-includes/usr/local/bin/tor-browser
index 4abdcd2..8e54493 100755
--- a/config/chroot_local-includes/usr/local/bin/tor-browser
+++ b/config/chroot_local-includes/usr/local/bin/tor-browser
@@ -22,6 +22,9 @@ PROFILE="${HOME}/.tor-browser/profile.default"
# Get LIVE_USERNAME
. /etc/live/config.d/username.conf
+# Import tor_has_bootstrapped()
+. /usr/local/lib/tails-shell-library/systemd.sh
+
# Allow Torbutton access to the control port filter (for new identity).
# Setting a password is required, otherwise Torbutton attempts to
# read the authentication cookie file instead, which fails.
@@ -68,7 +71,7 @@ start_browser() {
}
-if /usr/local/sbin/tor-has-bootstrapped || ask_for_confirmation; then
+if tor_has_bootstrapped || ask_for_confirmation; then
# Torbutton 1.5.1+ uses those environment variables
export TOR_SOCKS_HOST='127.0.0.1'
export TOR_SOCKS_PORT='9150'
diff --git a/config/chroot_local-includes/usr/local/lib/tails-greeter b/config/chroot_local-includes/usr/local/lib/tails-greeter
index 7637a04..a7ade34 100755
--- a/config/chroot_local-includes/usr/local/lib/tails-greeter
+++ b/config/chroot_local-includes/usr/local/lib/tails-greeter
@@ -1,5 +1,5 @@
#!/bin/bash
-cd /usr/share/tails-greeter/
+cd /usr/share/tails/greeter/
export LANG="en_US.UTF-8"
-/usr/share/tails-greeter/set-cursor.py watch
-/usr/bin/python3 ./tails-greeter.py
+/usr/share/tails/greeter/set-cursor.py watch
+/usr/bin/python3 ./tails-greeter.py "$@"
diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/po.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/po.sh
index bb041f5..05a5668 100644
--- a/config/chroot_local-includes/usr/local/lib/tails-shell-library/po.sh
+++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/po.sh
@@ -7,6 +7,15 @@ po_languages () {
done
}
+count_msgids () {
+ cat | grep -E '^msgid\s+' | wc -l
+}
+
+count_translated_strings () {
+ cat | msgattrib --translated --no-fuzzy --no-obsolete - \
+ | count_msgids
+}
+
diff_without_pot_creation_date () {
diff --ignore-matching-lines '^"POT-Creation-Date:' "${@}"
}
diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/systemd.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/systemd.sh
new file mode 100755
index 0000000..4e9e2f5
--- /dev/null
+++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/systemd.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+tor_has_bootstrapped() {
+ /bin/systemctl --quiet is-active tails-tor-has-bootstrapped.target
+}
diff --git a/config/chroot_local-includes/usr/local/lib/tails-shell-library/tails-greeter.sh b/config/chroot_local-includes/usr/local/lib/tails-shell-library/tails-greeter.sh
index dc6cc26..ca0c4db 100644
--- a/config/chroot_local-includes/usr/local/lib/tails-shell-library/tails-greeter.sh
+++ b/config/chroot_local-includes/usr/local/lib/tails-shell-library/tails-greeter.sh
@@ -1,7 +1,8 @@
#!/bin/sh
-PERSISTENCE_STATE='/var/lib/live/config/tails.persistence'
-PHYSICAL_SECURITY_SETTINGS='/var/lib/live/config/tails.physical_security'
+PERSISTENCE_SETTING='/var/lib/live/config/tails.persistence'
+MACSPOOF_SETTING='/var/lib/live/config/tails.macspoof'
+NETWORK_SETTING='/var/lib/live/config/tails.network'
_get_tg_setting() {
if [ -r "${1}" ]; then
@@ -11,7 +12,7 @@ _get_tg_setting() {
}
persistence_is_enabled() {
- [ "$(_get_tg_setting "${PERSISTENCE_STATE}" TAILS_PERSISTENCE_ENABLED)" = true ]
+ [ "$(_get_tg_setting "${PERSISTENCE_SETTING}" TAILS_PERSISTENCE_ENABLED)" = true ]
}
persistence_is_enabled_for() {
@@ -20,15 +21,15 @@ persistence_is_enabled_for() {
persistence_is_enabled_read_write() {
persistence_is_enabled && \
- [ "$(_get_tg_setting "${PERSISTENCE_STATE}" TAILS_PERSISTENCE_READONLY)" != true ]
+ [ "$(_get_tg_setting "${PERSISTENCE_SETTING}" TAILS_PERSISTENCE_READONLY)" != true ]
}
mac_spoof_is_enabled() {
# Only return false when explicitly told so to increase failure
# safety.
- [ "$(_get_tg_setting "${PHYSICAL_SECURITY_SETTINGS}" TAILS_MACSPOOF_ENABLED)" != false ]
+ [ "$(_get_tg_setting "${MACSPOOF_SETTING}" TAILS_MACSPOOF_ENABLED)" != false ]
}
tails_netconf() {
- _get_tg_setting "${PHYSICAL_SECURITY_SETTINGS}" TAILS_NETCONF
+ _get_tg_setting "${NETWORK_SETTING}" TAILS_NETCONF
}
diff --git a/config/chroot_local-includes/usr/local/lib/tails-unblock-network b/config/chroot_local-includes/usr/local/lib/tails-unblock-network
index 5f8e1b5..3e33d08 100755
--- a/config/chroot_local-includes/usr/local/lib/tails-unblock-network
+++ b/config/chroot_local-includes/usr/local/lib/tails-unblock-network
@@ -4,7 +4,7 @@ set -e
set -u
set -x
-CONFIG_FILE=/var/lib/gdm3/tails.physical_security
+CONFIG_FILE=/var/lib/gdm3/tails.network
NET_MODULES_BLACKLIST=/etc/modprobe.d/all-net-blacklist.conf
# Import the TAILS_NETCONF variable
diff --git a/config/chroot_local-includes/usr/local/sbin/restart-tor b/config/chroot_local-includes/usr/local/sbin/restart-tor
index 895b12c..389c99e 100755
--- a/config/chroot_local-includes/usr/local/sbin/restart-tor
+++ b/config/chroot_local-includes/usr/local/sbin/restart-tor
@@ -6,7 +6,7 @@ import sys
import sh
-from tailslib.tor import tor_has_bootstrapped
+from tailslib.systemd import tor_has_bootstrapped
from tailslib.exceptions import TorFailedToBoostrapError
diff --git a/config/chroot_local-includes/usr/local/sbin/tor-has-bootstrapped b/config/chroot_local-includes/usr/local/sbin/tor-has-bootstrapped
deleted file mode 100755
index 326e09a..0000000
--- a/config/chroot_local-includes/usr/local/sbin/tor-has-bootstrapped
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/sh
-
-/bin/systemctl --quiet is-active tor@default.service || exit 1
-/bin/systemctl --quiet is-active tails-tor-has-bootstrapped.target
diff --git a/config/chroot_local-includes/usr/local/sbin/unsafe-browser b/config/chroot_local-includes/usr/local/sbin/unsafe-browser
index bf0d711..ebbde63 100755
--- a/config/chroot_local-includes/usr/local/sbin/unsafe-browser
+++ b/config/chroot_local-includes/usr/local/sbin/unsafe-browser
@@ -7,8 +7,8 @@ set -u
TEXTDOMAIN="tails"
export TEXTDOMAIN
-# Import tor_is_working()
-. /usr/local/lib/tails-shell-library/tor.sh
+# Import tor_has_bootstrapped()
+. /usr/local/lib/tails-shell-library/systemd.sh
# Import the TBB_EXT variable, and guess_best_tor_browser_locale().
. /usr/local/lib/tails-shell-library/tor-browser.sh
@@ -63,7 +63,7 @@ maybe_restart_tor () {
# Restart Tor if it's not working (a captive portal may have prevented
# Tor from bootstrapping, and a restart is the fastest way to get
# wheels turning)
- if ! tor_is_working; then
+ if ! tor_has_bootstrapped; then
echo "* Restarting Tor"
restart-tor
if ! systemctl --quiet is-active tor@default.service; then
diff --git a/config/chroot_local-includes/usr/share/gdm/dconf/50-tails b/config/chroot_local-includes/usr/share/gdm/dconf/50-tails
index 9bbfde9..0245581 100644
--- a/config/chroot_local-includes/usr/share/gdm/dconf/50-tails
+++ b/config/chroot_local-includes/usr/share/gdm/dconf/50-tails
@@ -1,6 +1,10 @@
[org/gnome/desktop/background]
picture-uri='file:///usr/share/tails/desktop_wallpaper.png'
+[org/gnome/desktop/input-sources]
+# Hide duplicate and obscure keyboard layouts (#17089)
+show-all-sources = false
+
[org/gnome/desktop/peripherals/touchpad]
natural-scroll = true
tap-to-click = true
diff --git a/config/chroot_local-includes/usr/share/tails-greeter/greeter.ui b/config/chroot_local-includes/usr/share/tails-greeter/greeter.ui
deleted file mode 100644
index 08e00e1..0000000
--- a/config/chroot_local-includes/usr/share/tails-greeter/greeter.ui
+++ /dev/null
@@ -1,2021 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.20.0 -->
-<interface domain="tails">
- <requires lib="gtk+" version="3.20"/>
- <object class="GtkBox" id="box_admin_popover">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">18</property>
- <property name="margin_right">18</property>
- <property name="margin_top">18</property>
- <property name="margin_bottom">18</property>
- <property name="orientation">vertical</property>
- <property name="spacing">18</property>
- <child>
- <object class="GtkLabel" id="label_admin_title">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Administration Password</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- <attribute name="scale" value="1.5"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_admin_description">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Set up an administration password if you need to perform administrative tasks. Otherwise, the administration password is disabled for better security.</property>
- <property name="justify">fill</property>
- <property name="wrap">True</property>
- <property name="width_chars">50</property>
- <property name="max_width_chars">50</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="box_admin_password">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label_admin_password">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Administration Password</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_admin_password">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="visibility">False</property>
- <property name="placeholder_text" translatable="yes">Enter an administration password</property>
- <signal name="activate" handler="cb_entry_admin_password_activate" swapped="no"/>
- <signal name="changed" handler="cb_entry_admin_changed" swapped="no"/>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="box_admin_verify">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label_admin_verify">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Confirm</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="entry_admin_verify">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="visibility">False</property>
- <property name="placeholder_text" translatable="yes">Confirm your administration password</property>
- <signal name="activate" handler="cb_entry_admin_verify_activate" swapped="no"/>
- <signal name="changed" handler="cb_entry_admin_changed" swapped="no"/>
- <signal name="focus-out-event" handler="cb_entry_admin_focus_out_event" swapped="no"/>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="button_admin_disable">
- <property name="label" translatable="yes">Disable</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <signal name="clicked" handler="cb_button_admin_disable_clicked" swapped="no"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">4</property>
- </packing>
- </child>
- </object>
- <object class="GtkSizeGroup" id="sizegroup_admin">
- <widgets>
- <widget name="label_admin_password"/>
- <widget name="label_admin_verify"/>
- </widgets>
- </object>
- <object class="GtkBox" id="box_camouflage_popover">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">18</property>
- <property name="margin_right">18</property>
- <property name="margin_top">18</property>
- <property name="margin_bottom">18</property>
- <property name="orientation">vertical</property>
- <property name="spacing">18</property>
- <child>
- <object class="GtkLabel" id="label_camouflage_title">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes" comments="This string will never be displayed in the 1st version of the greeter.">Windows Camouflage</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- <attribute name="scale" value="1.5"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_camouflage_description">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes" comments="This string will never be displayed in the 1st version of the greeter.">This option makes Tails look like Microsoft Windows 10. This can be useful to avoid attracting suspicion in public places.</property>
- <property name="justify">fill</property>
- <property name="wrap">True</property>
- <property name="width_chars">50</property>
- <property name="max_width_chars">50</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="box_camouflage_controls">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label_camouflage_controls">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes" comments="This string will never be displayed in the 1st version of the greeter.">Microsoft Windows 10 camouflage</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkSwitch" id="switch_camouflage">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <object class="GtkBox" id="box_macspoof_popover">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">18</property>
- <property name="margin_right">18</property>
- <property name="margin_top">18</property>
- <property name="margin_bottom">18</property>
- <property name="orientation">vertical</property>
- <property name="spacing">18</property>
- <child>
- <object class="GtkLabel" id="label_macspoof_title">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">MAC Address Spoofing</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- <attribute name="scale" value="1.5"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_macspoof_description">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">MAC address spoofing hides the serial number of your network interface (Wi-Fi or wired) to the local network. Spoofing MAC addresses is generally safer as it helps you hide your geographical location. But it might also create connectivity problems or look suspicious.</property>
- <property name="justify">fill</property>
- <property name="wrap">True</property>
- <property name="width_chars">50</property>
- <property name="max_width_chars">50</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkFrame" id="frame_macspoof">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_bottom">18</property>
- <property name="label_xalign">0</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkListBox" id="listbox_macspoof_controls">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="selection_mode">browse</property>
- <signal name="row-activated" handler="cb_listbox_macspoof_row_activated" swapped="no"/>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_macspoof_on">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkBox" id="box_macspoof_on">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label_macspoof_on">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Spoof all MAC addresses (default)</property>
- <property name="justify">fill</property>
- <property name="wrap">True</property>
- <property name="max_width_chars">45</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkImage" id="image_macspoof_on">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">emblem-ok-symbolic</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_macspoof_off">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkBox" id="box_macspoof_off">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label_macspoof_off">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Don't spoof MAC addresses</property>
- <property name="wrap">True</property>
- <property name="max_width_chars">45</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkImage" id="image_macspoof_off">
- <property name="can_focus">False</property>
- <property name="icon_name">emblem-ok-symbolic</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child type="label_item">
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <object class="GtkBox" id="box_main">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkInfoBar" id="infobar_persistence">
- <property name="can_focus">False</property>
- <property name="message_type">warning</property>
- <property name="show_close_button">True</property>
- <signal name="close" handler="cb_infobar_close" swapped="no"/>
- <signal name="response" handler="cb_infobar_response" swapped="no"/>
- <child internal-child="action_area">
- <object class="GtkButtonBox" id="infobar_persistence-action_area">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">6</property>
- <property name="layout_style">end</property>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child internal-child="content_area">
- <object class="GtkBox" id="infobar_persistence-content_area">
- <property name="can_focus">False</property>
- <property name="spacing">16</property>
- <child>
- <object class="GtkLabel" id="label_infobar_persistence">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Cannot unlock encrypted storage with this passphrase.</property>
- <property name="wrap">True</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkInfoBar" id="infobar_network">
- <property name="app_paintable">True</property>
- <property name="can_focus">False</property>
- <property name="show_close_button">True</property>
- <signal name="close" handler="cb_infobar_close" swapped="no"/>
- <signal name="response" handler="cb_infobar_response" swapped="no"/>
- <child internal-child="action_area">
- <object class="GtkButtonBox" id="infobar_network-action_area">
- <property name="can_focus">False</property>
- <property name="spacing">6</property>
- <property name="layout_style">end</property>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child internal-child="content_area">
- <object class="GtkBox" id="infobar_network-content_area">
- <property name="can_focus">False</property>
- <property name="spacing">16</property>
- <child>
- <object class="GtkLabel" id="label_infobar_network">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">You will configure the Tor bridge and local proxy later on after connecting to a network.</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="box_inner">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">18</property>
- <property name="margin_right">18</property>
- <property name="margin_top">18</property>
- <property name="margin_bottom">18</property>
- <property name="orientation">vertical</property>
- <property name="spacing">18</property>
- <child>
- <object class="GtkBox" id="box_header">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkLabel" id="label_header_title">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Welcome to Tails!</property>
- <attributes>
- <attribute name="weight" value="semibold"/>
- <attribute name="scale" value="1.5"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_header_explanation">
- <property name="can_focus">False</property>
- <property name="label" translatable="yes" context="&quot;Take a Tour&quot; would be an assistant to guide the user through the available settings." comments="This string will never be displayed in the 1st version of the greeter.">To get guided through Tails' settings, click on &lt;b&gt;Take a Tour&lt;/b&gt; above</property>
- <property name="use_markup">True</property>
- <property name="justify">fill</property>
- <property name="wrap">True</property>
- <property name="lines">2</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="box_language">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkBox" id="box_language_header">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label_language_header_title">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Language &amp; Region</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLinkButton" id="linkbutton_language_help">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="receives_default">True</property>
- <property name="relief">none</property>
- <property name="uri">doc/first_steps/startup_options.en.html#locale</property>
- <signal name="activate-link" handler="cb_linkbutton_help_activate" swapped="no"/>
- <child>
- <object class="GtkImage" id="image_language_help">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-help</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_language_header_status">
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Default Settings</property>
- <attributes>
- <attribute name="style" value="italic"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="checkbutton_language_save">
- <property name="label" translatable="yes">Save Language &amp; Region Settings</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="xalign">0</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">3</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkFrame" id="frame_language">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label_xalign">0</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkListBox" id="listbox_language">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <signal name="row-activated" handler="cb_listbox_language_row_activated" swapped="no"/>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_text">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkBox" id="box_text">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkImage" id="image_text">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-language</property>
- <property name="icon_size">3</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_text_caption">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">_Language</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">listboxrow_text</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_text_value">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label">English</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_keyboard">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkBox" id="box_keyboard">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkImage" id="image_keyboard">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-keyboard-layout</property>
- <property name="icon_size">3</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_keyboard_caption">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">_Keyboard Layout</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">listboxrow_keyboard</property>
- <property name="ellipsize">end</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_keyboard_value">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label">English (US)</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_formats">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkBox" id="box_formats">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkImage" id="image_formats">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-formats</property>
- <property name="icon_size">3</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_formats_caption">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">_Formats</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">listboxrow_formats</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_formats_value">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label">United States</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_tz">
- <property name="sensitive">False</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkBox" id="box_tz">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkImage" id="image_tz">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-timezone</property>
- <property name="icon_size">3</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_tz_caption">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">_Time Zone</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">listboxrow_tz</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_tz_value">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label">UTC</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child type="label_item">
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="box_storage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkBox" id="box_storage_header">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label_storage_header_title">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Encrypted _Persistent Storage</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">entry_storage_passphrase</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkImage" id="image_storage_state">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-locked</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkSpinner" id="spinner_storage_unlock">
- <property name="can_focus">False</property>
- <property name="active">True</property>
- <style>
- <class name="suggested-action"/>
- </style>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="checkbutton_storage_show_passphrase">
- <property name="label" translatable="yes">Show Passphrase</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="xalign">0</property>
- <property name="draw_indicator">True</property>
- <signal name="toggled" handler="cb_checkbutton_storage_show_passphrase_toggled" swapped="no"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">3</property>
- </packing>
- </child>
- <child>
- <object class="GtkLinkButton" id="linkbutton_storage_help">
- <property name="visible">False</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="relief">none</property>
- <property name="uri">doc/first_steps/persistence/use.en.html</property>
- <signal name="activate-link" handler="cb_linkbutton_help_activate" swapped="no"/>
- <child>
- <object class="GtkImage" id="image_storage_help">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-help</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">4</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="button_storage_configure">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="always_show_image">True</property>
- <signal name="clicked" handler="cb_button_storage_configure_clicked" swapped="no"/>
- <child>
- <object class="GtkBox" id="box2">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkImage" id="image_storage">
- <property name="can_focus">False</property>
- <property name="icon_name">tails-locked</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_storage_configure">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Configure Persistent Storage</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- </child>
- <style>
- <class name="suggested-action"/>
- </style>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="box_storage_unlock">
- <property name="can_focus">False</property>
- <child>
- <object class="GtkEntry" id="entry_storage_passphrase">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="visibility">False</property>
- <property name="placeholder_text" translatable="yes" comments="The label for this placeholder text is not very big, so keep this string short.">Enter your passphrase to unlock the persistent storage</property>
- <signal name="activate" handler="cb_entry_storage_passphrase_activated" swapped="no"/>
- <signal name="changed" handler="cb_entry_storage_passphrase_changed" swapped="no"/>
- <style>
- <class name="linked_left"/>
- </style>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="button_storage_unlock">
- <property name="label" translatable="yes">Unlock</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <signal name="clicked" handler="cb_button_storage_unlock_clicked" swapped="no"/>
- <style>
- <class name="suggested-action"/>
- <class name="linked_right"/>
- </style>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">3</property>
- </packing>
- </child>
- <style>
- <class name="linked"/>
- </style>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="box_storage_unlocked">
- <property name="can_focus">False</property>
- <child>
- <object class="GtkButton" id="button_storage_lock">
- <property name="label" translatable="yes">Relock Persistent Storage</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <signal name="clicked" handler="cb_button_storage_lock_clicked" swapped="no"/>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_storage_unlocked">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Your persistent storage is unlocked. Restart Tails to lock it again.</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">3</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="box_settings">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkBox" id="box_settings_header">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label_settings_header_title">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">_Additional Settings</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">toolbutton_settings_add</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLinkButton" id="linkbutton_settings_help">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="receives_default">True</property>
- <property name="relief">none</property>
- <property name="uri">doc/first_steps/startup_options.en.html#additional</property>
- <signal name="activate-link" handler="cb_linkbutton_help_activate" swapped="no"/>
- <child>
- <object class="GtkImage" id="image_settings_help">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-help</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <placeholder/>
- </child>
- <child>
- <object class="GtkCheckButton" id="checkbutton_settings_save">
- <property name="label" translatable="yes">Save Additional Settings</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="xalign">0</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">3</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="box_settings_values">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkFrame" id="frame_settings">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label_xalign">0</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkListBox" id="listbox_settings">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <signal name="row-activated" handler="cb_listbox_settings_row_activated" after="yes" swapped="no"/>
- </object>
- </child>
- <child type="label_item">
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkToolbar" id="toolbar_settings">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="show_arrow">False</property>
- <property name="icon_size">2</property>
- <child>
- <object class="GtkToolButton" id="toolbutton_settings_add">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Add an additional setting</property>
- <property name="icon_name">list-add-symbolic</property>
- <signal name="clicked" handler="cb_toolbutton_settings_add_clicked" swapped="no"/>
- <signal name="mnemonic-activate" handler="cb_toolbutton_settings_mnemonic_activate" swapped="no"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="homogeneous">True</property>
- </packing>
- </child>
- <style>
- <class name="inline-toolbar"/>
- </style>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">3</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <object class="GtkBox" id="box_network_popover">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">18</property>
- <property name="margin_right">18</property>
- <property name="margin_top">18</property>
- <property name="margin_bottom">18</property>
- <property name="orientation">vertical</property>
- <property name="spacing">18</property>
- <child>
- <object class="GtkLabel" id="label_network_title">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Network Configuration</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- <attribute name="scale" value="1.5"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_network_description">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">If your Internet connection is censored, filtered, or proxied you can configure a Tor bridge or a local proxy. To work completely offline, you can disable all networking.</property>
- <property name="justify">fill</property>
- <property name="wrap">True</property>
- <property name="max_width_chars">50</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkFrame" id="frame_network">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label_xalign">0</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkListBox" id="listbox_network_controls">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="selection_mode">browse</property>
- <signal name="button-press-event" handler="cb_listbox_network_button_press" swapped="no"/>
- <signal name="row-activated" handler="cb_listbox_network_row_activated" swapped="no"/>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_network_clear">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkBox" id="box_network_clear">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label_network_clear">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Connect directly to the Tor network (default)</property>
- <property name="justify">fill</property>
- <property name="wrap">True</property>
- <property name="max_width_chars">45</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkImage" id="image_network_clear">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">emblem-ok-symbolic</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_network_specific">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkBox" id="box_network_specific">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label_network_specific">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Configure a Tor bridge or local proxy</property>
- <property name="wrap">True</property>
- <property name="max_width_chars">45</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkImage" id="image_network_specific">
- <property name="can_focus">False</property>
- <property name="icon_name">emblem-ok-symbolic</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_network_off">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkBox" id="box_network_off">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">12</property>
- <child>
- <object class="GtkLabel" id="label_network_off">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Disable all networking</property>
- <property name="wrap">True</property>
- <property name="max_width_chars">45</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkImage" id="image_network_off">
- <property name="can_focus">False</property>
- <property name="icon_name">emblem-ok-symbolic</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child type="label_item">
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <object class="GtkLabel" id="label_settings_default">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="label" translatable="yes">The default settings are safe in most situations. To add a custom setting, press the "+" button below.</property>
- <property name="justify">fill</property>
- <property name="wrap">True</property>
- <property name="lines">2</property>
- <property name="xalign">0</property>
- <property name="yalign">0</property>
- </object>
- <object class="GtkListBox" id="listbox_add_setting">
- <property name="width_request">400</property>
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">18</property>
- <property name="margin_right">18</property>
- <property name="margin_top">18</property>
- <property name="margin_bottom">18</property>
- <signal name="focus" handler="cb_listbox_add_setting_focus" after="yes" swapped="no"/>
- <signal name="row-activated" handler="cb_listbox_add_setting_row_activated" swapped="no"/>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_admin">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkBox" id="box_settings_admin">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkImage" id="image_admin">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-admin</property>
- <property name="icon_size">3</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_admin_caption">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">_Administration Password</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">listboxrow_admin</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_admin_value">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Off (default)</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_macspoof">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkBox" id="box_macspoof">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkImage" id="image_macspoof">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-macspoof</property>
- <property name="icon_size">3</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_macspoof_caption">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">_MAC Address Spoofing</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">listboxrow_macspoof</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_macspoof_value">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">On (default)</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_network">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <child>
- <object class="GtkBox" id="box_network">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkImage" id="image_network">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-network</property>
- <property name="icon_size">3</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_network_caption">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">_Network Connection</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">listboxrow_network</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_network_value">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Direct (default)</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkListBoxRow" id="listboxrow_camouflage">
- <property name="sensitive">False</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkBox" id="box_camouflage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">6</property>
- <property name="margin_right">6</property>
- <property name="margin_top">6</property>
- <property name="margin_bottom">6</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkImage" id="image_camouflage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">tails-camouflage</property>
- <property name="icon_size">3</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_camouflage_caption">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">_Windows Camouflage</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">listboxrow_camouflage</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label_camouflage_value">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Off (default)</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- <object class="GtkListStore" id="liststore_formats">
- <columns>
- <!-- column-name id -->
- <column type="gchararray"/>
- <!-- column-name name -->
- <column type="gchararray"/>
- </columns>
- </object>
- <object class="GtkBox" id="box_formats_popover">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">12</property>
- <property name="margin_right">12</property>
- <property name="margin_top">12</property>
- <property name="margin_bottom">12</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkSearchEntry" id="searchentry_formats">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="primary_icon_name">edit-find-symbolic</property>
- <property name="primary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">False</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow_formats">
- <property name="width_request">400</property>
- <property name="height_request">200</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkTreeView" id="treeview_formats">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="model">liststore_formats</property>
- <property name="headers_visible">False</property>
- <property name="activate_on_single_click">True</property>
- <child internal-child="selection">
- <object class="GtkTreeSelection" id="treeview-selection_formats"/>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <object class="GtkListStore" id="liststore_keyboard">
- <columns>
- <!-- column-name id -->
- <column type="gchararray"/>
- <!-- column-name name -->
- <column type="gchararray"/>
- </columns>
- </object>
- <object class="GtkBox" id="box_keyboard_popover">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">12</property>
- <property name="margin_right">12</property>
- <property name="margin_top">12</property>
- <property name="margin_bottom">12</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkSearchEntry" id="searchentry_keyboard">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="primary_icon_name">edit-find-symbolic</property>
- <property name="primary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">False</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow_keyboard">
- <property name="width_request">400</property>
- <property name="height_request">200</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkTreeView" id="treeview_keyboard">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="model">liststore_keyboard</property>
- <property name="headers_visible">False</property>
- <property name="activate_on_single_click">True</property>
- <child internal-child="selection">
- <object class="GtkTreeSelection" id="treeview-selection_keyboard"/>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <object class="GtkListStore" id="liststore_settings_add">
- <columns>
- <!-- column-name setting-id -->
- <column type="gchararray"/>
- <!-- column-name setting-label -->
- <column type="gchararray"/>
- </columns>
- <data>
- <row>
- <col id="0">admin-account</col>
- <col id="1" translatable="yes">Administration Password</col>
- </row>
- <row>
- <col id="0">mac-spoofing</col>
- <col id="1" translatable="yes">MAC Address Spoofing</col>
- </row>
- <row>
- <col id="0">network-configuration</col>
- <col id="1" translatable="yes">Network Configuration</col>
- </row>
- <row>
- <col id="0">camouflage</col>
- <col id="1" translatable="yes">Windows Camouflage</col>
- </row>
- </data>
- </object>
- <object class="GtkListStore" id="liststore_text">
- <columns>
- <!-- column-name id -->
- <column type="gchararray"/>
- <!-- column-name name -->
- <column type="gchararray"/>
- </columns>
- </object>
- <object class="GtkBox" id="box_text_popover">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">12</property>
- <property name="margin_right">12</property>
- <property name="margin_top">12</property>
- <property name="margin_bottom">12</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkSearchEntry" id="searchentry_text">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="primary_icon_name">edit-find-symbolic</property>
- <property name="primary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">False</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow_text">
- <property name="width_request">400</property>
- <property name="height_request">200</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkTreeView" id="treeview_text">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="model">liststore_text</property>
- <property name="headers_visible">False</property>
- <property name="activate_on_single_click">True</property>
- <child internal-child="selection">
- <object class="GtkTreeSelection" id="treeview-selection_text"/>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <object class="GtkListStore" id="liststore_tz">
- <columns>
- <!-- column-name id -->
- <column type="gchararray"/>
- <!-- column-name name -->
- <column type="gchararray"/>
- </columns>
- </object>
- <object class="GtkBox" id="box_tz_popover">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">12</property>
- <property name="margin_right">12</property>
- <property name="margin_top">12</property>
- <property name="margin_bottom">12</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkSearchEntry" id="searchentry_tz">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="primary_icon_name">edit-find-symbolic</property>
- <property name="primary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">False</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="scrolledwindow_tz">
- <property name="width_request">400</property>
- <property name="height_request">200</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkTreeView" id="treeview_tz">
- <property name="visible">True</property>
- <property name="can_focus">True</property>