Gui настройка сети (qt)

Требуется написать Gui программу для настройки сети.
Суть проста, человек вводит данные, нажимает кнопку сохранить, и это сохраняется в /etc/rc.conf
На qt накидал формочку, но как написать программу не знаю. Опыта программирования на qt нет.

Если кто поможет с программирование, буду рад!

По сути код всей программы закладывается в кнопку сохранить, которая берет данные из полей и записывает их в /etc/rc.conf в нужное место
Вообщем написал я эту программу, пришлось изучить Qt и Python и с использование модуля pyqt написал.

Программа работает от суперпользователя, так как перезаписывает файлы /etc/rc.conf, /etc/resolv.conf и перезапускает сеть.
Работает только в среде ArchLinux, все баги отловлены, в процессе написания программы обучался, поэтому старался всё делать максимально качественно.

Требуется модуль PyQt

#!/usr/bin/python
# pyarchnetcgf.py
# Программа на QT4 для редактирования сетевых настроек в ArchLinux
import sys, os
from PyQt4 import QtGui, QtCore
from subprocess import Popen, PIPE
RCCONF = "/etc/rc.conf"
RESOLVCONF = "/etc/resolv.conf"
try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s
class ArchNetCfg(QtGui.QWidget):
    def __init__(self, parent=None):
            QtGui.QWidget.__init__(self, parent)
            
            self.setWindowTitle("Сетевые настройки")
            
            ###Радио кнопки Статически и Автоматически###
            self.radioStatic = QtGui.QRadioButton("Статически", self)
            self.radioAuto = QtGui.QRadioButton("Автоматически", self)
            self.radioStatic.setChecked(True)
            
            ###Метки###
            ipLabel = QtGui.QLabel("IP-адрес")
            maskLabel = QtGui.QLabel("Маска")
            gatewayLabel = QtGui.QLabel("Шлюз")
            dns1Label = QtGui.QLabel("DNS1")
            dns2Label = QtGui.QLabel("DNS2")
            dns3Label = QtGui.QLabel("DNS3")
            macLabel = QtGui.QLabel("MAC-адрес")
            
            ###Подсказки для меток###
            ipLabel.setToolTip("IP-адрес - уникальный сетевой адрес узла (компьютера) в компьютерной сети.\nЕго можно узнать у вашего провайдера или системного администратора.")
            maskLabel.setToolTip("Маска подсети - битовая маска, определяющая, какая часть IP-адреса \nузла сети относится к сети, а какая - к адресу узла в этой сети.")
            gatewayLabel.setToolTip("Сетевой шлюз - предоставляет доступ в локальную сеть или интернет")
            dns1Label.setToolTip("Сервер предоставляющий IP-адрес хоста по его имени")
            dns2Label.setToolTip("Сервер предоставляющий IP-адрес хоста по его имени")
            dns3Label.setToolTip("Сервер предоставляющий IP-адрес хоста по его имени")
            
            ###Поля для правки адресов###
            self.ipEdit = QtGui.QLineEdit(self.read_setting_from_rcconf("address"))
            self.maskEdit = QtGui.QLineEdit(self.read_setting_from_rcconf("netmask"))
            self.gatewayEdit = QtGui.QLineEdit(self.read_setting_from_rcconf("gateway"))
            self.dns1Edit = QtGui.QLineEdit(self.read_resolvconf(0))
            self.dns2Edit = QtGui.QLineEdit(self.read_resolvconf(1))
            self.dns3Edit = QtGui.QLineEdit(self.read_resolvconf(2))
            self.macAddress = QtGui.QLineEdit(self.get_mac('eth0'))
            self.macAddress.setDisabled(True)
            
            ###Кнопки сохранить и отмена###
            self.buttonBox = QtGui.QDialogButtonBox(self)
            self.save = self.buttonBox.addButton(self.buttonBox.Save)
            self.cancel = self.buttonBox.addButton(self.buttonBox.Cancel)
            
            
            ###Расстановка элементов по сетки###
            hboxRadio = QtGui.QHBoxLayout()
            hboxRadio.addWidget(self.radioStatic)
            hboxRadio.addWidget(self.radioAuto)
            
            grid = QtGui.QGridLayout()
            grid.setSpacing(5)
            
            grid.addWidget(ipLabel, 1, 0)
            grid.addWidget(self.ipEdit, 1, 1)
            
            grid.addWidget(maskLabel, 2, 0)
            grid.addWidget(self.maskEdit, 2, 1)
            
            grid.addWidget(gatewayLabel, 3, 0)
            grid.addWidget(self.gatewayEdit, 3, 1)
            
            grid.addWidget(dns1Label, 4, 0)
            grid.addWidget(self.dns1Edit, 4, 1)
            
            grid.addWidget(dns2Label, 5, 0)
            grid.addWidget(self.dns2Edit, 5, 1)
            
            grid.addWidget(dns3Label, 6, 0)
            grid.addWidget(self.dns3Edit, 6, 1)
            
            grid.addWidget(macLabel, 7, 0)
            grid.addWidget(self.macAddress, 7, 1)
            
            hboxButton = QtGui.QHBoxLayout()
            hboxButton.addStretch(1)
            hboxButton.addWidget(self.buttonBox)
            
            vbox = QtGui.QVBoxLayout()
            vbox.addLayout(hboxRadio)
            vbox.addLayout(grid)
            vbox.addLayout(hboxButton)
            
            ###Геометрия окна###
            self.setLayout(vbox)
            self.setGeometry(300,300,0, 0)
            
            ###Сигналы и слоты###
            self.connect(self.cancel, QtCore.SIGNAL('clicked()'), QtGui.qApp, QtCore.SLOT('quit()'))
            self.connect(self.save, QtCore.SIGNAL('clicked()'), self.saveChanges)
            self.connect(self.radioAuto, QtCore.SIGNAL('toggled(bool)'), self.disableAll)
            self.connect(self.radioStatic, QtCore.SIGNAL('toggled(bool)'), self.enableAll)
            
    """Сделать элементы не активными"""
    def disableAll(self):
    
        self.ipEdit.setDisabled(True)
        self.maskEdit.setDisabled(True)
        self.gatewayEdit.setDisabled(True)
        self.dns1Edit.setDisabled(True)
        self.dns2Edit.setDisabled(True)
        self.dns3Edit.setDisabled(True)
    """Сделать элементы активными"""
    def enableAll(self):
    
        self.ipEdit.setDisabled(False)
        self.maskEdit.setDisabled(False)
        self.gatewayEdit.setDisabled(False)
        self.dns1Edit.setDisabled(False)
        self.dns2Edit.setDisabled(False)
        self.dns3Edit.setDisabled(False)
        
    """Сохранение настроек"""
    def saveChanges(self):
    
        # Значения всех полей
        ip = self.ipEdit.text()
        mask = self.maskEdit.text()
        gateway = self.gatewayEdit.text()
        dns1 = self.dns1Edit.text()
        dns2 = self.dns2Edit.text()
        dns3 = self.dns3Edit.text()
        
        # Остановить сеть!!!
        os.system("/etc/rc.d/network stop")
        
        if self.radioAuto.isChecked():
            
            #Записать автоматические настройки
            self.rcconf_edit("address","")
            self.rcconf_edit("netmask","")
            self.rcconf_edit("gateway","")
            
        else:
            
            # Записать настройки вручную
            self.rcconf_edit("address",ip)
            self.rcconf_edit("netmask",mask)
            self.rcconf_edit("gateway",gateway)
            
            # Записать DNS адрес
            self.writedns(dns1, dns2, dns3)  
            
        # Запустить сеть!!!
        os.system("/etc/rc.d/network start")
        
        # После сохранения, выходим    
        sys.exit()
    
    """ Функция считывает значение у параметра из rc.conf,
    вызывается: read_setting_from_rcconf("имя параметра")"""
    def read_setting_from_rcconf(self,param):
    
        config = open(RCCONF).readlines()
        # Вычисляем номер строки, которая начинается с имени параметра
        num_line = 0 #Номер строки
        for line in config:
            # Если строка N num_line начинается со слова param
            if config[num_line].startswith(param):
                break
            num_line+=1
    
        # Разбиваем строку на слова
        param_sett = config[num_line].split("=")
        # Очищаем значение параметра от пробелом, и возвращаем
        return param_sett[1].strip()
    
        """ Функция редактирования конфигурационного файла rc.conf,
     вызывается: rcconf_edit("параметр","значение") """
    def rcconf_edit(self,param, setting):
        # Читаем все строки в файле
        config = open(RCCONF).readlines()
        # Вычисляем номер строки, которая начинается с gateway
        num_line = 0 #Номер строки
        for line in config:
            # Если строка N num_line начинается со слова param
            if config[num_line].startswith(param):
                break
            num_line+=1
    
        # Разбиваем строку на слова
        param_sett = config[num_line].split("=")
        # Очищаем значение параметра от пробелом и сохраняем в переменную old_setting
        old_setting = param_sett[1].strip()
        # Заменяем строку "параметр = значение" на новую
        param_sett[1] = setting + "\n"
        config[num_line] = '='.join(param_sett)
        # Записываем новый конфиг в файл
        with open(RCCONF, 'w') as config_write:
            config_write.writelines(config)
    
    """ Функция считывает все dns адреса из resolv.conf и возвращает запрашиваемый по номеру"""
    def read_resolvconf(self,num_dns):
    
        config = open(RESOLVCONF).readlines()
        
        # Вычисляем номер строки, которая начинается с имени параметра
        num_line = 0 # Номер строки
        nameserver_list = [] # Список в котором будут храниться dns адреса
        for line in config:
            # Если строка N num_line начинается со слова nameserver и имеет продолжение
            if config[num_line].startswith("nameserver")  and len(config[num_line]) > 11:
                # То разбиваем строку на подстроки
                a = config[num_line].split()
            
                # Сохраняем значение в список
                nameserver_list.append(a[1])
            num_line+=1
            
        # Возвращаем dns адрес. Если num_dns задан неверный, то возвращается ничего
        try:
            return nameserver_list[num_dns]
        except IndexError:
            return ""
        
    def writedns(self, dns1, dns2, dns3):
        # Открыли на запись
            with open(RESOLVCONF, 'w') as resolv:
                all_dns_address = ('')
                
                # Записать в all_dns_address все используемые днс адреса, пустые поля игнорируются
                for dns in dns1, dns2, dns3:
                    if len(dns) > 0 :
                        all_dns_address = all_dns_address + 'nameserver %s\n' %(dns)
                                  
                # Добавить к комментариям список днс адресов
                text_in_resolv = ('# Generadet by pyarchnetcfg\n'
                                  '# /etc/resolv.conf.head can replace this line\n'
                                  '%s'
                                  '# /etc/resolv.conf.head can replace this line\n' %(all_dns_address))
                # Записать сформированную строку в файл
                resolv.write(text_in_resolv)
        
    """ Функция получения mac адреса, возвращает mac адрес """
    def get_mac(self, interface):
    
        # Выполнить ifconfig eth0
        p1 = Popen(['ifconfig', interface], stdout=PIPE)
        # и записать вывод в output в виде строки
        output = str(p1.communicate()[0])
        # Позиция слова ether в строке
        pos_word = output.find('ether')
        # mac адрес начинается c 6 символа после начала слова ether и кончается на 23 символе после начала слова ether
        return output[pos_word+6:pos_word+23]
            
app = QtGui.QApplication(sys.argv)
qb = ArchNetCfg()
qb.show()
sys.exit(app.exec_())
По “красоте” кода кто-нибудь другой подскажет, если что не так.
Но у меня вопрос: зачем она нужна, по-большому счёту?
Статика настраивается легко и просто непосредственно через nano, причём, как правило, ещё на этапе установки системы, когда никакими GUI ещё и не пахнет.
В процессе использования системы, при смене параметров подключения в рамках использования такого типа соединения - только здесь она и может быть использована, разве нет? И снова вопрос, зачем она, когда есть nano? Просто лишняя сущность? А если нету qt и прочих зависимостей? Ну, мало-ли.., и что, тащить только ради красивого окошка для одноразового использования?
Иными словами, “новичок” ей просто не сможет воспользоваться, потому что, когда она нужна - нету гуи, а “старичку” она уже не нужна.

Нет, всё класно! Qt, Python и всё такое.., а напиши gui-прогу для, например, l2tp-подключения - вон, некоторые лбы расшибают до сих пор.
Я для работы, создал свой дистрибутив на базе ArchLinux, с определенным набором софта, для офисного использования. Чтобы каждому сотруднику, кто пользуется этой системой, не настраивать сеть, я и написал эту программу. Для опытного пользователя конечно же эта программа не имеет смысла. Но для себя я получил большой опыт!
Следующим этапом попробую написать систему видеонаблюдения на базе motion и qt, а то под линукс с этим туго.
Свой дистр - ну, это всё объясняет)
Мы все (надеюсь, что все) рады за тот офис, раз с сетью там всё так легко и просто.
Творческих успехов!

ps. И всё-же, как насчёт “L2TP-GUI”? ;-)
Наверное, я чего-то пока не понял.
Возможно, кому-то и правда было бы удобно пользоваться этой программой.
Но я не очень представляю ситуацию с сотрудниками, которые сами себе настраивают сеть.
Ситуации разные бывают, не буду объяснять всех нюнсов, в мои задачи входило сделать определенную систему и передать ее людям, при этом я с ними не контактирую ( я не админ сети), а их админ или они сами могут настроить сеть уже. Это уже офтопик.
Для меня главное опыт.
Но я не очень представляю ситуацию с сотрудниками, которые сами себе настраивают сеть.
Например, в кач-ве “утренней зарядки” или в рамках программы по борьбе с курением: “А ну-ка, сейчас мы все вместе снова повторим вчерашнее упражнение…”

ps. Извините, на самом деле, всё это очень здорово: Qt, Python и всё такое…)
Поддерживаю вопрос по поводу L2TP-GUI
:)
Два раза написал что-ли?
:)

Вообще - добавь описание для “тех кто в танке” - что делать с выложенным кодом и как потом запускать программу (типа - сохранить приложенный код в файл с именем… и т.д.). Вдруг кому-то из новичков понадобится.
 
Зарегистрироваться или войдите чтобы оставить сообщение.