#!/usr/bin/python3
import gi, signal, locale,  subprocess, os
from locale import gettext as _
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk

os.environ["XDG_RUNTIME_DIR"] = "/root"

APP = 'barium-luks-manager'
UI = '/usr/share/rosa-rw/luks-manager/luks-manager.ui'
ICON = '/usr/share/icons/rosa.svg'
MLIB = '/usr/libexec/luks-manager.lib'
LOCALE_DIR = '/usr/share/locale'

#local tests block #####################################
if os.path.isfile('./luks-manager.ui'):
  UI = './luks-manager.ui'
  MLIB = './luks-manager.lib'
  ICON = './rosa.svg'
  LOCALE_DIR='./locale'
#########################################################

locale.bindtextdomain(APP, LOCALE_DIR)
locale.textdomain(APP)

class HandlerUi:
  def __init__(self):
    partitions = get_luks()
    if partitions:
      partSelector.remove_all()
      n = 0
      for part in partitions:
        partSelector.insert(n, part[0], f'{part[1]} ({part[0]})')
        n += 1
        partSelector.set_active_id(part[0])
        slotsNumber.set_text(get_slots(part[0]))
    window.show_all()
    if not check_tpm2():
      radio_tpm2.hide()
    if not check_token():
      radio_token.hide()
    show_hide()
    
  def on_btn_submit_clicked(self, *args):
    partition = partSelector.get_active_id()
    action = actSelector.get_active_id()
    passwd = entry_pass.get_text()
    pin =  entry_pin.get_text()
    for a in radio_list:
      if a.get_active():
        way = (a.get_name())
    print(way, action, partition, pin)
    run(way, action, partition, passwd, pin)

  def on_btn_cancel_clicked(self, button):
    Gtk.main_quit()
    
  def on_cbox_partitions_changed(self, *args):
    show_hide()
  def on_cbox_actions_changed(self, *args):
    window.show_all()
    if not check_tpm2():
      radio_tpm2.hide()
    if not check_token():
      radio_token.hide()
    show_hide()
  def on_radio_lspci_toggled(self, *args):
    show_hide()
  def on_radio_uird_toggled(self, *args):
    show_hide()
  def on_radio_token_toggled(self, *args):
    show_hide()
  def on_radio_tpm2_toggled(self, *args):
    show_hide()
    
def get_luks():
  partitions = []
  luksopend = []
  with subprocess.Popen([ 'ls -1 /dev/mapper' ], stdout=subprocess.PIPE, shell=True) as mapper:
    for line in mapper.stdout:
      line = line.rstrip().decode('UTF-8')
      luksopend.append('/dev/' + line)
  #remove me
  luksopend = [ '/dev/sda3', '/dev/sdb3' ]
  with subprocess.Popen([ 'blkid -t TYPE=crypto_LUKS -s LABEL -o device' ], stdout=subprocess.PIPE, shell=True) as blkid:
    for line in blkid.stdout:
      line = line.rstrip().decode('UTF-8')
      if line in luksopend:
          partlabel = get_label(line)
          partitions.append( [line, partlabel])
  return partitions

def get_label(part):
  with subprocess.Popen([ 'blkid -s LABEL -o value ' + part ], stdout=subprocess.PIPE, shell=True) as label:
    partlabel = label.stdout.readlines()[0].rstrip().decode('UTF-8')
  return partlabel
  
def get_slots(part):
  with subprocess.Popen([ MLIB + ' getSlots ' + part ], stdout=subprocess.PIPE, shell=True) as label:
    N = label.stdout.readlines()[0].rstrip().decode('UTF-8')
  return N

def check_tpm2():
  return os.path.exists('/dev/tpmrm0')

def check_token():
  with subprocess.Popen([ MLIB + ' token tokenlib'], stdout=subprocess.PIPE, shell=True) as label:
    try:
      lib = label.stdout.readlines()[0].rstrip().decode('UTF-8')
      return os.path.exists(lib)
    except:
      return False

def show_hide():
  part = partSelector.get_active_id()
  if part:
    slotsNumber.set_text(get_slots(part))
    if get_label(part) == 'ROSA-SYSTEM':
      radio_uird.show()
    else:
      radio_uird.hide()
    action = actSelector.get_active_id()
    for a in radio_list:
      if a.get_active():
        way = (a.get_name())
    if action == 'rmAll':
      label_pass.show()
      entry_pass.show()
      label_pin.hide()
      entry_pin.hide()
      for a in radio_list:
        a.hide()
    elif way == 'lspci' or way == 'tpm2' or way == 'uird':
      if action == 'addKey':
        label_pass.show()
        entry_pass.show()
        label_pin.hide()
        entry_pin.hide()
      elif action == 'rmKey':
        label_pass.hide()
        entry_pass.hide()
        label_pin.hide()
        entry_pin.hide()
    elif way == 'token':
      if action == 'addKey':
        label_pass.show()
        entry_pass.show()
        label_pin.show()
        entry_pin.show()
      if action == 'rmKey':
        label_pass.hide()
        entry_pass.hide()
        label_pin.show()
        entry_pin.show()
  else:
    label_pass.hide()
    entry_pass.hide()
    label_pin.hide()
    entry_pin.hide()
    for a in radio_list:
      a.hide()
          
def run(way, action, partition, passwd=None, pin=None):
  if action == 'rmAll':
    if not passwd:
      info(_('Warning!'), _("Need existing LUKS password for: ") + partition)
      return False
    runit( f'{MLIB} {action} {passwd} {partition}')
  elif way == 'lspci' or way == 'tpm2' or way == 'uird':
    if action == 'addKey':
      if not passwd:
        info(_('Warning!'), _("Need existing LUKS password for: ") + partition)
        return False
      runit( f'{MLIB} {way} {action} {passwd} {partition}' )
    elif action == 'rmKey':
      runit( f'{MLIB} {way} {action} placeholder {partition}' )
  elif way == 'token':
    if action == 'addKey':
      if not passwd:
        info( _('Warning!'), _("Need existing LUKS password for: ") + partition)
        return False
      elif not pin:
        info(_('Warning!'), _("Need pin code for token") )
        return False
      runit( f'{MLIB} {way} {action} {passwd} {partition} {pin}' )
    elif action == 'rmKey':
      if not pin:
        info(_('Warning!'), _("Need pin code for token"))
        return False
      runit( f'{MLIB} {way} {action} placeholder {partition} {pin}' )


def runit(cmd):
  print(cmd)
  proc_stderr = ''
  with subprocess.Popen([cmd], stderr=subprocess.PIPE, shell=True) as proc:
    for line in proc.stderr:
      decoded_line = line.rstrip().decode('UTF-8')
      if decoded_line:
        proc_stderr += decoded_line + '\n'
    ret = proc.wait()
    if ret != 0:
      info(_('Error!'), proc_stderr)
      return False
    info(_('Saccesfull'), _('Task complete'))
    Gtk.main_quit()

def info(header, text):
    parent = builder.get_object('window_main')
    messageinfo = Gtk.MessageDialog(transient_for=parent,
					destroy_with_parent=True,
					modal=True,
					message_type=Gtk.MessageType.WARNING,
					buttons=Gtk.ButtonsType.OK,
					text=header)
    messageinfo.format_secondary_text(text)
    messageinfo.run()
    messageinfo.destroy()

if __name__ == '__main__':

  signal.signal(signal.SIGINT, signal.SIG_DFL)
  builder = Gtk.Builder()
  builder.set_translation_domain(APP)
  builder.add_from_file(UI)

  partSelector = builder.get_object("cbox_partitions")
  actSelector = builder.get_object("cbox_actions")
  slotsNumber = builder.get_object("label_slots_namber")
  radio_uird = builder.get_object("radio_uird")
  radio_token = builder.get_object("radio_token")
  radio_tpm2 = builder.get_object("radio_tpm2")
  radio_lspci = builder.get_object("radio_lspci")
  radio_list = radio_lspci.get_group()

  label_pass = builder.get_object("label_pass")
  label_pin = builder.get_object("label_pin")
  entry_pass = builder.get_object("entry_pass")
  entry_pin = builder.get_object("entry_pin")

  window = builder.get_object('window_main')
  window.connect("destroy", Gtk.main_quit)
  window.show_all()

  builder.connect_signals(HandlerUi())
  Gtk.main()


