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

URL = ''
hardware_id = ''
OS_NAME = 'ROSA'
DOMAIN = 'registrar'
LOCALE_DIR = '/usr/share/locale'
locale.bindtextdomain(DOMAIN, LOCALE_DIR)
locale.textdomain(DOMAIN)
ICON = '/usr/share/icons/file_transfer_section.svg'
CSS = '/usr/share/registrar/registrar.css'
if os.path.exists('./registrar.ui'):
    UI = './registrar.ui'
else:
    UI = '/usr/share/registrar/registrar.ui'

user_deny_chars= ",:;!*+()/#%&@\\"
email_deny_chars= ",:;!*+()/#%&\\"
config = None
cfg = {}

if os.path.exists('./registrar.ini'):
    config = './registrar.ini'
elif os.path.exists('/etc/registrar.ini'):
    config = '/etc/registrar.ini'

if config:
    cfg = configparser.ConfigParser()
    cfg.read(config)

if 'REGISTRAR' in cfg:
    if 'URL' in cfg['REGISTRAR']:
        URL = cfg['REGISTRAR']['URL']
    if 'HWID' in cfg['REGISTRAR']:
        if os.path.exists(cfg['REGISTRAR']['HWID']):
            try: 
                with open('/run/hwid', 'r') as fhw:
                    for line in fhw.readlines():
                        if len(line.strip()) == 32:
                            hardware_id = line.strip()
                            break
            except:
                hardware_id = None
   
def status_request():
    retdict = {}
    try:
        echo(_("Send request..."))
        response = requests.get(URL + 'status.py', 
                    params=[ ( 'machine_id', machine_id ),
                             ( 'locale', os.getenv('LANG')),
                             ( 'counter', 0 ) ] )
        code = response.status_code
    except:
        code = 'unknown'
    if code == 200:
        retdict['status'] = 'unknown'
        for a in response.text.split('\n'):
            print(a)
            if a.startswith('<') or not a.strip():
                continue
            retdict[a.split(':')[0]] = a.split(':')[1]
        if 'exitcode' in retdict.keys() and retdict['exitcode'] == str(100):
            window.set_title(_('You are using a registered OS'))
        if 'support' in retdict.keys() and retdict['support'] != 'None':
            support_time = time.strftime("%d.%m.%Y, %H:%M:%S", time.localtime(float(retdict['support'])) )
            message (_('Registration status'), retdict['status'] + '\n' + _("Support ends in: ") + support_time)
        else:
            message (_('Registration status'), retdict['status'] + '\n' + _("Support not paid"))
        echo(_("OK!"))
    else: 
        message(_('registrar'), _('Server error:') + str(code), 'error')
        echo(_('Server error:') + str(code), 'red')

def confirm_request(pin):
    retdict = {}
    try:
        echo(_("Send request..."))
        response = requests.get(URL + 'checkpin.py', 
                    params=[( 'pin', pin   ),
                            ( 'locale', os.getenv('LANG')),
                            ( 'machine_id', machine_id ) ] )
        code = response.status_code
    except:
        code = 'unknown'
    if code == 200:
        for a in response.text.split('\n'):
            if a.startswith('<') or not a.strip():
                continue
            retdict[a.split(':')[0]] = a.split(':')[1]
        if 'exitcode' in retdict.keys() and retdict['exitcode'] == str(100):
            window.set_title(_('You are using a registered OS'))
            header_label.set_text(_('Thank you for registering!'))
            message (_('Status'), retdict['status'])
            os.execl('/usr/libexec/genform', 'genform', "not_exec_regisrar")
        elif 'status' in retdict.keys():
            message(_('registrar'), retdict['status'], 'error')
    else: 
        message(_('registrar'), _('Server error:') + str(code), 'error')
        echo(_('Server error:') + str(code), 'red')

def request(name, email, sendhw, product_id):
    echo(_("Prepare request..."))
    email_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("default"))
    name_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("default"))
    if not check_name(name):
        name_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("red"))
        return False
    if not check_email(email):
        email_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("red"))
        return False
    hwprobe_id = None
    if sendhw:
        hwprobe_id = hwprobe()
    retdict = {}
    try:
        echo(_("Send request..."))
        response = requests.get(URL + 'getreg.py', 
                    params=[( 'name', name   ),
                            ( 'email', email ),
                            ( 'machine_id', machine_id ),
                            ( 'hwprobe_id', hwprobe_id ),
                            ( 'locale', os.getenv('LANG')),
                            ( 'os_release', os_release ),
                            ( 'hardware_id', product_id ),
                            ])
        code = response.status_code
    except:
        code = 'unknown'
    if code == 200:
        for a in response.text.split('\n'):
            if a.startswith('<') or not a.strip():
                continue
            retdict[a.split(':')[0]] = a.split(':')[1]
        if 'status' in retdict.keys(): 
            if retdict['exitcode'] == '100':
                echo(_('Request successfull!'))
                message(_('registrar'), _('Request successfull!') + '\n'
                + _('User name: ') + str(name) + '\n'
                + _('Email: ') + str(email) + '\n'
                + _('Hw-probe ID: ') + str(hwprobe_id) + '\n'
                + _("What's next...") + '\n'
                + _('Wait for instructions at your email address: ') + str(email) + '\n'
                + _('If the message did not arrive within twenty minutes, start the registrar and try the request again.'))
                pincode = get_pin(_("Confirm registration"), _("enter code from email"))
                if pincode:
                    confirm_request(pincode)
                else:
                    message(_("How to confirm later"),_('Run registrar, file --> confirm registration') )
                Gtk.main_quit()
                return False
            else:
                message(_('registrar'), _('Server error: ') + retdict['status'])
                echo(_('Server error: ') + retdict['status'] + ' - ' + retdict['exitcode'], 'red')
            return False
    elif code == 404:
        code = _('Page not found: ') + URL
    message(_('registrar'), _('Failed to upload data, error code:') + str(code), 'error')
    echo(_('Server error:') + str(code), 'red')
    return False
      
def refresh():
    while Gtk.events_pending():
        Gtk.main_iteration_do(True)
    return True
    
def echo(arg, colour='default'):
    context_id = statusbar.get_context_id('registrar')
    statusbar.push(context_id, str(arg))
    statusbar.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse(colour))
    refresh()
    time.sleep(0.3)

def agreement():
    message(_('Personal data processing policy'),
        _(
'''Your data that we store:
- e-mail
- specified name (not real full name)
- machine-id
- os-release
- hardware probe (if sent)
- ID tied to hardware or OS serial number
- registration time
- end date of paid support
- type of support (standard, extended)
- OS boot counter
- time of the last operation of the counter
- change log'''
), 'info')

def hwprobe():
    echo(_("Prepare hw-probe..."))
    URL = None
    with subprocess.Popen([ 'hw-probe', '-all', '-upload' ], stdout=subprocess.PIPE) as hw:
      lines = hw.stdout.readlines()
      ID = None
      for line in lines:
          if line.decode('utf-8').startswith('Probe URL'):
              URL = line.decode('utf-8').replace('Probe URL:', '').strip()
              echo(_("Complete!"), 'green')
    return URL

def check_name(name):
    echo(_("Check name..."))
    if len(name) >= 100 or len(name) < 4:
        echo(_('User name length must be between 3 and 100 characters'), 'red')
        return False
    for char in user_deny_chars:
        if char in name:
            echo(_('Characters: ') + user_deny_chars + _(' are not allowed in users names'), 'red')
            return False
    name_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("green"))
    echo(_("OK!"), 'green')
    return True

def check_id(ID):
    echo(_("Check ID..."))
    if len(ID) >= 32 or len(ID) < 10:
        echo(_('ID length must be between 10 and 32 characters'), 'red')
        return False
    for char in user_deny_chars + ' ':
        if char in ID:
            echo(_('Characters: ') + user_deny_chars + _(' are not allowed in ID'), 'red')
            return False
    id_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("green"))
    echo(_("OK!"), 'green')
    return True

def check_hwprobe():
    if os.path.exists('/usr/bin/hw-probe'):
        return True
    return False

def check_email(email):
    echo(_("Check email..."))
    if len(email) >= 100 or len(email) < 6:
        echo(_('Email length must be between 5 and 100 characters'), 'red')
        return False
    for char in email_deny_chars:
        if char in email:
            echo(_('Characters: ') + email_deny_chars + _(' are not allowed in email address'), 'red')
            return False
    try:
        is_valid = validate_email(email, check_mx=True)
        if is_valid == None:
            echo(_('Second attempt'))
            is_valid = validate_email(email)
        if not is_valid:
            echo(_('Email address failed validation!'), 'red')
            return False
    except:
        message( _('registrar'), _('Cannot validate email address:') + '\n'
        + email + '\n' 
        + _('please check network') , 
        'error' )
        return  False
    email_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("green"))
    echo(_("OK!"), 'green')
    return True

def message( first, second, mtype='info'):
    if mtype == 'info':
        mtype = Gtk.MessageType.INFO
    elif mtype == 'error':
        mtype = Gtk.MessageType.ERROR
    messagedialog = Gtk.MessageDialog(transient_for=window,
						destroy_with_parent=True,
						modal=True,
						message_type=mtype,
						buttons=Gtk.ButtonsType.OK,
						text=first)
    messagedialog.format_secondary_text(second)
    response = messagedialog.run()
    if response == Gtk.ResponseType.OK or response == Gtk.ResponseType.DELETE_EVENT:
        messagedialog.destroy()

def ask( first, second):
    messagedialog = Gtk.MessageDialog(transient_for=window,
						destroy_with_parent=True,
						modal=True,
						message_type=Gtk.MessageType.INFO,
						buttons=Gtk.ButtonsType.OK_CANCEL,
						text=first)
    messagedialog.format_secondary_text(second)
    response = messagedialog.run()
    if response == Gtk.ResponseType.OK:
        messagedialog.destroy()
        return True
    if response == Gtk.ResponseType.CANCEL:
        messagedialog.destroy()
    return False
    

def show_IDs():
    IDs = 'machine-id: %s\nhardware-id: %s\nRosa-ID: %s' % (str(machine_id or _('No data')), str(hardware_id or _('No data')), _('No data'))
    clipboard.set_text(IDs, -1)
    message(_('Copied to clipboard'), IDs)

def get_pin(first, second):
    askdialog = Gtk.MessageDialog(transient_for=window,
                          modal=True,
                          destroy_with_parent=True,
                          message_type=Gtk.MessageType.QUESTION,
                          buttons=Gtk.ButtonsType.OK_CANCEL,
                          text = first)
    askdialog.format_secondary_text(second)
    dialogBox = askdialog.get_content_area()
    pinEntry = Gtk.Entry()
    pinEntry.set_visibility(True)
    pinEntry.set_size_request(50,0)
    dialogBox.pack_end(pinEntry, False, False, 0)
    askdialog.show_all()
    response = askdialog.run()
    text = pinEntry.get_text() 
    askdialog.destroy()
    if (response == Gtk.ResponseType.OK) and (text != ''):
        return text
    else:
        return None
    
def about():
    with subprocess.Popen([ 'rpm', '-q', '--info', 'registrar' ], stdout=subprocess.PIPE) as info:
      lines = info.stdout.readlines()
      text = ''
      for line in lines:
          string = line.decode('utf-8').strip()
          if string:
              text += string + '\n'
    return text
   
class Handler:
    def __init__(self):
        email_entry.set_placeholder_text('ivanov@mail.ru')
        name_entry.set_placeholder_text('Ivan Ivanych')
        header_label.set_text(_('For full user experience, information about updates and special offers from the company,' + '\n' 
        + 'as well as the opportunity to purchase technical support, we offer to register!'))
        echo(_(" "))
        if hardware_id:
            id_entry.set_text(hardware_id)
            id_entry.set_editable(False)
                
    def on_cancel_button_clicked(self, button):                
        Gtk.main_quit()
        
    def on_send_button_clicked(self, button):
        email = email_entry.get_text()
        name = name_entry.get_text()
        sendhw = hwprobe_chck.get_active()
        product_id = id_entry.get_text()
        if ask(_('Agreement'), _('By submitting the form, you agree to the personal data processing policy (details: Menu - > agreement)') ):
            request(name, email, sendhw, product_id)

    def on_menu_confirm_activate(self, item):
        echo('confirm registration')
        pin = get_pin(_("Confirm registration"), _("enter code from email"))
        confirm_request(pin)

    def on_menu_status_activate(self, item):
        echo(_('get registration status'))
        status_request()

    def on_menu_IDs_activate(self, item):
        echo(_('show identifiers'))
        show_IDs()
   
    def on_menu_exit_activate(self, item):
        Gtk.main_quit()

    def on_menu_info_activate(self, item):
        text = about()
        message(_('registrar'), about() + '\n'
        + _('Support email address: support@rosalinux.ru')
        , 'info')

    def on_menu_pay_activate(self, item):
        subprocess.call(['/usr/libexec/genform',  'not_exec_registrar'])
        
    def on_menu_agreement_activate(self, item):
        agreement()
        
    def on_name_entry_activate(self, entry):
        if not check_name(name_entry.get_text()):
            name_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("red"))
    def on_name_entry_backspace(self, entry):
        name_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("default"))
        statusbar.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("default"))
    def on_name_entry_move_cursor(self, *args):
        self.on_name_entry_backspace('qqq')
    def on_name_entry_insert_at_cursor(self, *args):
        self.on_name_entry_backspace('qqq')
    def on_name_entry_toggle_override(self, *args):
        self.on_name_entry_backspace('qqq')

    def on_id_entry_activate(self, entry):
        if not check_id(id_entry.get_text()):
            name_id.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("red"))
    def on_id_entry_backspace(self, entry):
        id_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("default"))
        statusbar.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("default"))
    def on_id_entry_move_cursor(self, *args):
        self.on_id_entry_backspace('qqq')
    def on_id_entry_insert_at_cursor(self, *args):
        self.on_id_entry_backspace('qqq')
    def on_id_entry_toggle_override(self, *args):
        self.on_id_entry_backspace('qqq')

    def on_email_entry_activate(self, entry):
        if not check_email(email_entry.get_text()):
            email_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("red"))
    def on_email_entry_backspace(self, entry):
        email_entry.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("default"))
        statusbar.modify_fg(Gtk.StateFlags.NORMAL, Gdk.color_parse("default"))
    def on_email_entry_move_cursor(self, *args):
        self.on_email_entry_backspace('qqq')
    def on_email_entry_insert_at_cursor(self, *args):
        self.on_email_entry_backspace('qqq')
    def on_email_entry_toggle_override(self, *args):
        self.on_email_entry_backspace('qqq')

    def on_hwprobe_checkbutton_toggled(self, entry):
        if not check_hwprobe():
            hwprobe_chck.set_sensitive(False)
            hwprobe_chck.set_active(False)
            hwprobe_label.set_text(_('hw-probe util not found'))
            echo(_('Hw-probe util not found'), 'red')
            
try: 
    with open('/etc/machine-id', 'r') as fmachine:
        for line in fmachine.readlines():
            if len(line.strip()) == 32:
                machine_id = line.strip()
except:
    print('cannot get machine_id')
    quit()

try: 
    with open('/etc/os-release', 'r') as osrelease:
        for line in osrelease.readlines():
            if line.startswith('NAME'):
                os_release = line.strip() + ':'
                OS_NAME = line.strip().split('=')[1]
                break 
except:
    os_release = 'NAME=unknown:'

try: 
    with open('/var/lib/rosa-iso-info', 'r') as osrelease:
        for line in osrelease.readlines():
                os_release += line.strip() + ':'
except:
    os_release += 'not_found'

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

name_entry = builder.get_object('name_entry')
email_entry = builder.get_object('email_entry') 
id_entry = builder.get_object('id_entry')
send_button = builder.get_object('send_button')
clear_button = builder.get_object('clear_button')
hwprobe_label = builder.get_object('hwprobe_label')
hwprobe_chck = builder.get_object('hwprobe_checkbutton')
header_label = builder.get_object('header_label')
statusbar = builder.get_object('status_bar')

window = builder.get_object('main_window')
window.set_icon_from_file(ICON)
window.connect("destroy", Gtk.main_quit)
window.set_title(OS_NAME + _(' registrating'))
window.show_all()
builder.connect_signals(Handler())
clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)

# Подключение CSS
if os.path.exists(CSS):
  css_provider = Gtk.CssProvider()
  css_provider.load_from_path(CSS)
  Gtk.StyleContext.add_provider_for_screen(
    Gdk.Screen.get_default(),
    css_provider,
    Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
  )

Gtk.main()

