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"));
58 QPoint p = QCursor::pos();
64 eWhat = eBlock = NULL;
67 QVBoxLayout *layout = new QVBoxLayout();
69 QGridLayout *topLayout = new QGridLayout();
70 QLabel *conf = new QLabel(tr("Configure:"));
71 topLayout->addWidget(conf, 0, 0);
73 what = new QComboBox();
74 connect(what, SIGNAL(currentIndexChanged(const QString &)),
75 this, SLOT(listBlocks(const QString &)));
76 topLayout->addWidget(what, 0, 1);
77 blocks = new QComboBox();
78 connect(blocks, SIGNAL(currentIndexChanged(const QString &)),
79 this, SLOT(showBlock(const QString &)));
80 topLayout->addWidget(blocks, 0, 2);
82 topLayout->setColumnStretch(2, 10);
84 QWidget *topBox = new QWidget();
85 topBox->setLayout(topLayout);
86 layout->addWidget(topBox);
87 QFrame *topSep = new QFrame();
88 topSep->setFrameShape(QFrame::HLine);
89 topSep->setFrameShadow(QFrame::Sunken);
90 layout->addWidget(topSep);
92 autoConf = new QCheckBox(tr("Automatically configure empty options"));
93 autoConf->setChecked(true);
94 layout->addWidget(autoConf);
96 DhcpcdIPv4Validator *v =
97 new DhcpcdIPv4Validator(DhcpcdIPv4Validator::Plain, this);
98 DhcpcdIPv4Validator *vc =
99 new DhcpcdIPv4Validator(DhcpcdIPv4Validator::CIDR, this);
100 DhcpcdIPv4Validator *vs =
101 new DhcpcdIPv4Validator(DhcpcdIPv4Validator::Spaced, this);
102 ip = new QLineEdit();
103 ip->setValidator(vc);
104 router = new QLineEdit();
105 router->setValidator(v);
106 rdnss = new QLineEdit();
107 rdnss->setValidator(vs);
108 dnssl = new QLineEdit();
109 #if defined(__NetBSD__) || (__OpenBSD__)
110 dnssl->setMaxLength(1024);
112 dnssl->setMaxLength(256);
114 QFormLayout *ipLayout = new QFormLayout();
115 ipLayout->addRow(tr("IP Address:"), ip);
116 ipLayout->addRow(tr("Router:"), router);
117 ipLayout->addRow(tr("DNS Servers:"), rdnss);
118 ipLayout->addRow(tr("DNS Search:"), dnssl);
119 ipSetup = new QWidget();
120 ipSetup->setLayout(ipLayout);
121 layout->addWidget(ipSetup);
123 QHBoxLayout *buttonLayout = new QHBoxLayout();
124 clear = new QPushButton(tr("&Clear"));
125 clear->setIcon(QIcon::fromTheme("edit-clear"));
126 buttonLayout->addWidget(clear);
127 QPushButton *rebind = new QPushButton(tr("&Rebind"));
128 rebind->setIcon(QIcon::fromTheme("application-x-executable"));
129 buttonLayout->addWidget(rebind);
130 QPushButton *close = new QPushButton(tr("&Close"));
131 close->setIcon(QIcon::fromTheme("window-close"));
132 buttonLayout->addWidget(close);
133 QWidget *buttons = new QWidget();
134 buttons->setLayout(buttonLayout);
135 layout->addWidget(buttons);
137 QIcon wired = DhcpcdQt::getIcon("devices", "network-wired");
138 what->addItem(wired, tr("interface"));
139 QIcon wireless = DhcpcdQt::getIcon("devices", "network-wireless");
140 what->addItem(wireless, tr("SSID"));
142 connect(clear, SIGNAL(clicked()), this, SLOT(clearConfig()));
143 connect(rebind, SIGNAL(clicked()), this, SLOT(rebind()));
144 connect(close, SIGNAL(clicked()), this, SLOT(tryClose()));
148 autoConf->setEnabled(false);
149 ipSetup->setEnabled(false);
150 clear->setEnabled(false);
152 DHCPCD_CONNECTION *con = parent->getConnection();
153 if (!dhcpcd_config_writeable(con))
154 QMessageBox::warning(this, tr("Not writeable"),
155 tr("The dhcpcd configuration file is not writeable\n\n%1")
156 .arg(dhcpcd_cffile(con)));
159 DhcpcdPreferences::~DhcpcdPreferences()
168 void DhcpcdPreferences::closeEvent(QCloseEvent *e)
171 parent->dialogClosed(this);
172 QDialog::closeEvent(e);
175 void DhcpcdPreferences::listBlocks(const QString &txt)
180 /* clear and then disconnect so we trigger a save */
182 blocks->disconnect(this);
185 eWhat = strdup(txt.toLower().toAscii());
187 list = dhcpcd_config_blocks(parent->getConnection(),
188 txt.toLower().toAscii());
190 if (txt == "interface") {
193 blocks->addItem(tr("Select an interface"));
194 ifaces = dhcpcd_interface_names_sorted(parent->getConnection());
195 for (i = ifaces; i && *i; i++) {
196 for (lp = list; lp && *lp; lp++) {
197 if (strcmp(*i, *lp) == 0)
200 icon = DhcpcdQt::getIcon("actions",
202 "document-save" : "document-new");
203 blocks->addItem(icon, *i);
205 dhcpcd_freev(ifaces);
207 QList<DhcpcdWi *> *wis = parent->getWis();
209 blocks->addItem(tr("Select a SSID"));
210 for (int i = 0; i < wis->size(); i++) {
211 DHCPCD_WI_SCAN *scan;
212 DhcpcdWi *wi = wis->at(i);
214 for (scan = wi->getScans(); scan; scan = scan->next) {
215 for (lp = list; lp && *lp; lp++) {
216 if (strcmp(scan->ssid, *lp) == 0)
219 icon = DhcpcdQt::getIcon("actions",
221 "document-save" : "document-new");
222 blocks->addItem(icon, scan->ssid);
229 /* Now make the 1st item unselectable and reconnect */
230 qobject_cast<QStandardItemModel *>
231 (blocks->model())->item(0)->setEnabled(false);
232 connect(blocks, SIGNAL(currentIndexChanged(const QString &)),
233 this, SLOT(showBlock(const QString &)));
237 void DhcpcdPreferences::clearConfig()
239 QIcon icon = DhcpcdQt::getIcon("actions", "document-new");
241 blocks->setItemIcon(blocks->currentIndex(), icon);
242 autoConf->setChecked(true);
249 void DhcpcdPreferences::showConfig()
254 if ((val = dhcpcd_config_get_static(config, "ip_address=")) != NULL)
257 a = !((val = dhcpcd_config_get(config, "inform")) == NULL &&
258 (iface && iface->flags & IFF_POINTOPOINT));
259 autoConf->setChecked(a);
261 router->setText(dhcpcd_config_get_static(config, "routers="));
262 rdnss->setText(dhcpcd_config_get_static(config,"domain_name_servers="));
263 dnssl->setText(dhcpcd_config_get_static(config, "domain_search="));
266 bool DhcpcdPreferences::changedConfig()
271 if ((val = dhcpcd_config_get_static(config, "ip_address=")) != NULL)
274 a = !((val = dhcpcd_config_get(config, "inform")) == NULL &&
275 (iface && iface->flags & IFF_POINTOPOINT));
276 if (autoConf->isChecked() != a)
278 if (ip->text().compare(val))
280 val = dhcpcd_config_get_static(config, "routers=");
281 if (router->text().compare(val))
283 val = dhcpcd_config_get_static(config, "domain_name_servers=");
284 if (rdnss->text().compare(val))
286 val = dhcpcd_config_get_static(config, "domain_search=");
287 if (rdnss->text().compare(val))
293 const char *DhcpcdPreferences::getString(QLineEdit *le)
295 if (le->text().isEmpty())
297 return le->text().trimmed().toAscii();
300 bool DhcpcdPreferences::setOption(const char *opt, const char *val, bool *ret)
302 if (opt[strlen(opt) - 1] == '=') {
303 if (!dhcpcd_config_set_static(&config, opt, val))
304 qCritical("dhcpcd_config_set_static: %s",
309 if (!dhcpcd_config_set(&config, opt, val))
310 qCritical("dhcpcd_config_set: %s",
322 bool DhcpcdPreferences::makeConfig()
324 const char ns[] = "", *val;
327 a = autoConf->isChecked();
329 if (iface && iface->flags & IFF_POINTOPOINT)
330 setOption("ip_address=", a ? NULL : ns, &ret);
333 setOption("inform", a ? val : NULL, &ret);
334 setOption("ip_address=", a ? NULL : val, &ret);
337 val = getString(router);
338 setOption("routers=", val, &ret);
340 val = getString(rdnss);
341 setOption("domain_name_servers=", val, &ret);
343 val = getString(dnssl);
344 setOption("domain_search=", val, &ret);
349 bool DhcpcdPreferences::writeConfig(bool *cancel)
352 switch (QMessageBox::question(this, tr("Save Configuration"),
353 tr("Do you want to save your changes?"),
354 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel)) {
355 case QMessageBox::Cancel:
358 case QMessageBox::Discard:
366 DHCPCD_CONNECTION *con = parent->getConnection();
368 qCritical("failed to make config");
371 if (!dhcpcd_config_write(con, eWhat, eBlock, config)) {
372 qCritical("dhcpcd_config_write: %s", strerror(errno));
373 QMessageBox::critical(parent,
374 tr("Failed to write configuration"),
375 tr("Failed to write configuration:\n\n%1: %2")
376 .arg(dhcpcd_cffile(con))
377 .arg(strerror(errno)));
381 /* Braces to avoid jump error */
383 QIcon icon = DhcpcdQt::getIcon("actions", "document-save");
384 blocks->setItemIcon(configIndex, icon);
389 /* Reload our config if there is a problem */
390 config = dhcpcd_config_read(con, eWhat, eBlock);
394 void DhcpcdPreferences::showBlock(const QString &txt)
398 if (changedConfig()) {
400 if (!writeConfig(&cancel))
408 eBlock = strdup(txt.toAscii());
410 dhcpcd_config_free(config);
412 DHCPCD_CONNECTION *con = parent->getConnection();
414 if (eBlock && eWhat) {
415 if (strcmp(eWhat, "interface") == 0)
416 iface = dhcpcd_get_if(con, eBlock, "link");
417 ip->setEnabled(iface == NULL ||
418 !(iface->flags & IFF_POINTOPOINT));
420 config = dhcpcd_config_read(con, eWhat, eBlock);
421 if (config == NULL && errno) {
425 qCritical("dhcpcd_config_read: %s", s);
426 QMessageBox::critical(this,
427 tr("Error reading configuration"),
428 tr("Error reading: ") + dhcpcd_cffile(con) +
437 configIndex = blocks->currentIndex();
440 bool enabled = dhcpcd_config_writeable(con) && eBlock != NULL;
441 autoConf->setEnabled(enabled);
442 ipSetup->setEnabled(enabled);
443 clear->setEnabled(enabled);
446 bool DhcpcdPreferences::tryRebind(const char *ifname)
449 if (dhcpcd_rebind(parent->getConnection(), ifname) == 0)
452 qCritical("dhcpcd_rebind: %s", strerror(errno));
453 QMessageBox::critical(this,
455 ifname ? tr("Failed to rebind interface %1: %2")
456 .arg(ifname).arg(strerror(errno)) :
457 tr("Failed to rebind: %1")
458 .arg(strerror(errno)));
462 void DhcpcdPreferences::rebind()
465 if (changedConfig()) {
467 writeConfig(&cancel);
472 DHCPCD_CONNECTION *con = parent->getConnection();
476 if (eBlock == NULL || strcmp(eWhat, "interface") == 0) {
477 worked = tryRebind(iface ? iface->ifname : NULL);
483 for (i = dhcpcd_interfaces(con); i; i = i->next) {
484 if (strcmp(i->type, "link") == 0 &&
485 (i->ssid && strcmp(i->ssid, eBlock) == 0))
488 if (!tryRebind(i->ifname))
493 QMessageBox::information(this,
494 tr("No matching interface"),
495 tr("No interface is bound to this SSID to rebind"));
504 void DhcpcdPreferences::tryClose()
507 if (changedConfig()) {
509 writeConfig(&cancel);