3 * Copyright 2014 Roy Marples <roy@marples.name>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <QFormLayout>
32 #include <QGridLayout>
33 #include <QHBoxLayout>
37 #include <QMessageBox>
39 #include <QPushButton>
40 #include <QStandardItemModel>
41 #include <QVBoxLayout>
46 #include "dhcpcd-preferences.h"
47 #include "dhcpcd-ipv4validator.h"
48 #include "dhcpcd-qt.h"
49 #include "dhcpcd-wi.h"
51 DhcpcdPreferences::DhcpcdPreferences(DhcpcdQt *parent)
54 this->parent = parent;
56 setWindowIcon(DhcpcdQt::getIcon("status", "network-transmit-receive"));
57 setWindowTitle(tr("Network Preferences"));
61 eWhat = eBlock = NULL;
64 QVBoxLayout *layout = new QVBoxLayout();
66 QGridLayout *topLayout = new QGridLayout();
67 QLabel *conf = new QLabel(tr("Configure:"));
68 topLayout->addWidget(conf, 0, 0);
70 what = new QComboBox();
71 connect(what, SIGNAL(currentIndexChanged(const QString &)),
72 this, SLOT(listBlocks(const QString &)));
73 topLayout->addWidget(what, 0, 1);
74 blocks = new QComboBox();
75 connect(blocks, SIGNAL(currentIndexChanged(const QString &)),
76 this, SLOT(showBlock(const QString &)));
77 topLayout->addWidget(blocks, 0, 2);
79 topLayout->setColumnStretch(2, 10);
81 QWidget *topBox = new QWidget();
82 topBox->setLayout(topLayout);
83 layout->addWidget(topBox);
84 QFrame *topSep = new QFrame();
85 topSep->setFrameShape(QFrame::HLine);
86 topSep->setFrameShadow(QFrame::Sunken);
87 layout->addWidget(topSep);
89 autoConf = new QCheckBox(tr("Automatically configure empty options"));
90 autoConf->setChecked(true);
91 layout->addWidget(autoConf);
93 DhcpcdIPv4Validator *v =
94 new DhcpcdIPv4Validator(DhcpcdIPv4Validator::Plain, this);
95 DhcpcdIPv4Validator *vc =
96 new DhcpcdIPv4Validator(DhcpcdIPv4Validator::CIDR, this);
97 DhcpcdIPv4Validator *vs =
98 new DhcpcdIPv4Validator(DhcpcdIPv4Validator::Spaced, this);
100 ip->setValidator(vc);
101 router = new QLineEdit();
102 router->setValidator(v);
103 rdnss = new QLineEdit();
104 rdnss->setValidator(vs);
105 dnssl = new QLineEdit();
106 #if defined(__NetBSD__) || (__OpenBSD__)
107 dnssl->setMaxLength(1024);
109 dnssl->setMaxLength(256);
111 QFormLayout *ipLayout = new QFormLayout();
112 ipLayout->addRow(tr("IP Address:"), ip);
113 ipLayout->addRow(tr("Router:"), router);
114 ipLayout->addRow(tr("DNS Servers:"), rdnss);
115 ipLayout->addRow(tr("DNS Search:"), dnssl);
116 ipSetup = new QWidget();
117 ipSetup->setLayout(ipLayout);
118 layout->addWidget(ipSetup);
120 QHBoxLayout *buttonLayout = new QHBoxLayout();
121 clear = new QPushButton(tr("&Clear"));
122 clear->setIcon(QIcon::fromTheme("edit-clear"));
123 buttonLayout->addWidget(clear);
124 QPushButton *rebind = new QPushButton(tr("&Rebind"));
125 rebind->setIcon(QIcon::fromTheme("application-x-executable"));
126 buttonLayout->addWidget(rebind);
127 QPushButton *close = new QPushButton(tr("&Close"));
128 close->setIcon(QIcon::fromTheme("window-close"));
129 buttonLayout->addWidget(close);
130 QWidget *buttons = new QWidget();
131 buttons->setLayout(buttonLayout);
132 layout->addWidget(buttons);
134 QIcon wired = DhcpcdQt::getIcon("devices", "network-wired");
135 what->addItem(wired, tr("interface"));
136 QIcon wireless = DhcpcdQt::getIcon("devices", "network-wireless");
137 what->addItem(wireless, tr("SSID"));
139 connect(clear, SIGNAL(clicked()), this, SLOT(clearConfig()));
140 connect(rebind, SIGNAL(clicked()), this, SLOT(rebind()));
141 connect(close, SIGNAL(clicked()), this, SLOT(tryClose()));
145 autoConf->setEnabled(false);
146 ipSetup->setEnabled(false);
147 clear->setEnabled(false);
149 DHCPCD_CONNECTION *con = parent->getConnection();
150 if (!dhcpcd_config_writeable(con))
151 QMessageBox::warning(this, tr("Not writeable"),
152 tr("The dhcpcd configuration file is not writeable\n\n%1")
153 .arg(dhcpcd_cffile(con)));
156 DhcpcdPreferences::~DhcpcdPreferences()
165 void DhcpcdPreferences::closeEvent(QCloseEvent *e)
168 parent->dialogClosed(this);
169 QDialog::closeEvent(e);
172 void DhcpcdPreferences::listBlocks(const QString &txt)
177 /* clear and then disconnect so we trigger a save */
179 blocks->disconnect(this);
182 eWhat = strdup(txt.toLower().toAscii());
184 list = dhcpcd_config_blocks(parent->getConnection(),
185 txt.toLower().toAscii());
187 if (txt == "interface") {
190 blocks->addItem(tr("Select an interface"));
191 for (i = dhcpcd_interfaces(parent->getConnection());
194 if (strcmp(i->type, "link") == 0) {
195 for (lp = list; lp && *lp; lp++) {
196 if (strcmp(i->ifname, *lp) == 0)
199 icon = DhcpcdQt::getIcon("devices",
201 "document-save" : "document-new");
202 blocks->addItem(icon, i->ifname);
206 QList<DhcpcdWi *> *wis = parent->getWis();
208 blocks->addItem(tr("Select a SSID"));
209 for (int i = 0; i < wis->size(); i++) {
210 DHCPCD_WI_SCAN *scan;
211 DhcpcdWi *wi = wis->at(i);
213 for (scan = wi->getScans(); scan; scan = scan->next) {
214 for (lp = list; lp && *lp; lp++) {
215 if (strcmp(scan->ssid, *lp) == 0)
218 icon = DhcpcdQt::getIcon("devices",
220 "document-save" : "document-new");
221 blocks->addItem(icon, scan->ssid);
226 dhcpcd_config_blocks_free(list);
228 /* Now make the 1st item unselectable and reconnect */
229 qobject_cast<QStandardItemModel *>
230 (blocks->model())->item(0)->setEnabled(false);
231 connect(blocks, SIGNAL(currentIndexChanged(const QString &)),
232 this, SLOT(showBlock(const QString &)));
236 void DhcpcdPreferences::clearConfig()
239 autoConf->setChecked(true);
246 void DhcpcdPreferences::showConfig()
251 if ((val = dhcpcd_config_get_static(config, "ip_address=")) != NULL)
254 a = !((val = dhcpcd_config_get(config, "inform")) == NULL &&
255 (iface && iface->flags & IFF_POINTOPOINT));
256 autoConf->setChecked(a);
258 router->setText(dhcpcd_config_get_static(config, "routers="));
259 rdnss->setText(dhcpcd_config_get_static(config,"domain_name_servers="));
260 dnssl->setText(dhcpcd_config_get_static(config, "domain_search="));
263 bool DhcpcdPreferences::changedConfig()
268 if ((val = dhcpcd_config_get_static(config, "ip_address=")) != NULL)
271 a = !((val = dhcpcd_config_get(config, "inform")) == NULL &&
272 (iface && iface->flags & IFF_POINTOPOINT));
273 if (autoConf->isChecked() != a)
275 if (ip->text().compare(val))
277 val = dhcpcd_config_get_static(config, "routers=");
278 if (router->text().compare(val))
280 val = dhcpcd_config_get_static(config, "domain_name_servers=");
281 if (rdnss->text().compare(val))
283 val = dhcpcd_config_get_static(config, "domain_search=");
284 if (rdnss->text().compare(val))
290 const char *DhcpcdPreferences::getString(QLineEdit *le)
292 if (le->text().isEmpty())
294 return le->text().trimmed().toAscii();
297 bool DhcpcdPreferences::setOption(const char *opt, const char *val, bool *ret)
299 if (opt[strlen(opt) - 1] == '=') {
300 if (!dhcpcd_config_set_static(&config, opt, val))
301 qCritical("dhcpcd_config_set_static: %s",
306 if (!dhcpcd_config_set(&config, opt, val))
307 qCritical("dhcpcd_config_set: %s",
319 bool DhcpcdPreferences::makeConfig()
321 const char ns[] = "", *val;
324 a = autoConf->isChecked();
326 if (iface && iface->flags & IFF_POINTOPOINT)
327 setOption("ip_address=", a ? NULL : ns, &ret);
330 setOption("inform", a ? val : NULL, &ret);
331 setOption("ip_address=", a ? NULL : val, &ret);
334 val = getString(router);
335 setOption("routers=", val, &ret);
337 val = getString(rdnss);
338 setOption("domain_name_servers=", val, &ret);
340 val = getString(dnssl);
341 setOption("domain_search=", val, &ret);
346 bool DhcpcdPreferences::writeConfig(bool *cancel)
349 switch (QMessageBox::question(this, tr("Save Configuration"),
350 tr("Do you want to save your changes?"),
351 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel)) {
352 case QMessageBox::Cancel:
355 case QMessageBox::Discard:
362 DHCPCD_CONNECTION *con = parent->getConnection();
364 qCritical("failed to make config");
367 if (!dhcpcd_config_write(con, eWhat, eBlock, config)) {
368 qCritical("dhcpcd_config_write: %s", strerror(errno));
369 QMessageBox::critical(parent,
370 tr("Failed to write configuration"),
371 tr("Failed to write configuration:\n\n%1: %2")
372 .arg(dhcpcd_cffile(con))
373 .arg(strerror(errno)));
379 /* Reload our config if there is a problem */
380 config = dhcpcd_config_read(con, eWhat, eBlock);
384 void DhcpcdPreferences::showBlock(const QString &txt)
388 if (changedConfig()) {
390 if (!writeConfig(&cancel))
398 eBlock = strdup(txt.toAscii());
400 dhcpcd_config_free(config);
402 DHCPCD_CONNECTION *con = parent->getConnection();
404 if (eBlock && eWhat) {
405 if (strcmp(eWhat, "interface") == 0)
406 iface = dhcpcd_get_if(con, eBlock, "link");
407 ip->setEnabled(iface == NULL ||
408 !(iface->flags & IFF_POINTOPOINT));
410 config = dhcpcd_config_read(con, eWhat, eBlock);
411 if (config == NULL && errno) {
415 qCritical("dhcpcd_config_read: %s", s);
416 QMessageBox::critical(this,
417 tr("Error reading configuration"),
418 tr("Error reading: ") + dhcpcd_cffile(con) +
425 bool enabled = dhcpcd_config_writeable(con) && eBlock != NULL;
426 autoConf->setEnabled(enabled);
427 ipSetup->setEnabled(enabled);
428 clear->setEnabled(enabled);
431 bool DhcpcdPreferences::tryRebind(const char *ifname)
434 if (dhcpcd_rebind(parent->getConnection(), ifname) == 0)
437 qCritical("dhcpcd_rebind: %s", strerror(errno));
438 QMessageBox::critical(this,
440 ifname ? tr("Failed to rebind interface %1: %2")
441 .arg(ifname).arg(strerror(errno)) :
442 tr("Failed to rebind: %1")
443 .arg(strerror(errno)));
447 void DhcpcdPreferences::rebind()
450 if (changedConfig()) {
452 writeConfig(&cancel);
457 DHCPCD_CONNECTION *con = parent->getConnection();
461 if (eBlock == NULL || strcmp(eWhat, "interface") == 0) {
462 worked = tryRebind(iface ? iface->ifname : NULL);
468 for (i = dhcpcd_interfaces(con); i; i = i->next) {
469 if (strcmp(i->type, "link") == 0 &&
470 (i->ssid && strcmp(i->ssid, eBlock) == 0))
473 if (!tryRebind(i->ifname))
478 QMessageBox::information(this,
479 tr("No matching interface"),
480 tr("No interface is bound to this SSID to rebind"));
489 void DhcpcdPreferences::tryClose()
492 if (changedConfig()) {
494 writeConfig(&cancel);