1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "bearermonitor.h"
52#include "sessionwidget.h"
53
54#include <QtCore/QDebug>
55
56#ifdef Q_OS_WIN
57#include <winsock2.h>
58#undef interface
59
60#ifndef NS_NLA
61#define NS_NLA 15
62#endif
63#endif
64
65BearerMonitor::BearerMonitor(QWidget *parent)
66: QWidget(parent)
67{
68 setupUi(this);
69 delete tabWidget->currentWidget();
70 sessionGroup->hide();
71 updateConfigurations();
72 onlineStateChanged(!manager.allConfigurations(QNetworkConfiguration::Active).isEmpty());
73 QNetworkConfiguration defaultConfiguration = manager.defaultConfiguration();
74 for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) {
75 QTreeWidgetItem *item = treeWidget->topLevelItem(i);
76
77 if (item->data(0, Qt::UserRole).toString() == defaultConfiguration.identifier()) {
78 treeWidget->setCurrentItem(item);
79 showConfigurationFor(item);
80 break;
81 }
82 }
83 connect(&manager, SIGNAL(onlineStateChanged(bool)), this ,SLOT(onlineStateChanged(bool)));
84 connect(&manager, SIGNAL(configurationAdded(const QNetworkConfiguration&)),
85 this, SLOT(configurationAdded(const QNetworkConfiguration&)));
86 connect(&manager, SIGNAL(configurationRemoved(const QNetworkConfiguration&)),
87 this, SLOT(configurationRemoved(const QNetworkConfiguration&)));
88 connect(&manager, SIGNAL(configurationChanged(const QNetworkConfiguration&)),
89 this, SLOT(configurationChanged(const QNetworkConfiguration)));
90 connect(&manager, SIGNAL(updateCompleted()), this, SLOT(updateConfigurations()));
91
92#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
93 connect(registerButton, SIGNAL(clicked()), this, SLOT(registerNetwork()));
94 connect(unregisterButton, SIGNAL(clicked()), this, SLOT(unregisterNetwork()));
95#else // Q_OS_WIN && !Q_OS_WINRT
96 nlaGroup->hide();
97#endif
98
99 connect(treeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)),
100 this, SLOT(createSessionFor(QTreeWidgetItem*)));
101
102 connect(treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
103 this, SLOT(showConfigurationFor(QTreeWidgetItem*)));
104
105 connect(newSessionButton, SIGNAL(clicked()),
106 this, SLOT(createNewSession()));
107 connect(deleteSessionButton, SIGNAL(clicked()),
108 this, SLOT(deleteSession()));
109 connect(scanButton, SIGNAL(clicked()),
110 this, SLOT(performScan()));
111
112 // Just in case update all configurations so that all
113 // configurations are up to date.
114 manager.updateConfigurations();
115}
116
117BearerMonitor::~BearerMonitor()
118{
119}
120
121static void updateItem(QTreeWidgetItem *item, const QNetworkConfiguration &config)
122{
123 item->setText(0, config.name());
124 item->setData(0, Qt::UserRole, config.identifier());
125
126 QFont font = item->font(1);
127 font.setBold((config.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active);
128 item->setFont(0, font);
129}
130
131void BearerMonitor::configurationAdded(const QNetworkConfiguration &config, QTreeWidgetItem *parent)
132{
133 if (!config.isValid())
134 return;
135
136 QTreeWidgetItem *item = new QTreeWidgetItem;
137 updateItem(item, config);
138
139 if (parent)
140 parent->addChild(item);
141 else
142 treeWidget->addTopLevelItem(item);
143
144 if (config.type() == QNetworkConfiguration::ServiceNetwork) {
145 const QList<QNetworkConfiguration> children = config.children();
146 for (const QNetworkConfiguration &child : children)
147 configurationAdded(child, item);
148 }
149}
150
151void BearerMonitor::configurationRemoved(const QNetworkConfiguration &config)
152{
153 for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) {
154 QTreeWidgetItem *item = treeWidget->topLevelItem(i);
155
156 if (item->data(0, Qt::UserRole).toString() == config.identifier()) {
157 delete item;
158 break;
159 }
160 }
161}
162
163void BearerMonitor::configurationChanged(const QNetworkConfiguration &config)
164{
165 for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) {
166 QTreeWidgetItem *item = treeWidget->topLevelItem(i);
167
168 if (item->data(0, Qt::UserRole).toString() == config.identifier()) {
169 updateItem(item, config);
170
171 if (config.type() == QNetworkConfiguration::ServiceNetwork)
172 updateSnapConfiguration(item, config);
173
174 if (item == treeWidget->currentItem())
175 showConfigurationFor(item);
176
177 break;
178 }
179 }
180}
181
182void BearerMonitor::updateSnapConfiguration(QTreeWidgetItem *parent, const QNetworkConfiguration &snap)
183{
184 QMap<QString, QTreeWidgetItem *> itemMap;
185 const QList<QTreeWidgetItem *> children = parent->takeChildren();
186 for (QTreeWidgetItem *item : children)
187 itemMap.insert(item->data(0, Qt::UserRole).toString(), item);
188
189 QList<QNetworkConfiguration> allConfigurations = snap.children();
190
191 while (!allConfigurations.isEmpty()) {
192 QNetworkConfiguration config = allConfigurations.takeFirst();
193
194 QTreeWidgetItem *item = itemMap.take(config.identifier());
195 if (item) {
196 updateItem(item, config);
197
198 parent->addChild(item);
199
200 if (config.type() == QNetworkConfiguration::ServiceNetwork)
201 updateSnapConfiguration(item, config);
202 } else {
203 configurationAdded(config, parent);
204 }
205 }
206
207 qDeleteAll(itemMap);
208}
209
210void BearerMonitor::updateConfigurations()
211{
212 progressBar->hide();
213 scanButton->show();
214
215 // Just in case update online state, on Symbian platform
216 // WLAN scan needs to be triggered initially to have their true state.
217 onlineStateChanged(manager.isOnline());
218
219 QList<QTreeWidgetItem *> items = treeWidget->findItems(QLatin1String("*"), Qt::MatchWildcard);
220 QMap<QString, QTreeWidgetItem *> itemMap;
221 while (!items.isEmpty()) {
222 QTreeWidgetItem *item = items.takeFirst();
223 itemMap.insert(item->data(0, Qt::UserRole).toString(), item);
224 }
225
226 QNetworkConfiguration defaultConfiguration = manager.defaultConfiguration();
227 QTreeWidgetItem *defaultItem = itemMap.take(defaultConfiguration.identifier());
228
229 if (defaultItem) {
230 updateItem(defaultItem, defaultConfiguration);
231
232 if (defaultConfiguration.type() == QNetworkConfiguration::ServiceNetwork)
233 updateSnapConfiguration(defaultItem, defaultConfiguration);
234 } else {
235 configurationAdded(defaultConfiguration);
236 }
237
238 QList<QNetworkConfiguration> allConfigurations = manager.allConfigurations();
239
240 while (!allConfigurations.isEmpty()) {
241 QNetworkConfiguration config = allConfigurations.takeFirst();
242
243 if (config.identifier() == defaultConfiguration.identifier())
244 continue;
245
246 QTreeWidgetItem *item = itemMap.take(config.identifier());
247 if (item) {
248 updateItem(item, config);
249
250 if (config.type() == QNetworkConfiguration::ServiceNetwork)
251 updateSnapConfiguration(item, config);
252 } else {
253 configurationAdded(config);
254 }
255 }
256
257 qDeleteAll(itemMap);
258}
259
260void BearerMonitor::onlineStateChanged(bool isOnline)
261{
262 if (isOnline)
263 onlineState->setText(tr("Online"));
264 else
265 onlineState->setText(tr("Offline"));
266}
267
268#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
269void BearerMonitor::registerNetwork()
270{
271 QTreeWidgetItem *item = treeWidget->currentItem();
272 if (!item) return;
273
274 QNetworkConfiguration configuration =
275 manager.configurationFromIdentifier(item->data(0, Qt::UserRole).toString());
276
277 const QString name = configuration.name();
278
279 qDebug() << "Registering" << name << "with system";
280
281 WSAQUERYSET networkInfo;
282 memset(&networkInfo, 0, sizeof(networkInfo));
283 networkInfo.dwSize = sizeof(networkInfo);
284 networkInfo.lpszServiceInstanceName = (LPWSTR)name.utf16();
285 networkInfo.dwNameSpace = NS_NLA;
286
287 if (WSASetService(&networkInfo, RNRSERVICE_REGISTER, 0) == SOCKET_ERROR)
288 qDebug() << "WSASetService(RNRSERVICE_REGISTER) returned" << WSAGetLastError();
289}
290
291void BearerMonitor::unregisterNetwork()
292{
293 QTreeWidgetItem *item = treeWidget->currentItem();
294 if (!item) return;
295
296 QNetworkConfiguration configuration =
297 manager.configurationFromIdentifier(item->data(0, Qt::UserRole).toString());
298
299 const QString name = configuration.name();
300
301 qDebug() << "Unregistering" << name << "with system";
302
303 WSAQUERYSET networkInfo;
304 memset(&networkInfo, 0, sizeof(networkInfo));
305 networkInfo.dwSize = sizeof(networkInfo);
306 networkInfo.lpszServiceInstanceName = (LPWSTR)name.utf16();
307 networkInfo.dwNameSpace = NS_NLA;
308
309 if (WSASetService(&networkInfo, RNRSERVICE_DELETE, 0) == SOCKET_ERROR)
310 qDebug() << "WSASetService(RNRSERVICE_DELETE) returned" << WSAGetLastError();
311}
312#endif // Q_OS_WIN && !Q_OS_WINRT
313
314void BearerMonitor::showConfigurationFor(QTreeWidgetItem *item)
315{
316 QString identifier;
317
318 if (item)
319 identifier = item->data(0, Qt::UserRole).toString();
320
321 QNetworkConfiguration conf = manager.configurationFromIdentifier(identifier);
322
323 switch (conf.state()) {
324 case QNetworkConfiguration::Active:
325 configurationState->setText(tr("Active"));
326 break;
327 case QNetworkConfiguration::Discovered:
328 configurationState->setText(tr("Discovered"));
329 break;
330 case QNetworkConfiguration::Defined:
331 configurationState->setText(tr("Defined"));
332 break;
333 case QNetworkConfiguration::Undefined:
334 configurationState->setText(tr("Undefined"));
335 break;
336 default:
337 configurationState->setText(QString());
338 }
339
340 switch (conf.type()) {
341 case QNetworkConfiguration::InternetAccessPoint:
342 configurationType->setText(tr("Internet Access Point"));
343 break;
344 case QNetworkConfiguration::ServiceNetwork:
345 configurationType->setText(tr("Service Network"));
346 break;
347 case QNetworkConfiguration::UserChoice:
348 configurationType->setText(tr("User Choice"));
349 break;
350 case QNetworkConfiguration::Invalid:
351 configurationType->setText(tr("Invalid"));
352 break;
353 default:
354 configurationType->setText(QString());
355 }
356
357 switch (conf.purpose()) {
358 case QNetworkConfiguration::UnknownPurpose:
359 configurationPurpose->setText(tr("Unknown"));
360 break;
361 case QNetworkConfiguration::PublicPurpose:
362 configurationPurpose->setText(tr("Public"));
363 break;
364 case QNetworkConfiguration::PrivatePurpose:
365 configurationPurpose->setText(tr("Private"));
366 break;
367 case QNetworkConfiguration::ServiceSpecificPurpose:
368 configurationPurpose->setText(tr("Service Specific"));
369 break;
370 default:
371 configurationPurpose->setText(QString());
372 }
373
374 configurationIdentifier->setText(conf.identifier());
375
376 configurationRoaming->setText(conf.isRoamingAvailable() ? tr("Available") : tr("Not available"));
377
378 configurationChildren->setText(QString::number(conf.children().count()));
379
380 configurationName->setText(conf.name());
381}
382
383void BearerMonitor::createSessionFor(QTreeWidgetItem *item)
384{
385 const QString identifier = item->data(0, Qt::UserRole).toString();
386
387 QNetworkConfiguration conf = manager.configurationFromIdentifier(identifier);
388
389 SessionWidget *session = new SessionWidget(conf);
390
391 tabWidget->addTab(session, conf.name());
392
393 sessionGroup->show();
394
395 sessionWidgets.append(session);
396}
397
398void BearerMonitor::createNewSession()
399{
400 QTreeWidgetItem *item = treeWidget->currentItem();
401 if (!item) return;
402
403 createSessionFor(item);
404}
405
406void BearerMonitor::deleteSession()
407{
408 SessionWidget *session = qobject_cast<SessionWidget *>(tabWidget->currentWidget());
409 if (session) {
410 sessionWidgets.removeAll(session);
411
412 delete session;
413
414 if (tabWidget->count() == 0)
415 sessionGroup->hide();
416 }
417}
418
419void BearerMonitor::performScan()
420{
421 scanButton->hide();
422 progressBar->show();
423 manager.updateConfigurations();
424}
425