Merge lp:~pete-woods/indicator-network/hotspot-management into lp:indicator-network/15.10

Proposed by Pete Woods on 2015-07-10
Status: Merged
Approved by: Pete Woods on 2015-08-10
Approved revision: 512
Merged at revision: 503
Proposed branch: lp:~pete-woods/indicator-network/hotspot-management
Merge into: lp:indicator-network/15.10
Diff against target: 1863 lines (+1534/-11)
16 files modified
data/com.ubuntu.connectivity1.NetworkingStatus.xml (+5/-0)
data/com.ubuntu.connectivity1.Private.xml (+22/-0)
data/nm-settings.xml (+214/-0)
debian/changelog (+7/-0)
src/connectivity-api/connectivity-qt/connectivityqt/connectivity.cpp (+93/-3)
src/connectivity-api/connectivity-qt/connectivityqt/connectivity.h (+35/-0)
src/indicator/CMakeLists.txt (+1/-0)
src/indicator/connectivity-service/connectivity-service.cpp (+106/-6)
src/indicator/connectivity-service/connectivity-service.h (+26/-0)
src/indicator/nmofono/hotspot-manager.cpp (+826/-0)
src/indicator/nmofono/hotspot-manager.h (+167/-0)
src/indicator/nmofono/manager-impl.cpp (+13/-1)
src/indicator/nmofono/manager-impl.h (+2/-0)
src/indicator/nmofono/manager.h (+3/-0)
src/qdbus-stubs/CMakeLists.txt (+13/-0)
tests/integration/indicator-network-test-base.cpp (+1/-1)
To merge this branch: bzr merge lp:~pete-woods/indicator-network/hotspot-management
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve on 2015-07-21
Indicator Applet Developers 2015-07-10 Pending
Review via email: mp+264431@code.launchpad.net

Commit Message

Add hotspot management.

Description of the Change

Add hotspot management.

To post a comment you must log in.
500. By Charles Kerr on 2015-07-27

drop build-dependency on g++-4.9 Edit Fixes: #1452327
Approved by: Pete Woods, PS Jenkins bot, Rodney Dawes

501. By CI Train Bot Account on 2015-07-27

Releasing 0.5.1+15.10.20150727-0ubuntu1

506. By Pete Woods on 2015-07-13

Only update the initialized property when both interfaces have been initalized

507. By Pete Woods on 2015-07-15

Add HotspotManager

508. By Pete Woods on 2015-07-15

Remove dead method

509. By Pete Woods on 2015-07-15

Initialize Priv data member in HotspotManager

510. By Pete Woods on 2015-07-21

Grab property values from the correct interface

511. By Pete Woods on 2015-07-21

Make HotspotManager more OO, e.g. use member variables instead of passing around state

512. By Pete Woods on 2015-07-28

Wire up reportError signal to public interface

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/com.ubuntu.connectivity1.NetworkingStatus.xml'
2--- data/com.ubuntu.connectivity1.NetworkingStatus.xml 2015-04-23 10:02:23 +0000
3+++ data/com.ubuntu.connectivity1.NetworkingStatus.xml 2015-07-28 08:25:09 +0000
4@@ -9,6 +9,11 @@
5 <property name="FlightMode" type="b" access="read"/>
6 <property name="WifiEnabled" type="b" access="read"/>
7
8+ <property name="HotspotSsid" type="ay" access="read"/>
9+ <property name="HotspotEnabled" type="b" access="read"/>
10+ <property name="HotspotMode" type="s" access="read"/>
11+ <property name="HotspotStored" type="b" access="read"/>
12+
13 <property name="UnstoppableOperationHappening" type="b" access="read"/>
14
15 </interface>
16
17=== modified file 'data/com.ubuntu.connectivity1.Private.xml'
18--- data/com.ubuntu.connectivity1.Private.xml 2015-04-22 10:06:53 +0000
19+++ data/com.ubuntu.connectivity1.Private.xml 2015-07-28 08:25:09 +0000
20@@ -18,6 +18,28 @@
21 <arg type="b" direction="in" name="enabled"/>
22 </method>
23
24+ <method name="SetHotspotSsid">
25+ <arg type="ay" direction="in" name="ssid"/>
26+ </method>
27+
28+ <method name="SetHotspotPassword">
29+ <arg type="s" direction="in" name="password"/>
30+ </method>
31+
32+ <method name="SetHotspotEnabled">
33+ <arg type="b" direction="in" name="enabled"/>
34+ </method>
35+
36+ <method name="SetHotspotMode">
37+ <arg type="s" direction="in" name="mode"/>
38+ </method>
39+
40+ <property name="HotspotPassword" type="s" access="read"/>
41+
42+ <signal name="ReportError">
43+ <arg type="i" direction="out" name="reason"/>
44+ </signal>
45+
46 </interface>
47 </node>
48
49
50=== added file 'data/nm-settings.xml'
51--- data/nm-settings.xml 1970-01-01 00:00:00 +0000
52+++ data/nm-settings.xml 2015-07-28 08:25:09 +0000
53@@ -0,0 +1,214 @@
54+<?xml version="1.0" encoding="UTF-8" ?>
55+
56+<node name="/org/freedesktop/NetworkManager/Settings" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
57+ <interface name="org.freedesktop.NetworkManager.Settings">
58+ <tp:docstring>
59+ The Settings interface allows clients to view and administrate the connections stored and used by NetworkManager.
60+ </tp:docstring>
61+
62+ <method name="ListConnections">
63+ <tp:docstring>
64+ List the saved network connections known to NetworkManager.
65+ </tp:docstring>
66+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_list_connections"/>
67+ <arg name="connections" type="ao" direction="out">
68+ <tp:docstring>
69+ List of connections.
70+ </tp:docstring>
71+ </arg>
72+ </method>
73+
74+ <method name="GetConnectionByUuid">
75+ <tp:docstring>
76+ Retrieve the object path of a connection, given that connection's UUID.
77+ </tp:docstring>
78+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_get_connection_by_uuid"/>
79+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
80+ <arg name="uuid" type="s" direction="in">
81+ <tp:docstring>
82+ The UUID to find the connection object path for.
83+ </tp:docstring>
84+ </arg>
85+ <arg name="connection" type="o" direction="out">
86+ <tp:docstring>
87+ The connection's object path.
88+ </tp:docstring>
89+ </arg>
90+ </method>
91+
92+ <method name="AddConnection">
93+ <tp:docstring>
94+ Add new connection and save it to disk. This operation does not start
95+ the network connection unless (1) device is idle and able to connect to
96+ the network described by the new connection, and (2) the connection
97+ is allowed to be started automatically.
98+ </tp:docstring>
99+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_add_connection"/>
100+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
101+ <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantDictMap"/>
102+ <arg name="connection" type="a{sa{sv}}" direction="in">
103+ <tp:docstring>
104+ Connection settings and properties.
105+ </tp:docstring>
106+ </arg>
107+ <arg name="path" type="o" direction="out">
108+ <tp:docstring>
109+ Object path of the new connection that was just added.
110+ </tp:docstring>
111+ </arg>
112+ </method>
113+
114+ <method name="AddConnectionUnsaved">
115+ <tp:docstring>
116+ Add new connection but do not save it to disk immediately. This
117+ operation does not start the network connection unless (1) device is
118+ idle and able to connect to the network described by the new connection,
119+ and (2) the connection is allowed to be started automatically.
120+
121+ Use the 'Save' method on the connection to save these changes
122+ to disk. Note that unsaved changes will be lost if the
123+ connection is reloaded from disk (either automatically on file
124+ change or due to an explicit ReloadConnections call).
125+ </tp:docstring>
126+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_add_connection_unsaved"/>
127+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
128+ <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantDictMap"/>
129+ <arg name="connection" type="a{sa{sv}}" direction="in">
130+ <tp:docstring>
131+ Connection settings and properties.
132+ </tp:docstring>
133+ </arg>
134+ <arg name="path" type="o" direction="out">
135+ <tp:docstring>
136+ Object path of the new connection that was just added.
137+ </tp:docstring>
138+ </arg>
139+ </method>
140+
141+ <method name="LoadConnections">
142+ <tp:docstring>
143+ Loads or reloads the indicated connections from disk. You
144+ should call this after making changes directly to an on-disk
145+ connection file to make sure that NetworkManager sees the
146+ changes. (If "monitor-connection-files" in NetworkManager.conf
147+ is "true", then this will have no real effect, but is
148+ harmless.) As with AddConnection(), this operation does not
149+ necessarily start the network connection.
150+ </tp:docstring>
151+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_load_connections"/>
152+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
153+ <arg name="filenames" type="as" direction="in">
154+ <tp:docstring>
155+ Array of paths to on-disk connection profiles in directories
156+ monitored by NetworkManager.
157+ </tp:docstring>
158+ </arg>
159+ <arg name="status" type="b" direction="out">
160+ <tp:docstring>
161+ Success or failure of the operation as a whole. True if
162+ NetworkManager at least tried to load the indicated
163+ connections, even if it did not succeed. False if an error
164+ occurred before trying to load the connections (eg,
165+ permission denied).
166+ </tp:docstring>
167+ </arg>
168+ <arg name="failures" type="as" direction="out">
169+ <tp:docstring>
170+ Paths of connection files that could not be loaded.
171+ </tp:docstring>
172+ </arg>
173+ </method>
174+
175+ <method name="ReloadConnections">
176+ <tp:docstring>
177+ Tells NetworkManager to reload all connection files from disk,
178+ including noticing any added or deleted connection files. By
179+ default, connections are re-read automatically any time they
180+ change, so you only need to use this command if you have set
181+ "monitor-connection-files=false" in NetworkManager.conf.
182+ </tp:docstring>
183+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_reload_connections"/>
184+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
185+ <arg name="status" type="b" direction="out">
186+ <tp:docstring>
187+ Success or failure.
188+ </tp:docstring>
189+ </arg>
190+ </method>
191+
192+ <method name="SaveHostname">
193+ <tp:docstring>
194+ Save the hostname to persistent configuration.
195+ </tp:docstring>
196+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_save_hostname"/>
197+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
198+ <arg name="hostname" type="s" direction="in">
199+ <tp:docstring>
200+ The hostname to save to persistent configuration. If blank, the persistent hostname is cleared.
201+ </tp:docstring>
202+ </arg>
203+ </method>
204+
205+ <property name="Connections" type="ao" access="read">
206+ <tp:docstring>
207+ List of object paths of available network connection profiles.
208+ </tp:docstring>
209+ </property>
210+
211+ <property name="Hostname" type="s" access="read">
212+ <tp:docstring>
213+ The machine hostname stored in persistent configuration.
214+ </tp:docstring>
215+ </property>
216+
217+ <property name="CanModify" type="b" access="read">
218+ <tp:docstring>
219+ If true, adding and modifying connections is supported.
220+ </tp:docstring>
221+ </property>
222+
223+ <signal name="PropertiesChanged">
224+ <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
225+ <arg name="properties" type="a{sv}" tp:type="String_Variant_Map">
226+ <tp:docstring>
227+ A dictionary mapping property names to variant boxed values
228+ </tp:docstring>
229+ </arg>
230+ </signal>
231+
232+ <signal name="NewConnection">
233+ <tp:docstring>
234+ Emitted when a new connection has been added after NetworkManager has
235+ started up and initialized. This signal is not emitted for connections
236+ read while starting up, because NetworkManager's D-Bus service is only
237+ available after all connections have been read, and to prevent spamming
238+ listeners with too many signals at one time. To retrieve the initial
239+ connection list, call the ListConnections() method once, and then listen
240+ for individual Settings.NewConnection and Settings.Connection.Deleted
241+ signals for further updates.
242+ </tp:docstring>
243+ <arg name="connection" type="o">
244+ <tp:docstring>
245+ Object path of the new connection.
246+ </tp:docstring>
247+ </arg>
248+ </signal>
249+
250+ <signal name="ConnectionRemoved">
251+ <tp:docstring>
252+ Emitted when a connection is no longer available. This happens when
253+ the connection is deleted or if it is no longer accessible by any of
254+ the system's logged-in users. After receipt of this signal, the
255+ connection no longer exists and cannot be used. Also see the
256+ Settings.Connection.Removed signal.
257+ </tp:docstring>
258+ <arg name="connection" type="o">
259+ <tp:docstring>
260+ Object path of the removed connection.
261+ </tp:docstring>
262+ </arg>
263+ </signal>
264+
265+ </interface>
266+</node>
267+
268
269=== modified file 'debian/changelog'
270--- debian/changelog 2015-07-27 18:07:08 +0000
271+++ debian/changelog 2015-07-28 08:25:09 +0000
272@@ -1,3 +1,10 @@
273+indicator-network (0.5.2-0ubuntu1) UNRELEASED; urgency=medium
274+
275+ [ Pete Woods ]
276+ * Add hotspot management.
277+
278+ -- Pete Woods <pete.woods@canonical.com> Fri, 10 Jul 2015 15:44:04 +0100
279+
280 indicator-network (0.5.1+15.10.20150727-0ubuntu1) wily; urgency=medium
281
282 [ CI Train Bot ]
283
284=== modified file 'src/connectivity-api/connectivity-qt/connectivityqt/connectivity.cpp'
285--- src/connectivity-api/connectivity-qt/connectivityqt/connectivity.cpp 2015-05-06 08:24:47 +0000
286+++ src/connectivity-api/connectivity-qt/connectivityqt/connectivity.cpp 2015-07-28 08:25:09 +0000
287@@ -45,6 +45,8 @@
288
289 shared_ptr<internal::DBusPropertyCache> m_propertyCache;
290
291+ shared_ptr<internal::DBusPropertyCache> m_writePropertyCache;
292+
293 shared_ptr<ComUbuntuConnectivity1NetworkingStatusInterface> m_readInterface;
294
295 shared_ptr<ComUbuntuConnectivity1PrivateInterface> m_writeInterface;
296@@ -85,6 +87,14 @@
297 }
298
299 public Q_SLOTS:
300+ void interfaceInitialized()
301+ {
302+ // If both interfaces have been initialized then we're good to go
303+ if (p.isInitialized())
304+ {
305+ Q_EMIT p.initialized();
306+ }
307+ }
308
309 void propertyChanged(const QString& name, const QVariant& value)
310 {
311@@ -112,6 +122,26 @@
312 Q_EMIT p.statusUpdated(status);
313 Q_EMIT p.onlineUpdated(status == Status::Online);
314 }
315+ else if (name == "HotspotEnabled")
316+ {
317+ Q_EMIT p.hotspotEnabledUpdated(value.toBool());
318+ }
319+ else if (name == "HotspotSsid")
320+ {
321+ Q_EMIT p.hotspotSsidUpdated(value.toByteArray());
322+ }
323+ else if (name == "HotspotPassword")
324+ {
325+ Q_EMIT p.hotspotPasswordUpdated(value.toString());
326+ }
327+ else if (name == "HotspotMode")
328+ {
329+ Q_EMIT p.hotspotModeUpdated(value.toString());
330+ }
331+ else if (name == "HotspotStored")
332+ {
333+ Q_EMIT p.hotspotStoredUpdated(value.toBool());
334+ }
335 }
336 };
337
338@@ -136,6 +166,16 @@
339 DBusTypes::DBUS_NAME, DBusTypes::PRIVATE_PATH,
340 d->m_sessionConnection);
341
342+ d->m_writePropertyCache = make_shared<internal::DBusPropertyCache>(
343+ DBusTypes::DBUS_NAME, DBusTypes::PRIVATE_INTERFACE,
344+ DBusTypes::PRIVATE_PATH, sessionConnection);
345+ connect(d->m_writePropertyCache.get(),
346+ &internal::DBusPropertyCache::propertyChanged, d.get(),
347+ &Priv::propertyChanged);
348+ connect(d->m_writePropertyCache.get(),
349+ &internal::DBusPropertyCache::initialized, d.get(),
350+ &Connectivity::Priv::interfaceInitialized);
351+
352 d->m_propertyCache = make_shared<internal::DBusPropertyCache>(
353 DBusTypes::DBUS_NAME, DBusTypes::SERVICE_INTERFACE,
354 DBusTypes::SERVICE_PATH, sessionConnection);
355@@ -143,8 +183,12 @@
356 &internal::DBusPropertyCache::propertyChanged, d.get(),
357 &Priv::propertyChanged);
358 connect(d->m_propertyCache.get(),
359- &internal::DBusPropertyCache::initialized, this,
360- &Connectivity::initialized);
361+ &internal::DBusPropertyCache::initialized, d.get(),
362+ &Connectivity::Priv::interfaceInitialized);
363+
364+ connect(d->m_writeInterface.get(),
365+ &ComUbuntuConnectivity1PrivateInterface::ReportError, this,
366+ &Connectivity::reportError);
367 }
368
369 Connectivity::~Connectivity()
370@@ -188,7 +232,8 @@
371
372 bool Connectivity::isInitialized() const
373 {
374- return d->m_propertyCache->isInitialized();
375+ return d->m_propertyCache->isInitialized()
376+ && d->m_writePropertyCache->isInitialized();
377 }
378
379 void Connectivity::setFlightMode(bool enabled)
380@@ -201,6 +246,51 @@
381 d->m_writeInterface->SetWifiEnabled(enabled);
382 }
383
384+QByteArray Connectivity::hotspotSsid() const
385+{
386+ return d->m_propertyCache->get("HotspotSsid").toByteArray();
387+}
388+
389+QString Connectivity::hotspotPassword() const
390+{
391+ return d->m_writePropertyCache->get("HotspotPassword").toString();
392+}
393+
394+bool Connectivity::hotspotEnabled() const
395+{
396+ return d->m_propertyCache->get("HotspotEnabled").toBool();
397+}
398+
399+QString Connectivity::hotspotMode() const
400+{
401+ return d->m_propertyCache->get("HotspotMode").toString();
402+}
403+
404+bool Connectivity::hotspotStored() const
405+{
406+ return d->m_propertyCache->get("HotspotStored").toBool();
407+}
408+
409+void Connectivity::setHotspotSsid(const QByteArray& ssid)
410+{
411+ d->m_writeInterface->SetHotspotSsid(ssid);
412+}
413+
414+void Connectivity::setHotspotPassword(const QString& password)
415+{
416+ d->m_writeInterface->SetHotspotPassword(password);
417+}
418+
419+void Connectivity::setHotspotEnabled(bool enabled)
420+{
421+ d->m_writeInterface->SetHotspotEnabled(enabled);
422+}
423+
424+void Connectivity::setHotspotMode(const QString& mode)
425+{
426+ d->m_writeInterface->SetHotspotMode(mode);
427+}
428+
429 }
430
431 #include "connectivity.moc"
432
433=== modified file 'src/connectivity-api/connectivity-qt/connectivityqt/connectivity.h'
434--- src/connectivity-api/connectivity-qt/connectivityqt/connectivity.h 2015-05-06 08:24:47 +0000
435+++ src/connectivity-api/connectivity-qt/connectivityqt/connectivity.h 2015-07-28 08:25:09 +0000
436@@ -94,6 +94,21 @@
437 Q_PROPERTY(bool UnstoppableOperationHappening READ unstoppableOperationHappening NOTIFY unstoppableOperationHappeningUpdated)
438 bool unstoppableOperationHappening() const;
439
440+ Q_PROPERTY(QByteArray hotspotSsid READ hotspotSsid WRITE setHotspotSsid NOTIFY hotspotSsidUpdated)
441+ QByteArray hotspotSsid() const;
442+
443+ Q_PROPERTY(QString hotspotPassword READ hotspotPassword WRITE setHotspotPassword NOTIFY hotspotPasswordUpdated)
444+ QString hotspotPassword() const;
445+
446+ Q_PROPERTY(bool hotspotEnabled READ hotspotEnabled WRITE setHotspotEnabled NOTIFY hotspotEnabledUpdated)
447+ bool hotspotEnabled() const;
448+
449+ Q_PROPERTY(QString hotspotMode READ hotspotMode WRITE setHotspotMode NOTIFY hotspotModeUpdated)
450+ QString hotspotMode() const;
451+
452+ Q_PROPERTY(bool hotspotStored READ hotspotStored NOTIFY hotspotStoredUpdated)
453+ bool hotspotStored() const;
454+
455 Q_PROPERTY(bool Initialized READ isInitialized NOTIFY initialized)
456 bool isInitialized() const;
457
458@@ -102,6 +117,14 @@
459
460 void setwifiEnabled(bool enabled);
461
462+ void setHotspotEnabled(bool active);
463+
464+ void setHotspotSsid(const QByteArray& ssid);
465+
466+ void setHotspotPassword(const QString& password);
467+
468+ void setHotspotMode(const QString& mode);
469+
470 Q_SIGNALS:
471 void flightModeUpdated(bool);
472
473@@ -117,6 +140,18 @@
474
475 void unstoppableOperationHappeningUpdated(bool);
476
477+ void hotspotSsidUpdated(const QByteArray& name);
478+
479+ void hotspotPasswordUpdated(const QString& password);
480+
481+ void hotspotEnabledUpdated(bool);
482+
483+ void hotspotModeUpdated(const QString& mode);
484+
485+ void hotspotStoredUpdated(bool);
486+
487+ void reportError(int reason);
488+
489 void initialized();
490
491 protected:
492
493=== modified file 'src/indicator/CMakeLists.txt'
494--- src/indicator/CMakeLists.txt 2015-05-12 09:07:46 +0000
495+++ src/indicator/CMakeLists.txt 2015-07-28 08:25:09 +0000
496@@ -26,6 +26,7 @@
497 set(NETWORK_SERVICE_SOURCES
498 ${NETWORK_SERVICE_HEADERS}
499
500+ nmofono/hotspot-manager.cpp
501 nmofono/kill-switch.cpp
502 nmofono/manager.cpp
503 nmofono/manager-impl.cpp
504
505=== modified file 'src/indicator/connectivity-service/connectivity-service.cpp'
506--- src/indicator/connectivity-service/connectivity-service.cpp 2015-05-06 08:24:47 +0000
507+++ src/indicator/connectivity-service/connectivity-service.cpp 2015-07-28 08:25:09 +0000
508@@ -49,7 +49,8 @@
509 {
510 }
511
512- void notifyPropertyChanged( const QString& path,
513+ void notifyPropertyChanged( const QObject& o,
514+ const QString& path,
515 const QString& interface,
516 const QStringList& propertyNames )
517 {
518@@ -61,7 +62,7 @@
519 QVariantMap changedProps;
520 for(const auto& propertyName: propertyNames)
521 {
522- changedProps.insert(propertyName, p.property(qPrintable(propertyName)));
523+ changedProps.insert(propertyName, o.property(qPrintable(propertyName)));
524 }
525 signal << changedProps;
526 signal << QStringList();
527@@ -71,25 +72,69 @@
528 public Q_SLOTS:
529 void flightModeUpdated()
530 {
531- notifyPropertyChanged(DBusTypes::SERVICE_PATH,
532+ notifyPropertyChanged(p,
533+ DBusTypes::SERVICE_PATH,
534 DBusTypes::SERVICE_INTERFACE,
535 { "FlightMode" });
536 }
537
538 void wifiEnabledUpdated()
539 {
540- notifyPropertyChanged(DBusTypes::SERVICE_PATH,
541+ notifyPropertyChanged(p,
542+ DBusTypes::SERVICE_PATH,
543 DBusTypes::SERVICE_INTERFACE,
544 { "WifiEnabled" });
545 }
546
547 void unstoppableOperationHappeningUpdated()
548 {
549- notifyPropertyChanged(DBusTypes::SERVICE_PATH,
550+ notifyPropertyChanged(p,
551+ DBusTypes::SERVICE_PATH,
552 DBusTypes::SERVICE_INTERFACE,
553 { "UnstoppableOperationHappening" });
554 }
555
556+ void hotspotSsidUpdated()
557+ {
558+ notifyPropertyChanged(p,
559+ DBusTypes::SERVICE_PATH,
560+ DBusTypes::SERVICE_INTERFACE,
561+ { "HotspotSsid" });
562+ }
563+
564+ void hotspotEnabledUpdated()
565+ {
566+ notifyPropertyChanged(p,
567+ DBusTypes::SERVICE_PATH,
568+ DBusTypes::SERVICE_INTERFACE,
569+ { "HotspotEnabled" });
570+ }
571+
572+ void hotspotPasswordUpdated()
573+ {
574+ // Note that this is on the private object
575+ notifyPropertyChanged(*m_privateService,
576+ DBusTypes::PRIVATE_PATH,
577+ DBusTypes::PRIVATE_INTERFACE,
578+ { "HotspotPassword" });
579+ }
580+
581+ void hotspotModeUpdated()
582+ {
583+ notifyPropertyChanged(p,
584+ DBusTypes::SERVICE_PATH,
585+ DBusTypes::SERVICE_INTERFACE,
586+ { "HotspotMode" });
587+ }
588+
589+ void hotspotStoredUpdated()
590+ {
591+ notifyPropertyChanged(p,
592+ DBusTypes::SERVICE_PATH,
593+ DBusTypes::SERVICE_INTERFACE,
594+ { "HotspotStored" });
595+ }
596+
597 void updateNetworkingStatus()
598 {
599 QStringList changed;
600@@ -129,7 +174,8 @@
601
602 if (!changed.empty())
603 {
604- notifyPropertyChanged(DBusTypes::SERVICE_PATH,
605+ notifyPropertyChanged(p,
606+ DBusTypes::SERVICE_PATH,
607 DBusTypes::SERVICE_INTERFACE,
608 changed);
609 }
610@@ -151,6 +197,15 @@
611 connect(d->m_manager.get(), &Manager::wifiEnabledUpdated, d.get(), &Private::wifiEnabledUpdated);
612 connect(d->m_manager.get(), &Manager::unstoppableOperationHappeningUpdated, d.get(), &Private::unstoppableOperationHappeningUpdated);
613
614+ auto hotspotManager = d->m_manager->hotspotManager();
615+ connect(hotspotManager.get(), &HotspotManager::enabledChanged, d.get(), &Private::hotspotEnabledUpdated);
616+ connect(hotspotManager.get(), &HotspotManager::ssidChanged, d.get(), &Private::hotspotSsidUpdated);
617+ connect(hotspotManager.get(), &HotspotManager::passwordChanged, d.get(), &Private::hotspotPasswordUpdated);
618+ connect(hotspotManager.get(), &HotspotManager::modeChanged, d.get(), &Private::hotspotModeUpdated);
619+ connect(hotspotManager.get(), &HotspotManager::storedChanged, d.get(), &Private::hotspotStoredUpdated);
620+
621+ connect(hotspotManager.get(), &HotspotManager::reportError, d->m_privateService.get(), &PrivateService::ReportError);
622+
623 d->updateNetworkingStatus();
624
625 if (!d->m_connection.registerObject(DBusTypes::SERVICE_PATH, this))
626@@ -200,6 +255,26 @@
627 return d->m_manager->unstoppableOperationHappening();
628 }
629
630+bool ConnectivityService::hotspotEnabled() const
631+{
632+ return d->m_manager->hotspotManager()->enabled();
633+}
634+
635+QByteArray ConnectivityService::hotspotSsid() const
636+{
637+ return d->m_manager->hotspotManager()->ssid();
638+}
639+
640+QString ConnectivityService::hotspotMode() const
641+{
642+ return d->m_manager->hotspotManager()->mode();
643+}
644+
645+bool ConnectivityService::hotspotStored() const
646+{
647+ return d->m_manager->hotspotManager()->stored();
648+}
649+
650 PrivateService::PrivateService(ConnectivityService& parent) :
651 p(parent)
652 {
653@@ -227,6 +302,31 @@
654 p.d->m_manager->setWifiEnabled(enabled);
655 }
656
657+void PrivateService::SetHotspotEnabled(bool enabled)
658+{
659+ p.d->m_manager->hotspotManager()->setEnabled(enabled);
660+}
661+
662+void PrivateService::SetHotspotSsid(const QByteArray &ssid)
663+{
664+ p.d->m_manager->hotspotManager()->setSsid(ssid);
665+}
666+
667+void PrivateService::SetHotspotPassword(const QString &password)
668+{
669+ p.d->m_manager->hotspotManager()->setPassword(password);
670+}
671+
672+void PrivateService::SetHotspotMode(const QString &mode)
673+{
674+ p.d->m_manager->hotspotManager()->setMode(mode);
675+}
676+
677+QString PrivateService::hotspotPassword() const
678+{
679+ return p.d->m_manager->hotspotManager()->password();
680+}
681+
682 }
683
684 #include "connectivity-service.moc"
685
686=== modified file 'src/indicator/connectivity-service/connectivity-service.h'
687--- src/indicator/connectivity-service/connectivity-service.h 2015-04-23 10:02:23 +0000
688+++ src/indicator/connectivity-service/connectivity-service.h 2015-07-28 08:25:09 +0000
689@@ -59,6 +59,18 @@
690 Q_PROPERTY(bool UnstoppableOperationHappening READ unstoppableOperationHappening)
691 bool unstoppableOperationHappening() const;
692
693+ Q_PROPERTY(bool HotspotEnabled READ hotspotEnabled)
694+ bool hotspotEnabled() const;
695+
696+ Q_PROPERTY(QByteArray HotspotSsid READ hotspotSsid)
697+ QByteArray hotspotSsid() const;
698+
699+ Q_PROPERTY(bool HotspotStored READ hotspotStored)
700+ bool hotspotStored() const;
701+
702+ Q_PROPERTY(QString HotspotMode READ hotspotMode)
703+ QString hotspotMode() const;
704+
705 Q_SIGNALS:
706 void unlockAllModems();
707
708@@ -80,6 +92,9 @@
709
710 ~PrivateService() = default;
711
712+ Q_PROPERTY(QString HotspotPassword READ hotspotPassword)
713+ QString hotspotPassword() const;
714+
715 protected Q_SLOTS:
716 void UnlockAllModems();
717
718@@ -89,6 +104,17 @@
719
720 void SetWifiEnabled(bool enabled);
721
722+ void SetHotspotEnabled(bool enabled);
723+
724+ void SetHotspotSsid(const QByteArray &ssid);
725+
726+ void SetHotspotPassword(const QString &password);
727+
728+ void SetHotspotMode(const QString &mode);
729+
730+Q_SIGNALS:
731+ void ReportError(int reason);
732+
733 protected:
734 ConnectivityService& p;
735 };
736
737=== added file 'src/indicator/nmofono/hotspot-manager.cpp'
738--- src/indicator/nmofono/hotspot-manager.cpp 1970-01-01 00:00:00 +0000
739+++ src/indicator/nmofono/hotspot-manager.cpp 2015-07-28 08:25:09 +0000
740@@ -0,0 +1,826 @@
741+/*
742+ * Copyright (C) 2014, 2015 Canonical, Ltd.
743+ *
744+ * Authors:
745+ * Jussi Pakkanen <jussi.pakkanen@canonical.com>
746+ * Jonas G. Drange <jonas.drange@canonical.com>
747+ *
748+ * This program is free software: you can redistribute it and/or modify it
749+ * under the terms of the GNU General Public License version 3, as published
750+ * by the Free Software Foundation.
751+ *
752+ * This library is distributed in the hope that it will be useful, but WITHOUT
753+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
754+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
755+ * details.
756+ *
757+ * You should have received a copy of the GNU General Public License
758+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
759+*/
760+
761+#include <nmofono/hotspot-manager.h>
762+#include <NetworkManagerActiveConnectionInterface.h>
763+#include <NetworkManagerDeviceInterface.h>
764+#include <NetworkManagerInterface.h>
765+#include <NetworkManagerSettingsInterface.h>
766+#include <NetworkManagerSettingsConnectionInterface.h>
767+#include <URfkillInterface.h>
768+
769+#include <QStringList>
770+#include <QDBusReply>
771+#include <QtDebug>
772+#include <QDBusInterface>
773+#include <QDBusMetaType>
774+#include <NetworkManager.h>
775+
776+using namespace std;
777+
778+namespace
779+{
780+const static QString wpa_supplicant_service = "fi.w1.wpa_supplicant1";
781+const static QString wpa_supplicant_interface = "fi.w1.wpa_supplicant1";
782+const static QString wpa_supplicant_path = "/fi/w1/wpa_supplicant1";
783+}
784+
785+class HotspotManager::Priv: public QObject
786+{
787+ Q_SLOTS
788+public:
789+ Priv(HotspotManager& parent) :
790+ p(parent)
791+ {
792+ }
793+
794+ /**
795+ * Disables a hotspot.
796+ */
797+ void disable()
798+ {
799+ getHotspot();
800+ if (!m_hotspot)
801+ {
802+ qWarning() << "Could not find a hotspot setup to disable.\n";
803+ return;
804+ }
805+
806+ // Get new settings
807+ QVariantDictMap new_settings = createConnectionSettings(m_ssid,
808+ m_password,
809+ m_device_path,
810+ m_mode, false);
811+ auto updating = m_hotspot->Update(new_settings);
812+ updating.waitForFinished();
813+ if (!updating.isValid())
814+ {
815+ qCritical()
816+ << "Could not update connection with autoconnect=false: "
817+ << updating.error().message();
818+ }
819+
820+ auto active_connections = m_manager->activeConnections();
821+ for (const auto &active_connection : active_connections)
822+ {
823+ OrgFreedesktopNetworkManagerConnectionActiveInterface iface(
824+ NM_DBUS_SERVICE, active_connection.path(),
825+ m_manager->connection());
826+
827+ // Cast the property to a object path.
828+ QDBusObjectPath backingConnection = iface.connection();
829+
830+ // This active connection's Connection property was our hotspot,
831+ // so we will deactivate it. Note that we do not remove the hotspot,
832+ // as we are storing the ssid, password and mode on the connection.
833+ if (backingConnection.path() == m_hotspot->path())
834+ {
835+ // Deactivate the connection.
836+ auto deactivation = m_manager->DeactivateConnection(
837+ active_connection);
838+ deactivation.waitForFinished();
839+ if (!deactivation.isValid())
840+ {
841+ qCritical() << "Could not get deactivate connection: "
842+ << deactivation.error().message();
843+ }
844+ return;
845+ }
846+ }
847+ }
848+
849+ bool destroy()
850+ {
851+ if (!m_hotspot)
852+ {
853+ qCritical() << __PRETTY_FUNCTION__ << "Failed to destroy hotspot because it didn't exist";
854+ return false;
855+ }
856+
857+ // Subscribe to the connection proxy's Removed signal.
858+ connect(m_hotspot.get(),
859+ &OrgFreedesktopNetworkManagerSettingsConnectionInterface::Removed,
860+ this, &Priv::onRemoved);
861+
862+ auto del = m_hotspot->Delete();
863+ del.waitForFinished();
864+ if (del.isError())
865+ {
866+ qWarning() << __PRETTY_FUNCTION__ << "Failed to delete connection:" << del.error().message();
867+ }
868+ return !del.isError();
869+ }
870+
871+ void setStored(bool value)
872+ {
873+ if (m_stored != value)
874+ {
875+ m_stored = value;
876+ Q_EMIT p.storedChanged(value);
877+ }
878+ }
879+
880+ void setEnable(bool value)
881+ {
882+ if (m_enabled != value)
883+ {
884+ m_enabled = value;
885+ Q_EMIT p.enabledChanged(value);
886+ }
887+ }
888+
889+ void updateSettingsFromDbus()
890+ {
891+ bool active = isHotspotActive();
892+ setEnable(active);
893+
894+ QVariantDictMap settings = getConnectionSettings(*m_hotspot);
895+ const char wifi_key[] = "802-11-wireless";
896+ const char security_key[] = "802-11-wireless-security";
897+
898+ if (settings.find(wifi_key) != settings.end())
899+ {
900+ QByteArray ssid = settings[wifi_key]["ssid"].toByteArray();
901+ if (!ssid.isEmpty())
902+ {
903+ p.setSsid(ssid);
904+ }
905+
906+ QString mode = settings[wifi_key]["mode"].toString();
907+ if (!mode.isEmpty())
908+ {
909+ p.setMode(mode);
910+ }
911+ }
912+
913+ QVariantDictMap secrets = getConnectionSecrets(*m_hotspot,
914+ security_key);
915+
916+ if (secrets.find(security_key) != secrets.end())
917+ {
918+ QString pwd = secrets[security_key]["psk"].toString();
919+ if (!pwd.isEmpty())
920+ {
921+ p.setPassword(pwd);
922+ }
923+ }
924+ }
925+
926+ // wpa_supplicant interaction
927+
928+ bool isHybrisWlan()
929+ {
930+ QString program("getprop");
931+ QStringList arguments;
932+ arguments << "urfkill.hybris.wlan";
933+
934+ QProcess *getprop = new QProcess();
935+ getprop->start(program, arguments);
936+
937+ if (!getprop->waitForFinished())
938+ {
939+ qCritical() << "getprop process failed:" << getprop->errorString();
940+ delete getprop;
941+ return false;
942+ }
943+
944+ int index = getprop->readAllStandardOutput().indexOf("1");
945+ delete getprop;
946+
947+ // A non-negative integer means getprop returned 1
948+ return index >= 0;
949+ }
950+
951+ /**
952+ * True if changed successfully, or there was no need. Otherwise false.
953+ * Supported modes are 'p2p', 'sta' and 'ap'.
954+ */
955+ bool changeInterfaceFirmware(const QString& interface, const QString& mode)
956+ {
957+ // Not supported.
958+ if (mode == "adhoc")
959+ {
960+ return true;
961+ }
962+
963+ if (isHybrisWlan())
964+ {
965+ QDBusInterface wpasIface(wpa_supplicant_service,
966+ wpa_supplicant_path,
967+ wpa_supplicant_interface,
968+ m_manager->connection());
969+
970+ const QDBusObjectPath interface_path(interface);
971+
972+ // TODO(jgdx): We need to guard against calling this
973+ // when the interface is not soft blocked.
974+ auto set_interface = wpasIface.call(
975+ "SetInterfaceFirmware", QVariant::fromValue(interface_path),
976+ QVariant(mode));
977+
978+ if (set_interface.type() == QDBusMessage::ErrorMessage)
979+ {
980+ qCritical() << "Failed to change interface firmware:"
981+ << set_interface.errorMessage();
982+ return false;
983+ }
984+ else
985+ {
986+ return true;
987+ }
988+ }
989+
990+ // We had no need to change the firmware.
991+ return true;
992+ }
993+
994+ // wpa_supplicant interaction
995+
996+ // UrfKill interaction
997+
998+ /*
999+ * True if call went through and returned true.
1000+ */
1001+ bool setWifiBlock(bool block)
1002+ {
1003+ OrgFreedesktopURfkillInterface urfkill_dbus_interface(
1004+ DBusTypes::URFKILL_BUS_NAME, DBusTypes::URFKILL_OBJ_PATH,
1005+ m_manager->connection());
1006+
1007+ const unsigned int device_type = 1; /* wifi type */
1008+ auto reply = urfkill_dbus_interface.Block(device_type, block);
1009+ reply.waitForFinished();
1010+
1011+ if (reply.isError())
1012+ {
1013+ qCritical() << "Failed to block wifi" << reply.error().message();
1014+ return false;
1015+ }
1016+
1017+ if (!reply)
1018+ {
1019+ qCritical() << "URfkill Block call did not succeed";
1020+ }
1021+
1022+ return reply;
1023+ }
1024+
1025+ // UrfKill interaction
1026+
1027+ /**
1028+ * Helper that maps QStrings to other QVariantMaps, i.e.
1029+ * QMap<QString, QVariantMap>. QVariantMap is an alias for
1030+ * QMap<QString, QVariant>.
1031+ * See http://doc.qt.io/qt-5/qvariant.html#QVariantMap-typedef and
1032+ * https://developer.gnome.org/NetworkManager/0.9/spec.html
1033+ * #type-String_String_Variant_Map_Map
1034+ */
1035+ QVariantDictMap createConnectionSettings(
1036+ const QByteArray &ssid, const QString &password,
1037+ const QDBusObjectPath &devicePath, QString mode, bool autoConnect = true)
1038+ {
1039+ Q_UNUSED(devicePath);
1040+ QVariantDictMap connection;
1041+
1042+ QString s_ssid = QString::fromLatin1(ssid);
1043+ QString s_uuid = QUuid().createUuid().toString();
1044+ // Remove {} from the generated uuid.
1045+ s_uuid.remove(0, 1);
1046+ s_uuid.remove(s_uuid.size() - 1, 1);
1047+
1048+ QVariantMap wireless;
1049+ wireless[QStringLiteral("security")] = QVariant(QStringLiteral("802-11-wireless-security"));
1050+ wireless[QStringLiteral("ssid")] = QVariant(ssid);
1051+ wireless[QStringLiteral("mode")] = QVariant(mode);
1052+
1053+ connection["802-11-wireless"] = wireless;
1054+
1055+ QVariantMap connsettings;
1056+ connsettings[QStringLiteral("autoconnect")] = QVariant(autoConnect);
1057+ connsettings[QStringLiteral("id")] = QVariant(s_ssid);
1058+ connsettings[QStringLiteral("uuid")] = QVariant(s_uuid);
1059+ connsettings[QStringLiteral("type")] = QVariant(QStringLiteral("802-11-wireless"));
1060+ connection["connection"] = connsettings;
1061+
1062+ QVariantMap ipv4;
1063+ ipv4[QStringLiteral("addressess")] = QVariant(QStringList());
1064+ ipv4[QStringLiteral("dns")] = QVariant(QStringList());
1065+ ipv4[QStringLiteral("method")] = QVariant(QStringLiteral("shared"));
1066+ ipv4[QStringLiteral("routes")] = QVariant(QStringList());
1067+ connection["ipv4"] = ipv4;
1068+
1069+ QVariantMap ipv6;
1070+ ipv6[QStringLiteral("method")] = QVariant(QStringLiteral("ignore"));
1071+ connection["ipv6"] = ipv6;
1072+
1073+ QVariantMap security;
1074+ security[QStringLiteral("proto")] = QVariant(QStringList{ "rsn" });
1075+ security[QStringLiteral("pairwise")] = QVariant(QStringList{ "ccmp" });
1076+ security[QStringLiteral("group")] = QVariant(QStringList{ "ccmp" });
1077+ security[QStringLiteral("key-mgmt")] = QVariant(QStringLiteral("wpa-psk"));
1078+ security[QStringLiteral("psk")] = QVariant(password);
1079+ connection["802-11-wireless-security"] = security;
1080+
1081+ return connection;
1082+ }
1083+
1084+ /**
1085+ * Helper that returns a QMap<QString, QVariantMap> given a QDBusObjectPath.
1086+ * See https://developer.gnome.org/NetworkManager/0.9/spec.html
1087+ * #org.freedesktop.NetworkManager.Settings.Connection.GetSettings
1088+ */
1089+ QVariantDictMap getConnectionSettings (OrgFreedesktopNetworkManagerSettingsConnectionInterface& conn) {
1090+ auto connection_settings = conn.GetSettings();
1091+ connection_settings.waitForFinished();
1092+ return connection_settings.value();
1093+ }
1094+
1095+
1096+ /**
1097+ * Helper that returns a QMap<QString, QVariantMap> given a QDBusObjectPath.
1098+ * See https://developer.gnome.org/NetworkManager/0.9/spec.html
1099+ * #org.freedesktop.NetworkManager.Settings.Connection.GetSettings
1100+ */
1101+ QVariantDictMap getConnectionSecrets (OrgFreedesktopNetworkManagerSettingsConnectionInterface& conn,
1102+ const QString key)
1103+ {
1104+ auto connection_secrets = conn.GetSecrets(key);
1105+ connection_secrets.waitForFinished();
1106+ return connection_secrets.value();
1107+ }
1108+
1109+ /**
1110+ * Helper that adds a connection and returns the QDBusObjectPath
1111+ * of the newly created connection.
1112+ * See https://developer.gnome.org/NetworkManager/0.9/spec.html
1113+ * #org.freedesktop.NetworkManager.Settings.AddConnection
1114+ */
1115+ void addConnection()
1116+ {
1117+ QVariantDictMap connection = createConnectionSettings(m_ssid, m_password,
1118+ m_device_path, m_mode);
1119+
1120+ auto add_connection_reply = m_settings->AddConnection(connection);
1121+ add_connection_reply.waitForFinished();
1122+
1123+ if (add_connection_reply.isError())
1124+ {
1125+ qCritical() << "Failed to add connection: "
1126+ << add_connection_reply.error().message();
1127+ m_hotspot.reset();
1128+ return;
1129+ }
1130+ QDBusObjectPath connectionPath(add_connection_reply);
1131+
1132+ m_hotspot = make_shared<
1133+ OrgFreedesktopNetworkManagerSettingsConnectionInterface>(
1134+ NM_DBUS_SERVICE, connectionPath.path(), m_manager->connection());
1135+ }
1136+
1137+ /**
1138+ * Returns a QDBusObjectPath of a hotspot given a mode.
1139+ * Valid modes are 'p2p', 'ap' and 'adhoc'.
1140+ */
1141+ void getHotspot()
1142+ {
1143+ const char wifi_key[] = "802-11-wireless";
1144+
1145+ auto listed_connections = m_settings->ListConnections();
1146+ listed_connections.waitForFinished();
1147+
1148+ for (const auto &connection : listed_connections.value())
1149+ {
1150+ auto conn = make_shared<OrgFreedesktopNetworkManagerSettingsConnectionInterface>(
1151+ NM_DBUS_SERVICE, connection.path(),
1152+ m_manager->connection());
1153+
1154+ auto connection_settings = getConnectionSettings(*conn);
1155+
1156+ if (connection_settings.find(wifi_key) != connection_settings.end())
1157+ {
1158+ auto wifi_setup = connection_settings[wifi_key];
1159+ QString wifi_mode = wifi_setup["mode"].toString();
1160+
1161+ if (wifi_mode == m_mode)
1162+ {
1163+ m_hotspot = conn;
1164+ return;
1165+ }
1166+ }
1167+ }
1168+ m_hotspot.reset();
1169+ }
1170+
1171+ /**
1172+ * Returns a QDBusObjectPath of a wireless device. For now
1173+ * it returns the first device.
1174+ */
1175+ void getWirelessDevice ()
1176+ {
1177+ // find the first wlan adapter for now
1178+ auto reply1 = m_manager->GetDevices();
1179+ reply1.waitForFinished();
1180+
1181+ if(!reply1.isValid()) {
1182+ qCritical() << "Could not get network device: "
1183+ << reply1.error().message();
1184+ m_device_path = QDBusObjectPath();
1185+ return;
1186+ }
1187+ auto devices = reply1.value();
1188+
1189+ QDBusObjectPath dev;
1190+ for (const auto &d : devices) {
1191+ OrgFreedesktopNetworkManagerDeviceInterface iface(NM_DBUS_SERVICE, d.path(), m_manager->connection());
1192+ auto type_v = iface.deviceType();
1193+
1194+ if (type_v == NM_DEVICE_TYPE_WIFI)
1195+ {
1196+ m_device_path = d;
1197+ return;
1198+ }
1199+ }
1200+ qCritical() << "Wireless device not found, hotspot functionality is inoperative.";
1201+ m_device_path = dev;
1202+ }
1203+
1204+ /**
1205+ * Helper to check if the hotspot on a given QDBusObjectPath is active
1206+ * or not. It checks if the Connection.Active [1] for the given
1207+ * path is in NetworkManager's ActiveConnections property [2].
1208+ * [1] https://developer.gnome.org/NetworkManager/0.9/spec.html
1209+ * #org.freedesktop.NetworkManager.Connection.Active
1210+ * [2] https://developer.gnome.org/NetworkManager/0.9/spec.html
1211+ * #org.freedesktop.NetworkManager
1212+ */
1213+ bool isHotspotActive ()
1214+ {
1215+ if (!m_hotspot)
1216+ {
1217+ return false;
1218+ }
1219+
1220+ QSet<QDBusObjectPath> active_relevant_connections;
1221+ auto active_connections = m_manager->activeConnections();
1222+ for (const auto &active_connection : active_connections)
1223+ {
1224+
1225+ // Active connection interface proxy. It might have a connection
1226+ // property we can use to deduce if this active connection represents
1227+ // our active hotspot.
1228+ OrgFreedesktopNetworkManagerConnectionActiveInterface active_connection_dbus_interface(
1229+ NM_DBUS_SERVICE, active_connection.path(),
1230+ m_manager->connection());
1231+
1232+ // Get the Connection property, if any.
1233+ auto connection_path =
1234+ active_connection_dbus_interface.connection();
1235+
1236+ // The object path is the same as the given hotspot path.
1237+ if (m_hotspot->path() == connection_path.path())
1238+ {
1239+ return true;
1240+ }
1241+ }
1242+
1243+ // No active connection had a Connection property equal to the
1244+ // given path, so return false.
1245+ return false;
1246+ }
1247+
1248+ void generatePassword()
1249+ {
1250+ static const std::string items("abcdefghijklmnopqrstuvwxyz01234567890");
1251+ const int password_length = 8;
1252+ std::string result;
1253+
1254+ for (int i = 0; i < password_length; i++)
1255+ {
1256+ result.push_back(items[std::rand() % items.length()]);
1257+ }
1258+
1259+ m_password = QString::fromStdString(result);
1260+ }
1261+
1262+public Q_SLOTS:
1263+ void onNewConnection(const QDBusObjectPath& path)
1264+ {
1265+ if (!m_hotspot)
1266+ {
1267+ return;
1268+ }
1269+
1270+ // The new connection is the same as the stored hotspot path.
1271+ if (path.path() == m_hotspot->path())
1272+ {
1273+ // If a new hotspot was added, it is also given that
1274+ // Wi-Fi has been soft blocked. We can now unblock Wi-Fi
1275+ // and let NetworkManager pick up the newly created
1276+ // connection.
1277+ bool unblocked = setWifiBlock(false);
1278+ if (!unblocked)
1279+ {
1280+ // "The device could not be readied for configuration"
1281+ Q_EMIT p.reportError(5);
1282+ }
1283+ else
1284+ {
1285+ // We successfully unblocked the Wi-Fi, so set m_enable to true.
1286+ setEnable(true);
1287+ }
1288+
1289+ // This also mean we have successfully created a hotspot connection
1290+ // object in NetworkManager, so m_stored should now be true.
1291+ setStored(true);
1292+ }
1293+ }
1294+
1295+
1296+ void onRemoved()
1297+ {
1298+ m_hotspot.reset();
1299+
1300+ // The UI does not support direct deletion of a hotspot, and given how
1301+ // hotspots currently work, every time we want to re-use a hotspot, we
1302+ // delete it an add a new one.
1303+ // Thus, if a hotspot was deleted, we now create a new one.
1304+ addConnection();
1305+
1306+ // We could not add a connection, so report, disable and unblock.
1307+ if (!m_hotspot)
1308+ {
1309+ qWarning() << __PRETTY_FUNCTION__ << " Adding connection failed";
1310+ // Emit "Unknown Error".
1311+ Q_EMIT p.reportError(0);
1312+ setEnable(false);
1313+ setWifiBlock(false);
1314+ }
1315+ }
1316+
1317+ void onPropertiesChanged(const QVariantMap& properties)
1318+ {
1319+ // If we have no hotspot path, ignore changes in NetworkManager.
1320+ if (!m_hotspot)
1321+ {
1322+ return;
1323+ }
1324+
1325+ // Set flag so we know that ActiveConnections changed.
1326+ bool active_connection_changed = false;
1327+
1328+ for (QVariantMap::const_iterator iter = properties.begin();
1329+ iter != properties.end(); ++iter)
1330+ {
1331+ if (iter.key() == "ActiveConnections")
1332+ {
1333+ active_connection_changed = true;
1334+
1335+ const QDBusArgument args = qvariant_cast<QDBusArgument>(
1336+ iter.value());
1337+ if (args.currentType() == QDBusArgument::ArrayType)
1338+ {
1339+ args.beginArray();
1340+
1341+ while (!args.atEnd())
1342+ {
1343+ QDBusObjectPath path = qdbus_cast<QDBusObjectPath>(
1344+ args);
1345+
1346+ OrgFreedesktopNetworkManagerConnectionActiveInterface active_connection_dbus_interface(
1347+ NM_DBUS_SERVICE, path.path(),
1348+ m_manager->connection());
1349+
1350+ QDBusObjectPath connection_path =
1351+ active_connection_dbus_interface.connection();
1352+
1353+ // We see our connection as being active, so we emit that is
1354+ // enabled and return.
1355+ if (connection_path.path() == m_hotspot->path())
1356+ {
1357+ setEnable(true);
1358+ return;
1359+ }
1360+ }
1361+ args.endArray();
1362+ }
1363+ }
1364+ }
1365+
1366+ // At this point ActiveConnections changed, but
1367+ // our hotspot was not in that list.
1368+ if (active_connection_changed)
1369+ {
1370+ setEnable(false);
1371+ }
1372+ }
1373+
1374+ // NetworkManager interaction
1375+
1376+public:
1377+ HotspotManager& p;
1378+
1379+ QString m_mode = "ap";
1380+ bool m_enabled = false;
1381+ bool m_stored = false;
1382+ QString m_password;
1383+ QByteArray m_ssid = "Ubuntu";
1384+
1385+ QDBusObjectPath m_device_path;
1386+
1387+ /**
1388+ * NetworkManager dbus interface proxy we will use to query
1389+ * against NetworkManager. See
1390+ * https://developer.gnome.org/NetworkManager/0.9/spec.html
1391+ * #org.freedesktop.NetworkManager
1392+ */
1393+ unique_ptr<OrgFreedesktopNetworkManagerInterface> m_manager;
1394+
1395+ /**
1396+ * NetworkManager Settings interface proxy we use to get
1397+ * the list of connections, as well as adding connections.
1398+ * See https://developer.gnome.org/NetworkManager/0.9/spec.html
1399+ * #org.freedesktop.NetworkManager.Settings
1400+ */
1401+ unique_ptr<OrgFreedesktopNetworkManagerSettingsInterface> m_settings;
1402+
1403+ shared_ptr<OrgFreedesktopNetworkManagerSettingsConnectionInterface> m_hotspot;
1404+};
1405+
1406+HotspotManager::HotspotManager(const QDBusConnection& connection, QObject *parent) :
1407+ QObject(parent), d(new Priv(*this))
1408+{
1409+ d->m_manager = make_unique<OrgFreedesktopNetworkManagerInterface>(
1410+ NM_DBUS_SERVICE, NM_DBUS_PATH, connection);
1411+ d->m_settings = make_unique<OrgFreedesktopNetworkManagerSettingsInterface>(
1412+ NM_DBUS_SERVICE, NM_DBUS_PATH_SETTINGS, connection);
1413+
1414+ d->generatePassword();
1415+ d->getWirelessDevice();
1416+
1417+ // Stored is false if hotspot path is empty.
1418+ d->getHotspot();
1419+ d->setStored(bool(d->m_hotspot));
1420+
1421+ if (d->m_stored)
1422+ {
1423+ d->updateSettingsFromDbus();
1424+ }
1425+
1426+ // Watches for new connections added to NetworkManager's Settings
1427+ // interface.
1428+ connect(d->m_settings.get(),
1429+ &OrgFreedesktopNetworkManagerSettingsInterface::NewConnection,
1430+ d.get(), &Priv::onNewConnection);
1431+
1432+ // Watches changes in NetworkManager
1433+ connect(d->m_manager.get(),
1434+ &OrgFreedesktopNetworkManagerInterface::PropertiesChanged, d.get(),
1435+ &Priv::onPropertiesChanged);
1436+}
1437+
1438+void HotspotManager::setEnabled(bool value)
1439+{
1440+ if (enabled() == value)
1441+ {
1442+ return;
1443+ }
1444+
1445+ bool blocked = d->setWifiBlock(true);
1446+
1447+ // Failed to soft block, here we revert the enabled setting.
1448+ if (!blocked)
1449+ {
1450+ // "The device could not be readied for configuration"
1451+ Q_EMIT reportError(5);
1452+ d->setEnable(false);
1453+ return;
1454+ }
1455+
1456+ // We are enabling a hotspot
1457+ if (value)
1458+ {
1459+ // If the SSID is empty, we report an error.
1460+ if (d->m_ssid.isEmpty())
1461+ {
1462+ qWarning() << __PRETTY_FUNCTION__ << " SSID was empty";
1463+ Q_EMIT reportError(1);
1464+ d->setEnable(false);
1465+ return;
1466+ }
1467+
1468+ bool changed = d->changeInterfaceFirmware("/", d->m_mode);
1469+ if (!changed)
1470+ {
1471+ // Necessary firmware for the device may be missing
1472+ qWarning() << __PRETTY_FUNCTION__ << " Could not change interface firmware";
1473+ Q_EMIT reportError(35);
1474+ d->setEnable(false);
1475+ d->setWifiBlock(false);
1476+ return;
1477+ }
1478+
1479+ if (d->m_stored)
1480+ {
1481+ // we defer enabling until old hotspot is deleted
1482+ // if we can delete the old one
1483+ // If not, unset stored flag and call this method.
1484+ if (!d->destroy())
1485+ {
1486+ d->setStored(false);
1487+ // recurse?
1488+ setEnabled(true);
1489+ d->setEnable(true);
1490+ }
1491+ }
1492+ else
1493+ {
1494+ // we defer enabling until new hotspot is created
1495+ d->addConnection();
1496+ if (!d->m_hotspot)
1497+ {
1498+ // Emit "Unknown Error".
1499+ qWarning() << __PRETTY_FUNCTION__ << " Could not create hotspot connection";
1500+ Q_EMIT reportError(0);
1501+ d->setEnable(false);
1502+ d->setWifiBlock(false);
1503+ }
1504+ }
1505+
1506+ }
1507+ else
1508+ {
1509+ // Disabling the hotspot.
1510+ d->disable();
1511+ d->setEnable(false);
1512+
1513+ bool unblocked = d->setWifiBlock(false);
1514+ if (!unblocked)
1515+ {
1516+ qWarning() << __PRETTY_FUNCTION__ << " Could not unblock WiFi";
1517+ // "The device could not be readied for configuration"
1518+ Q_EMIT reportError(5);
1519+ }
1520+ }
1521+
1522+}
1523+
1524+bool HotspotManager::enabled() const {
1525+ return d->m_enabled;
1526+}
1527+
1528+bool HotspotManager::stored() const {
1529+ return d->m_stored;
1530+}
1531+
1532+QByteArray HotspotManager::ssid() const {
1533+ return d->m_ssid;
1534+}
1535+
1536+void HotspotManager::setSsid(const QByteArray& value) {
1537+ if (d->m_ssid != value)
1538+ {
1539+ d->m_ssid = value;
1540+ Q_EMIT ssidChanged(value);
1541+ }
1542+}
1543+
1544+QString HotspotManager::password() const {
1545+ return d->m_password;
1546+}
1547+
1548+void HotspotManager::setPassword(const QString& value) {
1549+ if (d->m_password != value)
1550+ {
1551+ d->m_password = value;
1552+ Q_EMIT passwordChanged(value);
1553+ }
1554+}
1555+
1556+QString HotspotManager::mode() const {
1557+ return d->m_mode;
1558+}
1559+
1560+void HotspotManager::setMode(const QString& value) {
1561+ if (d->m_mode != value)
1562+ {
1563+ d->m_mode = value;
1564+ Q_EMIT modeChanged(value);
1565+ }
1566+}
1567
1568=== added file 'src/indicator/nmofono/hotspot-manager.h'
1569--- src/indicator/nmofono/hotspot-manager.h 1970-01-01 00:00:00 +0000
1570+++ src/indicator/nmofono/hotspot-manager.h 2015-07-28 08:25:09 +0000
1571@@ -0,0 +1,167 @@
1572+/*
1573+ * Copyright (C) 2014, 2015 Canonical, Ltd.
1574+ *
1575+ * Authors:
1576+ * Jussi Pakkanen <jussi.pakkanen@canonical.com>
1577+ * Jonas G. Drange <jonas.drange@canonical.com>
1578+ *
1579+ * This program is free software: you can redistribute it and/or modify it
1580+ * under the terms of the GNU General Public License version 3, as published
1581+ * by the Free Software Foundation.
1582+ *
1583+ * This library is distributed in the hope that it will be useful, but WITHOUT
1584+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1585+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
1586+ * details.
1587+ *
1588+ * You should have received a copy of the GNU General Public License
1589+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1590+*/
1591+
1592+#pragma once
1593+
1594+#include <QObject>
1595+#include <QDBusConnection>
1596+#include <memory>
1597+
1598+ /**
1599+ * HotspotManager API
1600+ * ==============================
1601+ *
1602+ * Methods
1603+ *
1604+ * Signals
1605+ * enabledChanged(bool enabled)
1606+ * Signal that gets emitted when the hotspot is disabled or enabled.
1607+ *
1608+ * storedChanged(bool stored)
1609+ * Signal that gets emitted when a hotspot was stored.
1610+ *
1611+ * ssidChanged(QByteArray ssid)
1612+ * Signal that gets emitted when the ssid of the hotspot was changed.
1613+ *
1614+ * passwordChanged(QString password)
1615+ * Signal that gets emitted when the password of the hotspot was changed.
1616+ *
1617+ * modeChanged(QString mode)
1618+ * Signal that gets emitted when the mode was changed.
1619+ *
1620+ * authChanged(QString auth)
1621+ *
1622+ * Note that none of these signal will be emitted if a change to the hotspot
1623+ * was made by anyone else than the HotspotManager. Right now, the canonical
1624+ * way to edit a hotspot, is through the hotspot manager.
1625+ *
1626+ *
1627+ * reportError(int reason)
1628+ * The reasons correspond to https://developer.gnome.org/
1629+ * NetworkManager/0.9/spec.html#type-NM_DEVICE_STATE_REASON
1630+ *
1631+ * Properties
1632+ * bool enabled [readwrite]
1633+ * Whether or not the hotspot is enabled.
1634+ *
1635+ * bool stored [readonly]
1636+ * Whether or not a hotspot is known to the hotspotmanager.
1637+ *
1638+ * QByteArray ssid [readwrite]
1639+ * The current SSID of the hotspot.
1640+ *
1641+ * QString auth [readwrite]
1642+ * The current authentication of the hotspot. The default for this property
1643+ * is "wpa-psk" and is currently the only supported scheme. WEP is unsupported
1644+ * by design, as is no scheme at all.
1645+ *
1646+ * TODO: Check/add support for wpa-eap
1647+ *
1648+ * QString password [readwrite]
1649+ * The current Pre-Shared-Key for the hotspot. If the key is 64-characters
1650+ * long, it must contain only hexadecimal characters and is interpreted as a
1651+ * hexadecimal WPA key. Otherwise, the key must be between 8 and 63 ASCII
1652+ * characters and is interpreted as a WPA passphrase.
1653+ *
1654+ * QString mode [readwrite, optional]
1655+ * The current hotspot mode. The default of this value is "ap", but can be
1656+ * set to "p2p" or "adhoc". "p2p" and "adhoc" is currently not fully supported.
1657+ *
1658+ * TODO: Complete support for adhoc and p2p modes.
1659+ */
1660+class HotspotManager : public QObject
1661+{
1662+ Q_OBJECT
1663+
1664+ Q_PROPERTY( bool enabled
1665+ READ enabled
1666+ WRITE setEnabled
1667+ NOTIFY enabledChanged)
1668+
1669+ Q_PROPERTY( QByteArray ssid
1670+ READ ssid
1671+ WRITE setSsid
1672+ NOTIFY ssidChanged)
1673+
1674+ Q_PROPERTY( QString password
1675+ READ password
1676+ WRITE setPassword
1677+ NOTIFY passwordChanged)
1678+
1679+ Q_PROPERTY( QString mode
1680+ READ mode
1681+ WRITE setMode
1682+ NOTIFY modeChanged)
1683+
1684+ Q_PROPERTY( bool stored
1685+ READ stored
1686+ NOTIFY storedChanged)
1687+
1688+public:
1689+ typedef std::shared_ptr<HotspotManager> SPtr;
1690+
1691+ explicit HotspotManager(const QDBusConnection& connection, QObject *parent = nullptr);
1692+
1693+ ~HotspotManager() = default;
1694+
1695+ bool enabled() const;
1696+
1697+ void setEnabled(bool);
1698+
1699+ bool stored() const;
1700+
1701+ QByteArray ssid() const;
1702+
1703+ QString password() const;
1704+
1705+ QString mode() const;
1706+
1707+Q_SIGNALS:
1708+ void enabledChanged(bool enabled);
1709+
1710+ void storedChanged(bool stored);
1711+
1712+ void ssidChanged(const QByteArray& ssid);
1713+
1714+ void passwordChanged(const QString& password);
1715+
1716+ void modeChanged(const QString& mode);
1717+
1718+ /*
1719+ * The mapping of code to string is taken from
1720+ * http://bazaar.launchpad.net/~vcs-imports/
1721+ * network-manager/trunk/view/head:/cli/src/common.c
1722+ *
1723+ * NetworkManager documentation: https://developer.gnome.org/
1724+ * NetworkManager/0.9/spec.html#type-NM_DEVICE_STATE_REASON
1725+ */
1726+ void reportError(int reason);
1727+
1728+public Q_SLOTS:
1729+ void setSsid(const QByteArray&);
1730+
1731+ void setPassword(const QString&);
1732+
1733+ void setMode(const QString&);
1734+
1735+private:
1736+ class Priv;
1737+ std::shared_ptr<Priv> d;
1738+};
1739
1740=== modified file 'src/indicator/nmofono/manager-impl.cpp'
1741--- src/indicator/nmofono/manager-impl.cpp 2015-06-18 12:28:05 +0000
1742+++ src/indicator/nmofono/manager-impl.cpp 2015-07-28 08:25:09 +0000
1743@@ -20,8 +20,11 @@
1744
1745 #include <nmofono/manager-impl.h>
1746 #include <nmofono/wifi/wifi-link-impl.h>
1747+#include <NetworkManagerActiveConnectionInterface.h>
1748+#include <NetworkManagerDeviceInterface.h>
1749 #include <NetworkManagerInterface.h>
1750-#include <NetworkManagerDeviceInterface.h>
1751+#include <NetworkManagerSettingsInterface.h>
1752+#include <NetworkManagerSettingsConnectionInterface.h>
1753
1754 #define slots
1755 #include <qofono-qt5/qofonomanager.h>
1756@@ -67,6 +70,8 @@
1757 SimUnlockDialog::Ptr m_unlockDialog;
1758 QList<wwan::Modem::Ptr> m_pendingUnlocks;
1759
1760+ HotspotManager::SPtr m_hotspotManager;
1761+
1762 Private(Manager& parent) :
1763 p(parent)
1764 {
1765@@ -238,6 +243,8 @@
1766 d->m_killSwitch = make_shared<KillSwitch>(systemConnection);
1767 connect(d->m_killSwitch.get(), &KillSwitch::stateChanged, d.get(), &Private::updateHasWifi);
1768
1769+ d->m_hotspotManager = make_shared<HotspotManager>(systemConnection);
1770+
1771 connect(d->nm.get(), &OrgFreedesktopNetworkManagerInterface::DeviceAdded, this, &ManagerImpl::device_added);
1772 QList<QDBusObjectPath> devices(d->nm->GetDevices());
1773 for(const auto &path : devices) {
1774@@ -550,6 +557,11 @@
1775 return d->m_ofonoLinks.values().toSet();
1776 }
1777
1778+HotspotManager::SPtr ManagerImpl::hotspotManager() const
1779+{
1780+ return d->m_hotspotManager;
1781+}
1782+
1783 }
1784
1785 #include "manager-impl.moc"
1786
1787=== modified file 'src/indicator/nmofono/manager-impl.h'
1788--- src/indicator/nmofono/manager-impl.h 2015-04-24 08:47:08 +0000
1789+++ src/indicator/nmofono/manager-impl.h 2015-07-28 08:25:09 +0000
1790@@ -66,6 +66,8 @@
1791 void unlockAllModems() override;
1792 void unlockModemByName(const QString &name) override;
1793
1794+ HotspotManager::SPtr hotspotManager() const;
1795+
1796 private Q_SLOTS:
1797 void device_added(const QDBusObjectPath &path);
1798 void device_removed(const QDBusObjectPath &path);
1799
1800=== modified file 'src/indicator/nmofono/manager.h'
1801--- src/indicator/nmofono/manager.h 2015-04-24 08:47:08 +0000
1802+++ src/indicator/nmofono/manager.h 2015-07-28 08:25:09 +0000
1803@@ -19,6 +19,7 @@
1804
1805 #pragma once
1806
1807+#include <nmofono/hotspot-manager.h>
1808 #include <nmofono/link.h>
1809 #include <nmofono/wifi/wifi-link.h>
1810 #include <nmofono/wwan/modem.h>
1811@@ -86,6 +87,8 @@
1812 Q_PROPERTY(bool unstoppableOperationHappening READ unstoppableOperationHappening NOTIFY unstoppableOperationHappeningUpdated)
1813 virtual bool unstoppableOperationHappening() const = 0;
1814
1815+ virtual HotspotManager::SPtr hotspotManager() const = 0;
1816+
1817 /// @private
1818 Q_PROPERTY(QSet<Link::Ptr> links READ links NOTIFY linksUpdated)
1819 virtual QSet<Link::Ptr> links() const = 0;
1820
1821=== modified file 'src/qdbus-stubs/CMakeLists.txt'
1822--- src/qdbus-stubs/CMakeLists.txt 2015-04-21 10:59:52 +0000
1823+++ src/qdbus-stubs/CMakeLists.txt 2015-07-28 08:25:09 +0000
1824@@ -29,6 +29,7 @@
1825 )
1826
1827 set_source_files_properties(
1828+ "${DATA_DIR}/nm-settings.xml"
1829 "${DATA_DIR}/nm-settings-connection.xml"
1830 "${DATA_DIR}/nm-manager.xml"
1831 "${DATA_DIR}/org.freedesktop.Notifications.xml"
1832@@ -99,6 +100,18 @@
1833
1834 qt5_add_dbus_interface(
1835 CONNECTIVITY_BACKEND_SRC
1836+ "${DATA_DIR}/nm-settings-connection.xml"
1837+ NetworkManagerSettingsConnectionInterface
1838+)
1839+
1840+qt5_add_dbus_interface(
1841+ CONNECTIVITY_BACKEND_SRC
1842+ "${DATA_DIR}/nm-settings.xml"
1843+ NetworkManagerSettingsInterface
1844+)
1845+
1846+qt5_add_dbus_interface(
1847+ CONNECTIVITY_BACKEND_SRC
1848 "${DATA_DIR}/org.freedesktop.Notifications.xml"
1849 NotificationsInterface
1850 )
1851
1852=== modified file 'tests/integration/indicator-network-test-base.cpp'
1853--- tests/integration/indicator-network-test-base.cpp 2015-07-07 08:29:34 +0000
1854+++ tests/integration/indicator-network-test-base.cpp 2015-07-28 08:25:09 +0000
1855@@ -180,7 +180,7 @@
1856 QString IndicatorNetworkTestBase::createAccessPoint(const QString& id, const QString& ssid, const QString& device, uchar strength,
1857 Secure secure, ApMode apMode, const QString& mac)
1858 {
1859- int secflags;
1860+ int secflags(NM_802_11_AP_SEC_NONE);
1861 if (secure == Secure::insecure)
1862 {
1863 secflags = NM_802_11_AP_SEC_NONE;

Subscribers

People subscribed via source and target branches