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>
44 #include "dhcpcd-preferences.h"
45 #include "dhcpcd-ipv4validator.h"
46 #include "dhcpcd-qt.h"
47 #include "dhcpcd-wi.h"
49 DhcpcdPreferences::DhcpcdPreferences(DhcpcdQt *parent)
52 this->parent = parent;
54 setWindowIcon(DhcpcdQt::getIcon("status", "network-transmit-receive"));
55 setWindowTitle(tr("Network Preferences"));
59 eWhat = eBlock = NULL;
62 QVBoxLayout *layout = new QVBoxLayout();
64 QGridLayout *topLayout = new QGridLayout();
65 QLabel *conf = new QLabel(tr("Configure:"));
66 topLayout->addWidget(conf, 0, 0);
68 what = new QComboBox();
69 connect(what, SIGNAL(currentIndexChanged(const QString &)),
70 this, SLOT(listBlocks(const QString &)));
71 topLayout->addWidget(what, 0, 1);
72 blocks = new QComboBox();
73 connect(blocks, SIGNAL(currentIndexChanged(const QString &)),
74 this, SLOT(showBlock(const QString &)));
75 topLayout->addWidget(blocks, 0, 2);
77 topLayout->setColumnStretch(2, 10);
79 QWidget *topBox = new QWidget();
80 topBox->setLayout(topLayout);
81 layout->addWidget(topBox);
82 QFrame *topSep = new QFrame();
83 topSep->setFrameShape(QFrame::HLine);
84 topSep->setFrameShadow(QFrame::Sunken);
85 layout->addWidget(topSep);
87 autoConf = new QCheckBox(tr("Automatically configure empty options"));
88 autoConf->setChecked(true);
89 layout->addWidget(autoConf);
91 DhcpcdIPv4Validator *v =
92 new DhcpcdIPv4Validator(DhcpcdIPv4Validator::Plain, this);
93 DhcpcdIPv4Validator *vc =
94 new DhcpcdIPv4Validator(DhcpcdIPv4Validator::CIDR, this);
95 DhcpcdIPv4Validator *vs =
96 new DhcpcdIPv4Validator(DhcpcdIPv4Validator::Spaced, this);
99 router = new QLineEdit();
100 router->setValidator(v);
101 rdnss = new QLineEdit();
102 rdnss->setValidator(vs);
103 dnssl = new QLineEdit();
104 #if defined(__NetBSD__) || (__OpenBSD__)
105 dnssl->setMaxLength(1024);
107 dnssl->setMaxLength(256);
109 QFormLayout *ipLayout = new QFormLayout();
110 ipLayout->addRow(tr("IP Address:"), ip);
111 ipLayout->addRow(tr("Router:"), router);
112 ipLayout->addRow(tr("DNS Servers:"), rdnss);
113 ipLayout->addRow(tr("DNS Search:"), dnssl);
114 ipSetup = new QWidget();
115 ipSetup->setLayout(ipLayout);
116 layout->addWidget(ipSetup);
118 QHBoxLayout *buttonLayout = new QHBoxLayout();
119 clear = new QPushButton(tr("&Clear"));
120 clear->setIcon(QIcon::fromTheme("edit-clear"));
121 buttonLayout->addWidget(clear);
122 QPushButton *rebind = new QPushButton(tr("&Rebind"));
123 rebind->setIcon(QIcon::fromTheme("application-x-executable"));
124 buttonLayout->addWidget(rebind);
125 QPushButton *close = new QPushButton(tr("&Close"));
126 close->setIcon(QIcon::fromTheme("window-close"));
127 buttonLayout->addWidget(close);
128 QWidget *buttons = new QWidget();
129 buttons->setLayout(buttonLayout);
130 layout->addWidget(buttons);
132 QIcon wired = DhcpcdQt::getIcon("devices", "network-wired");
133 what->addItem(wired, tr("Interface"));
134 QIcon wireless = DhcpcdQt::getIcon("devices", "network-wireless");
135 what->addItem(wireless, tr("SSID"));
137 connect(clear, SIGNAL(clicked()), this, SLOT(clearConfig()));
138 connect(rebind, SIGNAL(clicked()), this, SLOT(rebind()));
139 connect(close, SIGNAL(clicked()), this, SLOT(tryClose()));
143 autoConf->setEnabled(false);
144 ipSetup->setEnabled(false);
145 clear->setEnabled(false);
147 DHCPCD_CONNECTION *con = parent->getConnection();
148 if (!dhcpcd_config_writeable(con))
149 QMessageBox::warning(this, tr("Not writeable"),
150 tr("The dhcpcd configuration file is not writeable\n\n%1")
151 .arg(dhcpcd_cffile(con)));
154 DhcpcdPreferences::~DhcpcdPreferences()
163 void DhcpcdPreferences::closeEvent(QCloseEvent *e)
166 parent->dialogClosed(this);
167 QDialog::closeEvent(e);
170 void DhcpcdPreferences::listBlocks(const QString &txt)
173 /* clear and then disconnect so we trigger a save */
175 blocks->disconnect(this);
178 eWhat = strdup(txt.toLower().toAscii());
180 if (txt == "Interface") {
183 blocks->addItem(tr("Select an interface"));
184 for (i = dhcpcd_interfaces(parent->getConnection());
187 if (strcmp(i->type, "link") == 0) {
188 QIcon icon = DhcpcdQt::getIcon("devices",
190 "network-wireless" : "network-wired");
191 blocks->addItem(icon, i->ifname);
195 QList<DhcpcdWi *> *wis = parent->getWis();
197 blocks->addItem(tr("Select a SSID"));
198 for (int i = 0; i < wis->size(); i++) {
199 DHCPCD_WI_SCAN *scan;
200 DhcpcdWi *wi = wis->at(i);
202 for (scan = wi->getScans(); scan; scan = scan->next) {
205 icon = DhcpcdQt::getIcon(
206 scan->flags[0] == '\0' ?"devices" :"status",
207 scan->flags[0] == '\0' ?"network-wireless" :
208 "network-wireless-encrypted");
209 blocks->addItem(icon, scan->ssid);
214 /* Now make the 1st item unselectable and reconnect */
215 qobject_cast<QStandardItemModel *>(blocks->model())->item(0)->setEnabled(false);
216 connect(blocks, SIGNAL(currentIndexChanged(const QString &)),
217 this, SLOT(showBlock(const QString &)));
221 void DhcpcdPreferences::clearConfig()
224 autoConf->setChecked(true);
231 void DhcpcdPreferences::showConfig()
236 if ((val = dhcpcd_config_get_static(config, "ip_address=")) != NULL)
239 a = !((val = dhcpcd_config_get(config, "inform")) == NULL &&
240 (iface && iface->flags & IFF_POINTOPOINT));
241 autoConf->setChecked(a);
243 router->setText(dhcpcd_config_get_static(config, "routers="));
244 rdnss->setText(dhcpcd_config_get_static(config,"domain_name_servers="));
245 dnssl->setText(dhcpcd_config_get_static(config, "domain_search="));
248 bool DhcpcdPreferences::changedConfig()
253 if ((val = dhcpcd_config_get_static(config, "ip_address=")) != NULL)
256 a = !((val = dhcpcd_config_get(config, "inform")) == NULL &&
257 (iface && iface->flags & IFF_POINTOPOINT));
258 if (autoConf->isChecked() != a)
260 if (ip->text().compare(val))
262 val = dhcpcd_config_get_static(config, "routers=");
263 if (router->text().compare(val))
265 val = dhcpcd_config_get_static(config, "domain_name_servers=");
266 if (rdnss->text().compare(val))
268 val = dhcpcd_config_get_static(config, "domain_search=");
269 if (rdnss->text().compare(val))
275 const char *DhcpcdPreferences::getString(QLineEdit *le)
277 if (le->text().isEmpty())
279 return le->text().trimmed().toAscii();
282 bool DhcpcdPreferences::setOption(const char *opt, const char *val, bool *ret)
284 if (opt[strlen(opt) - 1] == '=') {
285 if (!dhcpcd_config_set_static(&config, opt, val))
286 qCritical("dhcpcd_config_set_static: %s",
291 if (!dhcpcd_config_set(&config, opt, val))
292 qCritical("dhcpcd_config_set: %s",
304 bool DhcpcdPreferences::makeConfig()
306 const char ns[] = "", *val;
309 a = autoConf->isChecked();
311 if (iface && iface->flags & IFF_POINTOPOINT)
312 setOption("ip_address=", a ? NULL : ns, &ret);
315 setOption("inform", a ? val : NULL, &ret);
316 setOption("ip_address=", a ? NULL : val, &ret);
319 val = getString(router);
320 setOption("routers=", val, &ret);
322 val = getString(rdnss);
323 setOption("domain_name_servers=", val, &ret);
325 val = getString(dnssl);
326 setOption("domain_search=", val, &ret);
331 bool DhcpcdPreferences::writeConfig(bool *cancel)
334 switch (QMessageBox::question(this, tr("Save Configuration"),
335 tr("Do you want to save your changes?"),
336 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel)) {
337 case QMessageBox::Cancel:
340 case QMessageBox::Discard:
347 DHCPCD_CONNECTION *con = parent->getConnection();
349 qCritical("failed to make config");
352 if (!dhcpcd_config_write(con, eWhat, eBlock, config)) {
353 qCritical("dhcpcd_config_write: %s", strerror(errno));
354 QMessageBox::critical(parent,
355 tr("Failed to write configuration"),
356 tr("Failed to write configuration:\n\n%1: %2")
357 .arg(dhcpcd_cffile(con))
358 .arg(strerror(errno)));
364 /* Reload our config if there is a problem */
365 config = dhcpcd_config_read(con, eWhat, eBlock);
369 void DhcpcdPreferences::showBlock(const QString &txt)
373 if (changedConfig()) {
375 if (!writeConfig(&cancel))
383 eBlock = strdup(txt.toAscii());
385 dhcpcd_config_free(config);
387 DHCPCD_CONNECTION *con = parent->getConnection();
389 if (eBlock && eWhat) {
390 if (strcmp(eWhat, "interface") == 0)
391 iface = dhcpcd_get_if(con, eBlock, "link");
392 ip->setEnabled(iface == NULL ||
393 !(iface->flags & IFF_POINTOPOINT));
395 config = dhcpcd_config_read(con, eWhat, eBlock);
396 if (config == NULL && errno) {
400 qCritical("dhcpcd_config_read: %s", s);
401 QMessageBox::critical(this,
402 tr("Error reading configuration"),
403 tr("Error reading: ") + dhcpcd_cffile(con) +
410 bool enabled = dhcpcd_config_writeable(con) && eBlock != NULL;
411 autoConf->setEnabled(enabled);
412 ipSetup->setEnabled(enabled);
413 clear->setEnabled(enabled);
416 bool DhcpcdPreferences::tryRebind(const char *ifname)
419 if (dhcpcd_rebind(parent->getConnection(), ifname) == 0)
422 qCritical("dhcpcd_rebind: %s", strerror(errno));
423 QMessageBox::critical(this,
425 ifname ? tr("Failed to rebind interface %1: %2")
426 .arg(ifname).arg(strerror(errno)) :
427 tr("Failed to rebind: %1")
428 .arg(strerror(errno)));
432 void DhcpcdPreferences::rebind()
435 if (changedConfig()) {
437 writeConfig(&cancel);
442 DHCPCD_CONNECTION *con = parent->getConnection();
446 if (iface && strcmp(eWhat, "interface") == 0) {
447 worked = tryRebind(iface ? iface->ifname : NULL);
452 for (i = dhcpcd_interfaces(con); i; i = i->next) {
453 if (strcmp(i->type, "link") == 0 &&
455 (i->ssid && strcmp(i->ssid, eBlock) == 0)))
458 if (!tryRebind(i->ifname))
463 QMessageBox::information(this,
464 tr("No matching interface"),
465 tr("No interface is bound to this SSID to rebind"));
474 void DhcpcdPreferences::tryClose()
477 if (changedConfig()) {
479 writeConfig(&cancel);