#!/usr/bin/python
#
# Copyright 2012-2013 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/>
#
"""Persistence handling

"""
import logging
import os
import subprocess

import gettext
_ = gettext.gettext

import tailsgreeter
import tailsgreeter.config
import tailsgreeter.errors
from tailsgreeter.utils import unicode_to_utf8

class PersistenceSettings(object):
    """Model storing settings related to persistence

    """
    def __init__(self):
        pass

    def list_containers(self):
        """Returns a list of persistence containers we might want to unlock."""
        proc = subprocess.Popen(
            [
                "/usr/bin/sudo", "-n", "/usr/local/sbin/live-persist",
                "--log-file=/var/log/live-persist",
                "--encryption=luks",
                "list", "TailsData"
            ],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
            )
        out, err = proc.communicate()
        out = unicode_to_utf8(out)
        err = unicode_to_utf8(err)
        if proc.returncode:
            raise tailsgreeter.errors.LivePersistError(
                _("live-persist failed with return code %(returncode)s:\n%(stderr)s")
                % { 'returncode': proc.returncode, 'stderr': err }
                )
        containers = str.splitlines(out)
        logging.debug("found containers: %s", containers)
        return containers

    def activate(self, device, password, readonly):
        cleartext_device = self.unlock_device(device, password)
        logging.debug("unlocked cleartext_device: %s", cleartext_device)
        self.setup_persistence(cleartext_device, readonly)
        with open(tailsgreeter.config.persistence_state_file, 'w') as f:
            os.chmod(tailsgreeter.config.persistence_state_file, 0o600)
            f.write('TAILS_PERSISTENCE_ENABLED=true\n')
            if readonly:
                f.write('TAILS_PERSISTENCE_READONLY=true\n')

    def unlock_device(self, device, password):
        """Unlock the LUKS persistent device"""
        cleartext_name = 'TailsData_unlocked'
        cleartext_device = '/dev/mapper/' + cleartext_name
        if not os.path.exists(cleartext_device):
            args = [
                "/usr/bin/sudo", "-n",
                "/sbin/cryptsetup", "luksOpen",
                "--tries", "1",
                device, cleartext_name
                ]
            proc = subprocess.Popen(
                args, stdin=subprocess.PIPE,
                stdout=subprocess.PIPE, stderr=subprocess.PIPE
                )
            out, err = proc.communicate(password + "\n")
            out = unicode_to_utf8(out)
            err = unicode_to_utf8(err)
            if proc.returncode:
                logging.debug(
                    "cryptsetup failed with return code %(returncode)s:\n%(stdout)s\n%(stderr)s"
                    % { 'returncode': proc.returncode, 'stdout': out, 'stderr': err })
                raise tailsgreeter.errors.WrongPassphraseError(
                    _("cryptsetup failed with return code %(returncode)s:\n%(stdout)s\n%(stderr)s")
                    % { 'returncode': proc.returncode, 'stdout': out, 'stderr': err }
                    )
            logging.debug("crytpsetup success")
        return cleartext_device

    def setup_persistence(self, cleartext_device, readonly):
        args = [ "/usr/bin/sudo", "-n", "/usr/local/sbin/live-persist" ]
        if readonly:
            args.append('--read-only')
        else:
            args.append('--read-write')
        args.append('--log-file=/var/log/live-persist')
        args.append('activate')
        args.append(cleartext_device)
        proc = subprocess.Popen(
            args,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE
            )
        out, err = proc.communicate()
        out = unicode_to_utf8(out)
        err = unicode_to_utf8(err)
        if proc.returncode:
            raise tailsgreeter.errors.LivePersistError(
                _("live-persist failed with return code %(returncode)s:\n%(stdout)s\n%(stderr)s")
                % { 'returncode': proc.returncode, 'stdout': out, 'stderr': err }
                )
