#!/usr/bin/python3 -su

## Copyright (C) 2018 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

import sys
import signal

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor, QTextCursor
from PyQt5.QtWidgets import *

from subprocess import call, Popen, PIPE

import os
import re
import glob
import tempfile

from . import tor_status, tor_bootstrap, torrc_gen, info


class TorControlPanel(QDialog):
    def __init__(self):
        super(TorControlPanel, self).__init__()

        ## Make sure torrc exists.
        command = 'leaprun tor-config-sane'
        call(command, shell=True)

        self.setMinimumSize(650, 465)

        icons_path = '/usr/share/tor-control-panel/'
        self.refresh_icon = QtGui.QIcon(icons_path + 'refresh.png')
        self.exit_icon = QtGui.QIcon(icons_path + 'Exit.png')

        self.restart_icon = QtGui.QIcon(icons_path + 'restart.png')
        self.stop_icon = QtGui.QIcon(icons_path + 'stop.png')
        self.tool_icon = QtGui.QIcon(icons_path + 'tools.png')
        self.info_icon = QtGui.QIcon(icons_path + 'help.png')
        self.back_icon = QtGui.QIcon(icons_path + 'prev.png')
        self.accept_icon = QtGui.QIcon(icons_path + 'accept_icon.png')
        self.onions_icon = QtGui.QIcon(icons_path + 'onion.png')
        self.newid_icon = QtGui.QIcon(icons_path + 'newnym.png')

        self.tor_status_color = ['green', '#AF0000', '#AF0000', 'orange',
                                 'orange', '#AF0000']
        self.tor_status_list = ['running', 'stopped', 'disabled',
                                'disabled-running', 'acquiring', 'no_controller']

        self.message = ''
        self.tor_message = info.tor_stopped()
        self.tor_running_path = '/run/tor/tor.pid'
        self.torrc_file_path = '/usr/local/etc/torrc.d/40_tor_control_panel.conf'

        self.button_name = ['systemd &journal', 'Tor &log', '&torrc']

        self.journal_command = 'leaprun', 'tor-control-panel-read-tor-default-log'

        self.bridges = ['None',
                        'obfs4',
                        'snowflake',
                        'meek',
                        'Custom bridges']

        self.default_bridges = ['None',
                                'obfs4',
                                'snowflake',
                                'meek']

        self.proxies = ['None',
                        'HTTP / HTTPS',
                        'SOCKS4',
                        'SOCKS5']

        self.use_default_bridges = False
        self.use_custom_bridges = False
        self.use_proxy = False

        self.tor_log = '/run/tor/log'

        self.tor_log_tempfile = tempfile.NamedTemporaryFile()
        self.tor_log_html = self.tor_log_tempfile.name

        # tor log HTML style
        self.warn_style = '<span style="background-color:yellow">{}' \
            .format('[warn]')
        self.error_style = '<span style="background-color:red">{}' \
            .format('[error]')

        # Has to be declared here to make the messagebox modal.
        # See lines 502 and 624.
        self.valid_custom_bridges = QMessageBox(QMessageBox.Warning, 'Warning',
                                                    info.invalid_custom_bridges(), QMessageBox.Ok)

        self.valid_proxy = QMessageBox(QMessageBox.Warning, 'Warning',
                                    info.invalid_ip_port(), QMessageBox.Ok)

        self.bootstrap_done = True

        self.tabs = QTabWidget()
        self.tab1 = QWidget()
        self.tab2 = QWidget()
        self.tab3 = QWidget()

        self.button_layout = QHBoxLayout()
        self.quit_button = QPushButton(self.exit_icon, ' Exit')
        self.quit_button.clicked.connect(self.quit)

        self.button_box = QFrame()
        self.button_layout.addWidget(self.quit_button)
        self.button_layout.setAlignment(Qt.AlignRight)

        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.tabs)
        self.layout.addLayout(self.button_layout)
        self.setLayout(self.layout)

        self.tab1_layout = QVBoxLayout(self.tab1)
        self.info_frame = QFrame()
        self.frame_layout = QGridLayout(self.info_frame)
        self.frame_layout.setAlignment(Qt.AlignTop)

        self.status = QPushButton()
        self.status.setEnabled(False)
        self.frame_layout.addWidget(self.status, 1, 0, 1, 1)
        self.tor_message_browser = QTextBrowser()
        self.frame_layout.addWidget(self.tor_message_browser, 1, 1, 2, 1)
        self.bootstrap_progress = QtWidgets.QProgressBar()
        self.frame_layout.addWidget(self.bootstrap_progress, 2, 1, 1, 1)

        self.user_frame = QFrame()
        self.user_layout = QHBoxLayout(self.user_frame)
        self.config_frame = QGroupBox()

        self.bridges_label = QLabel()
        self.bridge_type = QLabel()
        self.bridges_combo = QComboBox()
        for bridge in self.bridges:
            self.bridges_combo.addItem(bridge)
        self.bridges_combo.insertSeparator(1)
        self.bridges_combo.insertSeparator(7)
        self.bridges_combo.addItem('Disable network')
        self.bridge_info_button = QPushButton(self.info_icon, '')
        self.bridge_info_button.clicked.connect(info.show_help_censorship)

        self.proxy_label = QLabel()
        self.proxy_type = QLabel()
        self.proxy_combo = QComboBox()
        for proxy in self.proxies:
            self.proxy_combo.addItem(proxy)
        self.proxy_combo.insertSeparator(1)
        self.proxy_combo.currentIndexChanged.connect(
            lambda: self.proxy_settings_show(self.proxy_combo.currentText()))

        self.proxy_info_button = QPushButton(self.info_icon, '')
        self.proxy_info_button.clicked.connect(info.show_proxy_help)

        self.config_frame_layout = QGridLayout()
        self.config_frame_layout.addWidget(self.bridges_label, 1, 0)
        self.config_frame_layout.addWidget(self.bridge_type, 1, 1)
        self.config_frame_layout.addWidget(self.bridges_combo, 1, 1)
        self.config_frame_layout.addWidget(self.bridge_info_button, 1, 2)
        self.config_frame_layout.addWidget(self.proxy_label, 2, 0)
        self.config_frame_layout.addWidget(self.proxy_type, 2, 1)
        self.config_frame_layout.addWidget(self.proxy_combo, 2, 1)
        self.config_frame_layout.addWidget(self.proxy_info_button, 2, 2)
        self.config_frame_layout.setAlignment(Qt.AlignTop)
        self.config_frame_layout.setVerticalSpacing(6)

        self.proxy_ip_label = QLabel()
        self.proxy_ip_edit = QLineEdit()
        self.proxy_port_label = QLabel()
        self.proxy_port_edit = QLineEdit()

        self.proxy_user_label = QLabel()
        self.proxy_user_edit = QLineEdit()
        self.proxy_pwd_label = QLabel()
        self.proxy_pwd_edit = QLineEdit()

        self.prev_button = QPushButton(self.back_icon, '')
        self.prev_button.clicked.connect(self.exit_configuration)

        self.proxy_settings_layout = QGridLayout()  #(self.proxy_frame)
        self.proxy_settings_layout.addWidget(self.proxy_ip_label, 1, 0)
        self.proxy_settings_layout.addWidget(self.proxy_ip_edit, 1, 1)
        self.proxy_settings_layout.addWidget(self.proxy_port_label, 1, 2)
        self.proxy_settings_layout.addWidget(self.proxy_port_edit, 1, 3)
        self.proxy_settings_layout.addWidget(self.proxy_user_label, 2, 0)
        self.proxy_settings_layout.addWidget(self.proxy_user_edit, 2, 1)
        self.proxy_settings_layout.addWidget(self.proxy_pwd_label, 2, 2)
        self.proxy_settings_layout.addWidget(self.proxy_pwd_edit, 2, 3)
        self.proxy_settings_layout.addWidget(self.prev_button, 2, 4)
        self.proxy_settings_layout.setAlignment(Qt.AlignRight)

        self.config_layout = QVBoxLayout(self.config_frame)
        self.config_layout.addLayout(self.config_frame_layout)
        self.config_layout.addLayout(self.proxy_settings_layout)

        self.user_layout.addWidget(self.config_frame)

        self.control_box = QGroupBox()
        self.restart_button = QPushButton(self.restart_icon, ' Restart Tor',
                                          self.control_box)
        self.stop_button = QPushButton(self.stop_icon, ' Stop Tor',
                                       self.control_box)
        self.stop_button.clicked.connect(self.stop_tor)
        self.configure_button = QPushButton(self.tool_icon, ' Configure',
                                            self.control_box)

        self.restart_button.clicked.connect(self.restart_tor)
        self.stop_button.clicked.connect(self.stop_tor)
        self.configure_button.clicked.connect(self.configure)

        self.user_layout.addWidget(self.control_box)

        self.tab1_layout.addWidget(self.info_frame)
        self.tab1_layout.addWidget(self.user_frame)

        self.tab2_layout = QVBoxLayout(self.tab2)
        self.view_layout = QHBoxLayout()
        self.view_layout.setAlignment(Qt.AlignBottom)

        self.view_frame = QFrame()
        self.view_frame.setMinimumHeight(70)
        self.files_box = QGroupBox(self.view_frame)
        self.refresh_button = QPushButton(self.refresh_icon, ' Refresh')
        self.view_layout.setAlignment(Qt.AlignTop)
        self.view_layout.addWidget(self.view_frame)
        self.view_layout.addWidget(self.refresh_button)

        self.files_box_layout = QGridLayout(self.files_box)
        self.torrc_button = QRadioButton(self.files_box)
        self.log_button = QRadioButton(self.files_box)
        self.journal_button = QRadioButton(self.files_box)
        self.files_box_layout.addWidget(self.torrc_button, 1, 0)
        self.files_box_layout.addWidget(self.log_button, 1, 1)
        self.files_box_layout.addWidget(self.journal_button, 2, 1)

        self.torrc_button.toggled.connect(self.refresh_logs)
        self.log_button.toggled.connect(self.refresh_logs)
        self.journal_button.toggled.connect(self.refresh_logs)
        self.refresh_button.clicked.connect(self.refresh_logs)

        self.file_browser = QTextBrowser()
        self.file_browser.setLineWrapMode(QTextBrowser.NoWrap)

        self.tab2_layout.addLayout(self.view_layout)
        self.tab2_layout.addWidget(self.file_browser)

        self.custom_bridges_frame = QFrame(self.tab1)
        self.custom_bridges_layout = QVBoxLayout(self.custom_bridges_frame)
        self.custom_bridges_help = QLabel(self.custom_bridges_frame)
        self.custom_bridges = QtWidgets.QTextEdit(self.custom_bridges_frame)
        self.custom_bridges_layout.addWidget(self.custom_bridges_help)
        self.custom_bridges_layout.addWidget(self.custom_bridges)
        self.custom_bridges.setLineWrapMode(QTextEdit.NoWrap)

        self.custom_buttons = QHBoxLayout(self.custom_bridges_frame)
        self.custom_cancel_button = QPushButton(QtGui.QIcon(
            self.back_icon), 'Cancel', self.custom_bridges_frame)
        self.custom_cancel_button.clicked.connect(self.hide_custom_bridges)
        self.custom_accept_button = QPushButton(QtGui.QIcon(
            self.accept_icon), 'Accept', self.custom_bridges_frame)
        self.custom_accept_button.clicked.connect(self.accept_custom_bridges)
        self.custom_buttons.addWidget(self.custom_cancel_button)
        self.custom_buttons.addWidget(self.custom_accept_button)
        self.custom_buttons.setAlignment(Qt.AlignRight)
        self.custom_bridges_layout.addLayout(self.custom_buttons)

        self.tab1_layout.addWidget(self.custom_bridges_frame)

        self.utils_layout = QtWidgets.QVBoxLayout(self.tab3)

        self.onioncircuits_box = QFrame()
        self.onions_layout = QVBoxLayout(self.onioncircuits_box)
        self.onioncircuits_button = QPushButton(self.onions_icon,
                                                ' Onion &Circuits')
        self.onioncircuits_button.clicked.connect(self.onioncircuits)
        self.onions_label = QLabel()
        self.onions_layout.addWidget(self.onioncircuits_button)
        self.onions_layout.addWidget(self.onions_label)

        self.newnym_box = QFrame()
        self.newnym_layout = QVBoxLayout(self.newnym_box)
        self.newnym_button = QPushButton(self.newid_icon, ' Request new Tor circuit ')
        self.newnym_button.clicked.connect(self.newnym)
        self.newnym_label = QLabel()
        self.newnym_layout.addWidget(self.newnym_button)
        self.newnym_layout.addWidget(self.newnym_label)
        self.dummy1 = QFrame()
        self.dummy2 = QFrame()

        self.utils_layout.addWidget(self.onioncircuits_box)
        self.utils_layout.addWidget(self.newnym_box)
        self.utils_layout.addWidget(self.dummy1)
        self.utils_layout.addWidget(self.dummy2)

        self.newnym_box.setFrameShape(QFrame.Panel | QFrame.Raised)
        self.onioncircuits_box.setFrameShape(QFrame.Panel | QFrame.Raised)

        self.setup_ui()

    def setup_ui(self):
        self.tabs.addTab(self.tab1, 'Control')
        self.tabs.addTab(self.tab3, 'Utilities')
        self.tabs.addTab(self.tab2, 'Logs')

        self.quit_button.setIconSize(QtCore.QSize(20, 20))

        self.status.setText('Tor status')

        self.tor_message_browser.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.tor_message_browser.setMinimumHeight(24)
        self.tor_message_browser.setStyleSheet('background-color:rgba(0, 0, 0, 0)')

        self.bootstrap_progress.setMaximumHeight(15)
        self.bootstrap_progress.setMinimum(0)
        self.bootstrap_progress.setMaximum(100)
        self.bootstrap_progress.hide()

        self.user_frame.setLineWidth(2)
        self.user_frame.setMaximumHeight(175)
        self.user_frame.setMinimumHeight(175)
        self.user_frame.setFrameShape(QFrame.Panel | QFrame.Raised)

        self.config_frame.setTitle('User configuration')

        self.bridges_label.setMaximumWidth(90)
        self.bridges_label.setText('Bridges type :')
        self.bridge_type.setStyleSheet('font:bold')
        self.bridge_type.setMinimumHeight(24)
        self.bridges_combo.hide()
        self.bridge_info_button.setMaximumWidth(20)
        self.bridge_info_button.setFlat(True)
        self.bridge_info_button.hide()
        self.bridge_info_button.setToolTip('Show bridges help')

        self.proxy_label.setText('Proxy type :')
        self.proxy_label.setMaximumWidth(90)
        self.proxy_type.setStyleSheet('font:bold')
        self.proxy_type.setMinimumHeight(24)
        self.proxy_combo.hide()
        self.proxy_info_button.setMaximumWidth(20)
        self.proxy_info_button.setFlat(True)
        self.proxy_info_button.hide()
        self.proxy_info_button.setToolTip('Show proxies help')

        self.proxy_ip_label.setText('Address:')
        self.proxy_ip_label.hide()
        self.proxy_ip_edit.setPlaceholderText('ex : 127.0.0.1')
        self.proxy_ip_edit.hide()
        self.proxy_ip_edit.setEnabled(False)

        self.proxy_port_label.setText('Port:')
        self.proxy_port_label.hide()
        self.proxy_port_edit.setPlaceholderText('1-65535')
        self.proxy_port_edit.hide()
        self.proxy_port_edit.setEnabled(False)

        self.proxy_user_label.setText('User: ')
        self.proxy_user_label.hide()
        self.proxy_user_edit.setPlaceholderText('Optional')
        self.proxy_user_edit.hide()
        self.proxy_user_edit.setEnabled(False)

        self.proxy_pwd_label.setText('Password: ')
        self.proxy_pwd_label.hide()
        self.proxy_pwd_edit.setPlaceholderText('Optional')
        self.proxy_pwd_edit.hide()
        self.proxy_pwd_edit.setEnabled(False)

        self.prev_button.setMaximumWidth(20)
        self.prev_button.setFlat(True)
        self.prev_button.hide()
        self.prev_button.setToolTip('Quit configuration')

        self.control_box.setMinimumWidth(140)
        self.control_box.setMaximumWidth(140)
        self.control_box.setTitle('Control')
        self.restart_button.setIconSize(QtCore.QSize(28, 28))
        self.restart_button.setFlat(True)
        self.restart_button.setGeometry(QtCore.QRect(10, 28, 113, 32))
        self.stop_button.setIconSize(QtCore.QSize(28, 28))
        self.stop_button.setFlat(True)
        self.stop_button.setGeometry(QtCore.QRect(10, 70, 96, 32))
        self.configure_button.setIconSize(QtCore.QSize(28, 28))
        self.configure_button.setFlat(True)
        self.configure_button.setGeometry(QtCore.QRect(10, 110, 102, 32))
        self.configure_button.setDefault(True)

        self.custom_bridges_frame.hide()
        self.custom_cancel_button.setFlat(True)
        self.custom_accept_button.setFlat(True)
        self.custom_bridges_help.setWordWrap(True)
        self.custom_bridges_help.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self.custom_bridges_help.setText(info.tcp_custom_bridges_help())

        self.newnym_box.setMaximumHeight(130)
        self.newnym_button.setMaximumWidth(175)
        self.newnym_button.setIconSize(QtCore.QSize(18, 18))
        self.newnym_label.setWordWrap(True)
        self.newnym_label.setTextFormat(Qt.RichText)
        self.newnym_label.setText(info.newnym_text())

        self.onioncircuits_box.setMaximumHeight(80)
        self.onioncircuits_button.setMaximumWidth(120)
        self.onioncircuits_button.setIconSize(QtCore.QSize(20, 20))
        self.onions_label.setWordWrap(True)
        self.onions_label.setText(info.onions_text())

        self.files_box_layout.setVerticalSpacing(0)
        self.files_box_layout.setHorizontalSpacing(20)
        self.files_box_layout.setContentsMargins(6, 0, 6, 0)
        self.files_box.setTitle('  Files            Logs')
        self.torrc_button.setText('&torrc')
        self.log_button.setText('Tor &log')
        self.journal_button.setText('systemd &journal')
        self.log_button.setChecked(True)

        self.refresh_button.setMaximumWidth(70)
        self.refresh_button.setFlat(True)

    def newnym(self):
        from stem import Signal
        from stem.control import Controller

        try:
            with Controller.from_socket_file('/run/tor/control') as controller:
                controller.authenticate()
                controller.signal(Signal.NEWNYM)
                self.restart_tor()

        except stem.UnsatisfiableRequest:
            print('signal NEWNYM  failed to be processed')

    def onioncircuits(self):
        command = 'onioncircuits &'
        call(command, shell=True)

    def update_bootstrap(self, bootstrap_phase, bootstrap_percent):
        self.bootstrap_progress.show()
        self.bootstrap_progress.setValue(bootstrap_percent)
        self.bootstrap_done = False

        if bootstrap_percent == 100:
            self.message = bootstrap_phase
            self.bootstrap_progress.hide()
            self.restart_button.setEnabled(True)
            self.stop_button.setEnabled(True)
            self.refresh(False)
            self.bootstrap_done = True
        else:
            self.message = bootstrap_phase
            self.tor_status = 'acquiring'
            self.refresh_status()

        if bootstrap_phase == 'no_controller':
            if hasattr(self, 'bootstrap_thread'):
                self.bootstrap_thread.terminate()
            self.tor_status = 'no_controller'
            self.message = info.no_controller()
            self.bootstrap_progress.hide()
            self.restart_button.setEnabled(True)
            self.stop_button.setEnabled(True)
            self.refresh_status()

        elif bootstrap_phase == 'socket_error':
            self.bootstrap_thread.terminate()
            self.message = info.socket_error()
            self.bootstrap_progress.hide()
            self.control_box.setEnabled(True)
            self.refresh_status()

        elif bootstrap_phase == 'cookie_authentication_failed':
            self.bootstrap_thread.terminate()
            self.message = info.cookie_error()
            self.bootstrap_progress.hide()
            self.control_box.setEnabled(True)
            self.refresh_status()

    def start_bootstrap(self):
        self.bootstrap_thread = tor_bootstrap.TorBootstrap(self)
        self.bootstrap_thread.signal.connect(self.update_bootstrap)
        self.bootstrap_thread.start()

    def hide_custom_bridges(self):
        self.status.show()
        self.tor_message_browser.show()
        self.user_frame.show()
        self.custom_bridges_frame.hide()
        self.exit_configuration()

    def check_valid_custom_bridges(self):
        bridges = self.custom_bridges.toPlainText()
        return (bridges.startswith('obfs4')
                or (('.' in bridges) and (':' in bridges)))

    def accept_custom_bridges(self):
        if not self.check_valid_custom_bridges():
             self.valid_custom_bridges.setWindowModality(QtCore.Qt.WindowModal)
             self.valid_custom_bridges.exec_()
             return

        else:
            self.hide_custom_bridges()
            self.set_torrc()

    def valid_ip(self, address):
        import socket
        try:
            socket.gethostbyname(address)
            return True
        except socket.error:
            return False

    def valid_port(self, port):
        try:
            if 1 <= int(port) <= 65535:
                return True
            else:
                return False
        except (ValueError, TypeError):
            return False

    def check_valid_proxy_settings(self):
        return (self.valid_ip(self.proxy_ip_edit.text()) and
                self.valid_port(self.proxy_port_edit.text()))

    def proxy_settings_show(self, proxy):
        if proxy == 'None':
            self.proxy_ip_label.hide()
            self.proxy_ip_edit.hide()
            self.proxy_port_label.hide()
            self.proxy_port_edit.hide()
            self.proxy_user_label.hide()
            self.proxy_user_edit.hide()
            self.proxy_pwd_label.hide()
            self.proxy_pwd_edit.hide()
        elif not proxy == 'None':
            self.proxy_ip_label.show()
            self.proxy_ip_edit.show()
            self.proxy_port_label.show()
            self.proxy_port_edit.show()
            self.proxy_user_label.show()
            self.proxy_user_edit.show()
            self.proxy_pwd_label.show()
            self.proxy_pwd_edit.show()
            enable_auth = not proxy == 'SOCKS4' and 'Accept' in \
                          self.configure_button.text()
            self.proxy_user_edit.setEnabled(enable_auth)
            self.proxy_pwd_edit.setEnabled(enable_auth)

    def configure(self):
        if 'Configure' in self.configure_button.text():
            self.configure_button.setText(' Accept    ')
            self.configure_button.setIcon(self.accept_icon)
            self.restart_button.setEnabled(False)
            self.stop_button.setEnabled(False)
            self.bridges_combo.show()
            self.proxy_combo.show()
            self.proxy_ip_edit.setEnabled(True)
            self.proxy_port_edit.setEnabled(True)
            self.proxy_user_edit.setEnabled(True)
            self.proxy_pwd_edit.setEnabled(True)
            self.proxy_settings_show(self.proxy_combo.currentText())
            self.bridge_info_button.show()
            self.proxy_info_button.show()
            self.prev_button.show()

            bridge = self.bridge_type.text()
            index = self.bridges_combo.findText(bridge, QtCore.Qt.MatchFixedString)
            self.bridges_combo.setCurrentIndex(index)

            proxy = self.proxy_type.text()
            index = self.proxy_combo.findText(proxy, QtCore.Qt.MatchFixedString)
            self.proxy_combo.setCurrentIndex(index)
            self.proxy_settings_show(proxy)

        elif 'Accept' in self.configure_button.text():
            bridge = self.bridges_combo.currentText()
            if self.bridges_combo.currentText() in self.default_bridges:
                self.use_default_bridges = True
                self.use_custom_bridges = False

            elif self.bridges_combo.currentText() == 'Custom bridges':
                self.status.hide()
                self.tor_message_browser.hide()
                self.user_frame.hide()

                ## Retrieve custom bridges
                if os.path.exists(self.torrc_file_path):
                    with open(self.torrc_file_path, 'r') as f:
                        if '# Custom' in f.read():
                            self.custom_bridges.clear()
                            f.seek(0)
                            lines = f.readlines()
                            for line in lines:
                                if line.startswith('Bridge'):
                                    line = line.strip('Bridge' '\n')
                                    self.custom_bridges.append(line)
                    f.close()
                    self.custom_bridges.moveCursor(QtGui.QTextCursor.Start)

                self.custom_bridges_frame.show()
                self.use_custom_bridges = True
                self.use_default_bridges = False

            elif self.bridges_combo.currentText() == 'Disable network':
                tor_status.set_disabled()
                self.exit_configuration()

            elif self.bridges_combo.currentText() == 'Enable network':
                tor_status.set_enabled()
                self.restart_tor()
                self.exit_configuration()

            if not self.proxy_combo.currentText() == 'None':
                if self.check_valid_proxy_settings():
                    self.use_proxy = True
                else:
                    self.valid_proxy.setWindowModality(QtCore.Qt.WindowModal)
                    self.valid_proxy.exec_()
                    return

            else:
                self.use_proxy = False

            tor_is_enabled = tor_status.tor_status() == 'tor_enabled'
            if not tor_is_enabled:
                self.refresh(True)
                self.restart_button.setEnabled(False)
            if not self.use_custom_bridges and tor_is_enabled :
                self.set_torrc()

    def set_torrc(self):
        args = []

        if self.use_default_bridges:
            args.append(self.bridges_combo.currentText().split()[0])
        else:
            args.append('None')

        if self.use_custom_bridges:
            args.append(self.custom_bridges.toPlainText())
        else:
            args.append('None')

        if self.use_proxy:
            args.append(self.proxy_combo.currentText())
            args.append(self.proxy_ip_edit.text())
            args.append(self.proxy_port_edit.text())
            if not self.proxy_user_edit.text() == 'None':
                args.append(self.proxy_user_edit.text())
            else:
                args.append('')
            if not self.proxy_pwd_edit.text() == 'None':
                args.append(self.proxy_pwd_edit.text())
            else:
                args.append('')
        else:
            args.append('None')

        torrc_gen.gen_torrc(args)
        self.restart_tor()
        self.exit_configuration()

    def exit_configuration(self):
        self.configure_button.setText(' Configure')
        self.configure_button.setIcon(self.tool_icon)
        self.prev_button.hide()
        self.restart_button.setEnabled(True)
        self.stop_button.setEnabled(True)
        self.bridges_combo.hide()
        self.proxy_combo.hide()
        self.bridge_info_button.hide()
        self.proxy_info_button.hide()
        self.proxy_settings_show(self.proxy_type.text())
        self.proxy_ip_edit.setEnabled(False)
        self.proxy_port_edit.setEnabled(False)
        self.proxy_user_edit.setEnabled(False)
        self.proxy_pwd_edit.setEnabled(False)

    def refresh_status(self):
        self.tor_message_browser.setText(self.message)
        color = self.tor_status_color[self.tor_status_list.index(
            self.tor_status)]
        self.status.setStyleSheet('background-color:%s; color:white; \
                                  font:bold' % color)

    def refresh_logs(self):
        for button in self.files_box.findChildren(QRadioButton):
            if button.isChecked():
                if button.text() == self.button_name[0]:
                    p = Popen(self.journal_command, stdout=PIPE, stderr=PIPE)
                    stdout, stderr = p.communicate()
                    text = stdout.decode()

                # Get n last lines from Tor log, HTML format for highlighting
                # warnings and errors, write to file for text browser.
                elif button.text() == self.button_name[1]:
                    if os.path.exists(self.tor_log):
                        lines = os.popen('tail -n 3000 %s' % self.tor_log).read()
                        lines = lines.split('\n')
                        with open(self.tor_log_html, 'w') as fw:
                            for line in lines:
                                line = line + '\n'
                                line = re.sub(line[12:19], '...', line)
                                line = line.replace('[warn]', self.warn_style)
                                line = line.replace('[error]', self.error_style)
                                if '[warn]' in line or '[error]' in line:
                                    line = line.replace('\n', '</span><br>')
                                else:
                                    line = line.replace('\n', '<br>')
                                fw.write(line)

                        with open(self.tor_log_html, 'r') as f:
                            text = f.read()

                    else:
                        text = 'Something is wrong: directory /run/tor does not exists. Try to restart Tor.'

                elif button.text() == self.button_name[2]:
                    with open(torrc_gen.torrc_path()) as f:
                        text = f.read()

                self.file_browser.setText(text)
                self.file_browser.moveCursor(QtGui.QTextCursor.End)

    def refresh_user_configuration(self):
        args = torrc_gen.parse_torrc()

        self.bridge_type.setText(args[0])
        index = self.bridges_combo.findText(args[0])
        self.bridges_combo.setCurrentIndex(index)

        if self.bridge_type in self.default_bridges:
            self.use_default_bridges = True

        elif self.bridge_type == 'Custom bridges':
            self.use_custom_bridges = True

        self.proxy_type.setText(args[1])
        if not self.proxy_type == 'None':
            self.use_proxy = True
            index = self.proxy_combo.findText(args[1])
            self.proxy_combo.setCurrentIndex(index)
            if not args[1] == 'None':
                self.proxy_ip_edit.setText(args[2])
                self.proxy_port_edit.setText(args[3])
                self.proxy_user_edit.setText(args[4])
                self.proxy_pwd_edit.setText(args[5])
        else:
            self.use_proxy = False

    def refresh(self, bootstrap):
        ## get status
        tor_is_enabled = tor_status.tor_status() == 'tor_enabled'
        tor_is_running = os.path.exists(self.tor_running_path)

        if tor_is_enabled and tor_is_running:
            self.tor_status = 'running'
            tor_state = True
            ## when refresh is called from update_bootstrap, the thread
            ## would be destroyed while running, crashing the program.
            if bootstrap:
                self.start_bootstrap()

        else:
            if not tor_is_running:
                self.tor_status = 'stopped'
                tor_state = False
                self.bridges_combo.removeItem(8)
                self.bridges_combo.addItem('Disable network')

            if not tor_is_enabled:
                if tor_is_running:
                    self.tor_status = 'disabled-running'
                    tor_state = True
                    self.bridges_combo.removeItem(8)
                    self.bridges_combo.addItem('Enable network')


                elif not tor_is_running:
                    self.tor_status = 'disabled'
                    tor_state = False
                    self.bridges_combo.removeItem(8)
                    self.bridges_combo.addItem('Enable network')

            self.message = self.tor_message[self.tor_status_list.index(
                self.tor_status)]

        self.newnym_button.setEnabled(tor_state)

        self.refresh_status()
        self.refresh_user_configuration()
        self.refresh_logs()

    def restart_tor(self):
        if not self.bootstrap_done:
            self.bootstrap_thread.terminate()
        ## if running restart tor directly stem returns
        ## bootstrap_percent 100 or a socket error, randomly.
        self.stop_tor()
        self.restart_button.setEnabled(False)

        restart_command = 'leaprun acw-tor-control-restart'
        p = Popen(restart_command, shell=True)
        self.start_bootstrap()

    def stop_tor(self):
        self.restart_button.setEnabled(True)
        if not self.bootstrap_done:
            self.bootstrap_progress.hide()
            self.bootstrap_thread.terminate()
        stop_command = 'leaprun acw-tor-control-stop'
        p = Popen(stop_command, shell=True)
        p.wait()
        self.refresh(True)

    def quit(self):
        if not self.bootstrap_done:
            self.bootstrap_thread.terminate()
        self.accept()


def signal_handler(sig, frame):
    sys.exit(128 + sig)


def main():
    if os.geteuid() == 0:
        print('tor_control_panel.py: ERROR: Do not run with sudo / as root!')
        sys.exit(1)

    app = QApplication(sys.argv)

    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    timer = QtCore.QTimer()
    timer.start(500)
    timer.timeout.connect(lambda: None)

    tor_controller = TorControlPanel()
    tor_controller.refresh(True)
    tor_controller.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
