Merge lp:~nick-dedekind/indicator-network/simunlock.dialog into lp:indicator-network/13.10

Proposed by Nick Dedekind
Status: Merged
Approved by: Ted Gould
Approved revision: 291
Merged at revision: 299
Proposed branch: lp:~nick-dedekind/indicator-network/simunlock.dialog
Merge into: lp:indicator-network/13.10
Diff against target: 1038 lines (+755/-47)
10 files modified
CMakeLists.txt (+7/-1)
debian/control (+1/-0)
network/CMakeLists.txt (+17/-0)
network/device-mobile.vala (+118/-16)
network/mobile-sim-manager.vala (+545/-0)
network/network-action-manager.vala (+6/-24)
network/network-menu-service.vala (+3/-2)
network/network-menu.vala (+5/-4)
network/ofono.vala (+30/-0)
network/utils.vala (+23/-0)
To merge this branch: bzr merge lp:~nick-dedekind/indicator-network/simunlock.dialog
Reviewer Review Type Date Requested Status
Ted Gould (community) Approve
Michał Sawicz Approve
PS Jenkins bot (community) continuous-integration Approve
Pete Woods Pending
Review via email: mp+185810@code.launchpad.net

Commit message

SIM pin/puk unload menu & dialog notification.

Description of the change

SIM pin/puk unload menu & dialog notification.

To post a comment you must log in.
Revision history for this message
Pete Woods (pete-woods) wrote :

I would really like to see some tests for this along the lines of what I did for the secret agent (https://code.launchpad.net/~indicator-applet-developers/indicator-network/secret-agent/+merge/182898).

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> I would really like to see some tests for this along the lines of what I did
> for the secret agent (https://code.launchpad.net/~indicator-applet-developers
> /indicator-network/secret-agent/+merge/182898).

eh. This is so embedded with the mobile device now (ofono). Will need to extract all of that to enable testing. At this point I think we're beyond that. It's a blocker for v1.
2nd iteration?

Revision history for this message
Pete Woods (pete-woods) wrote :

> > I would really like to see some tests for this along the lines of what I did
> > for the secret agent (https://code.launchpad.net/~indicator-applet-
> developers
> > /indicator-network/secret-agent/+merge/182898).
>
> eh. This is so embedded with the mobile device now (ofono). Will need to
> extract all of that to enable testing. At this point I think we're beyond
> that. It's a blocker for v1.
> 2nd iteration?

That comment was quite some time ago. Feel free to hack away!

291. By Nick Dedekind

merged with trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

Yeah, this is working!

review: Approve
Revision history for this message
Ted Gould (ted) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-10-03 12:08:41 +0000
3+++ CMakeLists.txt 2013-10-10 15:57:20 +0000
4@@ -16,7 +16,7 @@
5 include(UseGSettings)
6
7 # Workaround for libexecdir on debian
8-if (EXISTS "/etc/debian_version")
9+if (EXISTS "/etc/debian_version")
10 set(CMAKE_INSTALL_LIBEXECDIR ${CMAKE_INSTALL_LIBDIR})
11 set(CMAKE_INSTALL_FULL_LIBEXECDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBEXECDIR}")
12 endif()
13@@ -41,6 +41,12 @@
14 )
15 include_directories(${NM_INCLUDE_DIRS})
16
17+set(NOTIFY_REQUIRED_VERSION 0.7.5)
18+pkg_check_modules(
19+ NOTIFY REQUIRED
20+ libnotify>=${NOTIFY_REQUIRED_VERSION}
21+)
22+include_directories(${NOTIFY_INCLUDE_DIRS})
23
24 find_package(Qt5Core REQUIRED)
25 include_directories(${Qt5Core_INCLUDE_DIRS})
26
27=== modified file 'debian/control'
28--- debian/control 2013-10-03 13:04:00 +0000
29+++ debian/control 2013-10-10 15:57:20 +0000
30@@ -10,6 +10,7 @@
31 libglib2.0-dev,
32 libnm-glib-dev (>= 0.9),
33 libnm-util-dev (>= 0.9),
34+ libnotify-dev,
35 libqmenumodel-dev,
36 libqtdbusmock1-dev,
37 libqtdbustest1-dev,
38
39=== modified file 'network/CMakeLists.txt'
40--- network/CMakeLists.txt 2013-10-08 04:00:49 +0000
41+++ network/CMakeLists.txt 2013-10-10 15:57:20 +0000
42@@ -13,6 +13,7 @@
43 vala_init(libnetwork
44 PACKAGES
45 libnm-glib
46+ libnotify
47 CUSTOM_VAPIS
48 "${CMAKE_CURRENT_SOURCE_DIR}/action-muxer.vapi"
49 "${CMAKE_CURRENT_SOURCE_DIR}/url-dispatcher.vapi"
50@@ -24,9 +25,14 @@
51 )
52
53 vala_add(libnetwork
54+ utils.vala
55+)
56+
57+vala_add(libnetwork
58 network-action-manager.vala
59 DEPENDS
60 ofono
61+ utils
62 )
63
64 vala_add(libnetwork
65@@ -40,6 +46,14 @@
66 settings-wifi
67 settings-airplane
68 network-action-manager
69+ mobile-sim-manager
70+)
71+
72+vala_add(libnetwork
73+ mobile-sim-manager.vala
74+ DEPENDS
75+ ofono
76+ utils
77 )
78
79 vala_add(libnetwork
80@@ -56,6 +70,7 @@
81 device-mobile.vala
82 DEPENDS
83 device-base
84+ mobile-sim-manager
85 )
86
87 vala_add(libnetwork
88@@ -117,6 +132,7 @@
89 network
90 ${GLIB_LIBRARIES}
91 ${NM_LIBRARIES}
92+ ${NOTIFY_LIBRARIES}
93 )
94
95 ###########################
96@@ -126,6 +142,7 @@
97 vala_init(network-service
98 PACKAGES
99 libnm-glib
100+ libnotify
101 libnetwork
102 DEPENDS
103 "${CMAKE_CURRENT_BINARY_DIR}/libnetwork.vapi"
104
105=== modified file 'network/device-mobile.vala'
106--- network/device-mobile.vala 2013-08-25 19:00:08 +0000
107+++ network/device-mobile.vala 2013-10-10 15:57:20 +0000
108@@ -22,11 +22,122 @@
109
110 namespace Network.Device
111 {
112+ internal class MobileMenu
113+ {
114+ private NM.Client client;
115+ private NM.DeviceModem device;
116+ private Menu apsmenu;
117+ private string action_prefix;
118+ private MobileSimManager mobilesimmanager;
119+
120+ private MenuItem device_item;
121+ private MenuItem settings_item;
122+ private MenuItem? unlock_sim_item = null;
123+
124+ public MobileMenu (NM.Client client, DeviceModem device, Menu global_menu, string action_prefix, bool show_enable, MobileSimManager mobilesimmanager)
125+ {
126+ this.client = client;
127+ this.device = device;
128+ this.apsmenu = global_menu;
129+ this.action_prefix = action_prefix;
130+ this.mobilesimmanager = mobilesimmanager;
131+
132+ if (show_enable) {
133+ device_item = create_item_for_mobile_device();
134+ this.apsmenu.append_item(device_item);
135+ }
136+
137+ settings_item = new MenuItem(_("Cellular settings…"), "indicator.global.settings::cellular");
138+ this.apsmenu.append_item(settings_item);
139+
140+ update_sim_lock_menu(mobilesimmanager.pin_required);
141+ mobilesimmanager.notify["pin-required"].connect((s, value) => {
142+ update_sim_lock_menu(mobilesimmanager.pin_required);
143+ });
144+ }
145+
146+ ~MobileMenu ()
147+ {
148+ }
149+
150+ private MenuItem create_item_for_mobile_device ()
151+ {
152+ var device_item = new MenuItem(_("Cellular"), action_prefix + ".device-enabled");
153+ device_item.set_attribute ("x-canonical-type" , "s", "com.canonical.indicator.switch");
154+
155+ return device_item;
156+ }
157+
158+ private void update_sim_lock_menu(bool pin_required)
159+ {
160+ string action_name = action_prefix + "unlock";
161+ debug(@"sim lock updated $(pin_required) - action $action_name");
162+ for (int i = 0; i < apsmenu.get_n_items(); i++)
163+ {
164+ string name;
165+
166+ if (!apsmenu.get_item_attribute (i, "action", "s", out name))
167+ continue;
168+ debug(@"update_sim_lock_menu action $name");
169+
170+ if (name == action_name) {
171+ if (!pin_required) {
172+ apsmenu.remove (i);
173+ }
174+ return;
175+ }
176+ }
177+
178+ if (pin_required) {
179+ unlock_sim_item = new MenuItem(_("Unlock SIM…"), action_name);
180+ apsmenu.insert_item (0, unlock_sim_item);
181+ } else {
182+ unlock_sim_item = null;
183+ }
184+ }
185+ }
186+
187+ internal class MobileActionManager
188+ {
189+ private SimpleActionGroup actions;
190+ private NM.Client client;
191+ private NM.DeviceModem device;
192+ private MobileSimManager mobilesimmanager;
193+ private SimpleAction unlock_action;
194+
195+ public MobileActionManager (SimpleActionGroup actions, NM.Client client, NM.DeviceModem device, MobileSimManager mobilesimmanager)
196+ {
197+ this.actions = actions;
198+ this.client = client;
199+ this.device = device;
200+ this.mobilesimmanager = mobilesimmanager;
201+
202+ unlock_action = new SimpleAction("unlock", null);
203+ unlock_action.activate.connect((ac,ps) => {
204+ if (mobilesimmanager.pin_unlocking) {
205+ debug(@"SIM unlock already in progress");
206+ return;
207+ }
208+ mobilesimmanager.send_unlock_notification();
209+ });
210+ actions.insert(unlock_action);
211+
212+ unlock_action.set_enabled(mobilesimmanager.pin_required && !mobilesimmanager.pin_unlocking);
213+ mobilesimmanager.notify["pin-required"].connect((s, value) => {
214+ unlock_action.set_enabled(mobilesimmanager.pin_required && !mobilesimmanager.pin_unlocking);
215+ });
216+ mobilesimmanager.notify["pin-unlocking"].connect((s, value) => {
217+ unlock_action.set_enabled(mobilesimmanager.pin_required && !mobilesimmanager.pin_unlocking);
218+ });
219+ }
220+ }
221+
222 public class Mobile : Base {
223- private GLib.MenuItem enabled_item;
224- private GLib.MenuItem settings_item;
225+ private MobileMenu mobilemenu;
226+ private MobileActionManager mobileactionmanager;
227+ private MobileSimManager mobilesimmanager;
228
229- public Mobile (NM.Client client, NM.DeviceModem device, GLibLocal.ActionMuxer muxer, bool show_enable) {
230+ public Mobile (NM.Client client, NM.DeviceModem device, GLibLocal.ActionMuxer muxer, bool show_enable, GLib.DBusConnection conn) {
231 GLib.Object(
232 client: client,
233 device: device,
234@@ -34,19 +145,9 @@
235 muxer: muxer
236 );
237
238- if (show_enable) {
239- enabled_item = new MenuItem(_("Cellular"), "indicator." + device.get_iface() + ".device-enabled");
240- enabled_item.set_attribute ("x-canonical-type" , "s", "com.canonical.indicator.switch");
241- _menu.append_item(enabled_item);
242- }
243-
244- settings_item = new MenuItem(_("Cellular settings…"), "indicator.global.settings::cellular");
245- _menu.append_item(settings_item);
246- }
247-
248- ~Mobile ()
249- {
250- muxer.remove(namespace);
251+ mobilesimmanager = new MobileSimManager(client, device, conn, this.namespace);
252+ mobilemenu = new MobileMenu(client, device, this._menu, "indicator." + this.namespace + ".", show_enable, mobilesimmanager);
253+ mobileactionmanager = new MobileActionManager(actions, client, device, mobilesimmanager);
254 }
255
256 protected override void disable_device ()
257@@ -61,4 +162,5 @@
258 device.set_autoconnect(true);
259 }
260 }
261+
262 }
263
264=== added file 'network/mobile-sim-manager.vala'
265--- network/mobile-sim-manager.vala 1970-01-01 00:00:00 +0000
266+++ network/mobile-sim-manager.vala 2013-10-10 15:57:20 +0000
267@@ -0,0 +1,545 @@
268+// vim: tabstop=4 noexpandtab shiftwidth=4 softtabstop=4
269+/*
270+ * Copyright 2013 Canonical Ltd.
271+ *
272+ * This program is free software; you can redistribute it and/or modify
273+ * it under the terms of the GNU General Public License as published by
274+ * the Free Software Foundation; version 3.
275+ *
276+ * This program is distributed in the hope that it will be useful,
277+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
278+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
279+ * GNU Lesser General Public License for more details.
280+ *
281+ * You should have received a copy of the GNU Lesser General Public License
282+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
283+ *
284+ * Authors:
285+ * Nick Dedekind <nick-dedekind@canonical.com
286+ */
287+
288+using NM;
289+using Notify;
290+
291+namespace Network
292+{
293+ public class MobileSimManager : GLib.Object
294+ {
295+ public bool sim_installed { get; private set; default = false; }
296+ public bool pin_required { get { return required_pin != "none" && required_pin != ""; } }
297+ public bool pin_unlocking { get; private set; default = false; }
298+
299+ private NM.Client client;
300+ private NM.DeviceModem device;
301+ private GLib.DBusConnection conn;
302+ private string namespace;
303+ private oFono.SIMManager? simmanager = null;
304+ private oFono.Modem? ofono_modem = null;
305+ private HashTable<string, uchar> retries = new HashTable<string, uchar>(str_hash, str_equal);
306+ private List<CurrentNotification?> notifications = new List<CurrentNotification?> ();
307+
308+ // Sim Unlocking
309+ private string _required_pin = "none";
310+ private string last_required_pin = "";
311+ private string puk_code = "";
312+ private string old_pin = "";
313+ private string new_pin = "";
314+ private int export_id = 0;
315+
316+ private const string APPLICATION_ID = "com.canonical.indicator.network";
317+ private const string SIM_UNLOCK_MENU_PATH = "/com/canonical/indicator/network/unlocksim";
318+ private const string SIM_UNLOCK_ACTION_PATH = "/com/canonical/indicator/network/unlocksim";
319+ private const string OFONO_ERROR_FAILED = "org.ofono.Error.Failed";
320+
321+ struct CurrentNotification {
322+ public int id;
323+ public Notification? notification;
324+ public uint unlock_menu_export_id;
325+ public uint unlock_actions_export_id;
326+ public Menu? unlock_menu;
327+ public SimpleActionGroup? unlock_actions;
328+
329+ public CurrentNotification() {
330+ this.id = 0;
331+ this.notification = null;
332+ this.unlock_menu_export_id = 0;
333+ this.unlock_actions_export_id = 0;
334+ this.unlock_menu = null;
335+ this.unlock_actions = null;
336+ }
337+ }
338+
339+ private string required_pin {
340+ get { return _required_pin; }
341+ set { if (_required_pin != value) { _required_pin = value; notify_property("pin-required"); } }
342+ }
343+
344+ delegate void PinCancelCallback ();
345+ delegate void PinEnteredCallback (string pin);
346+
347+ public MobileSimManager (NM.Client client, DeviceModem device, GLib.DBusConnection conn, string namespace)
348+ {
349+ this.client = client;
350+ this.device = device;
351+ this.conn = conn;
352+ this.namespace = namespace;
353+
354+ create_ofono_sim_manager();
355+ }
356+
357+ public bool send_unlock_notification ()
358+ {
359+ if (pin_required == false) {
360+ clear_stored_data();
361+ return false;
362+ }
363+
364+ if (send_unlock (required_pin == "puk" ? _("Please enter SIM PUK") : _("Please enter SIM PIN"),
365+ required_pin,
366+ required_pin == "puk" ? 8 : 4,
367+ pin_unlock_entered)) {
368+ debug(@"SIM Unlock: $required_pin");
369+ last_required_pin = required_pin;
370+ pin_unlocking = true;
371+ debug(@"PIN LOCKING: $pin_unlocking");
372+ return true;
373+ } else {
374+ debug(@"SIM unlock notification request failed");
375+ clear_stored_data();
376+ return false;
377+ }
378+ }
379+
380+ public bool send_change_pin_notification()
381+ {
382+ if (send_unlock(_("Please enter SIM PIN"), "pin", 4, pin_change_old_entered)) {
383+ debug(@"SIM change. Sent old pin request");
384+ return true;
385+ } else {
386+ debug(@"SIM change. Old pin notification failed");
387+ return false;
388+ }
389+ }
390+
391+ private bool send_unlock(string title, string? retry_type, int pin_length, PinEnteredCallback? pin_entered_callback)
392+ {
393+ string body = "";
394+ if (retry_type != null) {
395+ uchar pin_retries = 0;
396+ if (retries.lookup_extended(retry_type, null, out pin_retries)) {
397+ if (pin_retries > 1) {
398+ body = _(@"$(pin_retries) attempts remaining");
399+ } else if (pin_retries == 1) {
400+ body = _(@"$(pin_retries) attempt remaining");
401+ } else {
402+ debug(@"No pin retries remaining");
403+ send_fail_notification(_("No retries remaining"));
404+ return false;
405+ }
406+ }
407+ }
408+
409+ // set the export hints
410+ string exported_action_path = @"$(SIM_UNLOCK_ACTION_PATH)$(export_id)";
411+ string exported_menu_path = @"$(SIM_UNLOCK_MENU_PATH)$(export_id)";
412+ export_id++;
413+
414+ VariantBuilder menu_model_actions = new VariantBuilder (new VariantType ("a{sv}") );
415+ menu_model_actions.add ("{sv}", "notifications", new Variant.string (exported_action_path));
416+
417+ VariantBuilder menu_model_paths = new VariantBuilder (new VariantType ("a{sv}") );
418+ menu_model_paths.add ("{sv}", "busName", new Variant.string (APPLICATION_ID));
419+ menu_model_paths.add ("{sv}", "menuPath", new Variant.string (exported_menu_path));
420+ menu_model_paths.add ("{sv}", "actions", menu_model_actions.end ());
421+
422+ // create the menu
423+ var menu = new Menu ();
424+ var pin_unlock = new MenuItem ("", "notifications." + namespace + ".simunlock");
425+ pin_unlock.set_attribute ("x-canonical-type", "s", "com.canonical.snapdecision.pinlock");
426+ pin_unlock.set_attribute ("x-canonical-pin-length", "i", pin_length);
427+ menu.append_item (pin_unlock);
428+
429+ // create the actions
430+ var actions = new SimpleActionGroup();
431+ var unlockpin_item = new SimpleAction.stateful(namespace + ".simunlock", VariantType.BOOLEAN, new Variant.string(""));
432+ unlockpin_item.activate.connect ((ac, value) => {
433+ if (value.get_boolean() == false) {
434+ unlock_cancelled();
435+ }
436+ });
437+ if (pin_entered_callback != null) {
438+ unlockpin_item.change_state.connect ((ac, value) => {
439+ pin_entered_callback(value.get_string());
440+ });
441+ }
442+ actions.insert (unlockpin_item);
443+
444+ // export the menu
445+ uint menu_export_id = 0;
446+ try {
447+ menu_export_id = conn.export_menu_model(exported_menu_path, menu);
448+ } catch (Error e) {
449+ warning(@"Unable to export sim unlock menu model for '$(device.get_iface())': $(e.message)");
450+ clear_stored_data();
451+ return false;
452+ }
453+
454+ // export the actions
455+ uint actions_export_id = 0;
456+ try {
457+ actions_export_id = conn.export_action_group(exported_action_path, actions as ActionGroup);
458+ } catch (Error e) {
459+ warning(@"Unable to export sim unlock actions group for '$(device.get_iface())': $(e.message)");
460+ if (menu_export_id != 0) {
461+ conn.unexport_menu_model(menu_export_id);
462+ }
463+ clear_stored_data();
464+ return false;
465+ }
466+
467+ // create and show the notification
468+ var notification = new Notification(title, body, "");
469+ notification.set_hint_string ("x-canonical-snap-decisions", "true");
470+ notification.set_hint ("x-canonical-private-menu-model", menu_model_paths.end ());
471+
472+ CurrentNotification new_notification = CurrentNotification() {
473+ notification = notification,
474+ unlock_menu_export_id = menu_export_id,
475+ unlock_actions_export_id = actions_export_id,
476+ unlock_menu = menu,
477+ unlock_actions = actions
478+ };
479+
480+ try {
481+ new_notification.notification.closed.connect (notification_closed);
482+ new_notification.notification.show ();
483+
484+ notifications.append(new_notification);
485+ } catch (Error e) {
486+ warning(@"Unable to create sim unlock unlock notification for '$(device.get_iface())': $(e.message)");
487+ clear_notification(new_notification);
488+ clear_stored_data();
489+ return false;
490+ }
491+ return true;
492+ }
493+
494+ private void send_fail_notification (string title)
495+ {
496+ try {
497+ var notification = new Notification(title, "", "");
498+ notification.closed.connect (notification_closed);
499+ notification.show ();
500+ } catch (Error e) {
501+ warning(@"Unable to create sim unlock unlock notification for '$(device.get_iface())': $(e.message)");
502+ return;
503+ }
504+ }
505+
506+ private void create_ofono_sim_manager()
507+ {
508+ try {
509+ if (ofono_modem == null) {
510+ ofono_modem = Bus.get_proxy_sync (BusType.SYSTEM, "org.ofono", device.get_iface());
511+ }
512+
513+ ofono_modem.property_changed.connect((prop, value) => {
514+ if (prop == "Interfaces") {
515+ create_ofono_sim_manager();
516+ }
517+ });
518+
519+ var modem_properties = ofono_modem.get_properties();
520+ var interfaces = modem_properties.lookup("Interfaces");
521+
522+ if (interfaces == null) {
523+ debug(@"Modem '$(device.get_iface())' doesn't have voice support, no interfaces");
524+ return;
525+ }
526+
527+ if (!Utils.variant_contains(interfaces, "org.ofono.SimManager")) {
528+ debug(@"Modem '$(device.get_iface())' doesn't have SIM management support only: $(interfaces.print(false))");
529+ return;
530+ }
531+ } catch (Error e) {
532+ warning(@"Unable to get oFono modem properties for '$(device.get_iface())': $(e.message)");
533+ return;
534+ }
535+
536+ try {
537+ /* Initialize the SIM Manager */
538+ simmanager = Bus.get_proxy_sync (BusType.SYSTEM, "org.ofono", device.get_iface());
539+ simmanager.property_changed.connect(simmanager_property);
540+ var simprops = simmanager.get_properties();
541+ simprops.foreach((k, v) => {
542+ simmanager_property(k, v);
543+ });
544+
545+ } catch (Error e) {
546+ warning(@"Unable to get oFono information from $(device.get_iface()): $(e.message)");
547+ simmanager = null;
548+ }
549+
550+ return;
551+ }
552+
553+ /* Properties from the SIM manager allow us to know the state of the SIM
554+ that we've got installed. */
555+ private void simmanager_property (string prop, Variant value)
556+ {
557+ switch (prop) {
558+ case "Present": {
559+ sim_installed = value.get_boolean();
560+ break;
561+ }
562+ case "PinRequired": {
563+ required_pin = value.get_string();
564+ break;
565+ }
566+ case "Retries": {
567+ if (value.get_type_string() == "a{sy}") {
568+ for (int i = 0; i < value.n_children(); i++) {
569+ string? key = null;
570+ uchar tries = 0;
571+ value.get_child(i, "{sy}", &key, &tries);
572+
573+ retries[key] = tries;
574+ }
575+ }
576+ break;
577+ }
578+ }
579+ }
580+
581+ private void pin_unlock_entered (string pin)
582+ {
583+ if (required_pin == last_required_pin) {
584+ bool retry = false;
585+ if (required_pin == "puk") {
586+ // if it's a puk, we need to reset the pin.
587+ close_all_notifications(true);
588+ if (send_unlock(_("Enter new PIN code"), null, 4, pin_reset_new_entered)) {
589+ debug("SIM pin request. Sent new pin request");
590+ puk_code = pin;
591+ } else {
592+ warning("SIM pin request. New pin notification failed");
593+ }
594+ } else if (!enter_pin(required_pin, pin, out retry)) {
595+ warning("SIM pin request. Failed. retry=$(retry)");
596+ close_all_notifications(true);
597+ if (retry) {
598+ send_unlock_notification();
599+ } else {
600+ send_fail_notification("An unexpected error occurred.");
601+ }
602+ } else {
603+ debug("SIM pin request. Done");
604+ close_all_notifications(true);
605+ }
606+ } else {
607+ warning(@"Required pin type changed. old=$(last_required_pin), new=$(required_pin)");
608+ close_all_notifications(true);
609+ }
610+ }
611+
612+ private void pin_reset_new_entered (string pin)
613+ {
614+ close_all_notifications(false);
615+
616+ if (send_unlock(_("Please confirm PIN code"), null, 4, pin_reset_confirm_entered)) {
617+ debug("SIM reset pin request. Sent confirm pin request");
618+ new_pin = pin;
619+ } else {
620+ warning("SIM reset pin request. Confirm pin notification failed");
621+ clear_stored_data();
622+ }
623+ }
624+
625+ private void pin_reset_confirm_entered (string pin)
626+ {
627+ if (new_pin == pin) {
628+ if (reset_pin("puk", puk_code, pin)) {
629+ debug("SIM reset pin request. Done.");
630+ close_all_notifications(true);
631+ } else {
632+ warning("SIM reset request. Failed.");
633+ close_all_notifications(true);
634+ send_fail_notification("Failed to reset pin.");
635+ }
636+ } else {
637+ warning("SIM reset request. Pin codes did not match");
638+ close_all_notifications(true);
639+ send_fail_notification(_("Pin codes did not match"));
640+ }
641+ }
642+
643+ private void pin_change_old_entered (string pin)
644+ {
645+ close_all_notifications(true);
646+
647+ if (send_unlock(_("Please enter new SIM PIN"), "pin", 4, pin_change_new_entered)) {
648+ debug("SIM change pin request. Sent new pin request");
649+ old_pin = pin;
650+ } else {
651+ warning("SIM change pin request. New pin notification failed");
652+ clear_stored_data();
653+ }
654+ }
655+
656+ private void pin_change_new_entered (string pin)
657+ {
658+ close_all_notifications(false);
659+
660+ if (send_unlock(_("Please confirm PIN code"), null, 4, pin_change_confirm_entered)) {
661+ debug("SIM change pin request. Sent confirm pin request");
662+ new_pin = pin;
663+ } else {
664+ warning("SIM change pin request. Confirm pin notification failed");
665+ clear_stored_data();
666+ }
667+ }
668+
669+ private void pin_change_confirm_entered (string pin)
670+ {
671+ if (new_pin == pin) {
672+ if (change_pin("pin", old_pin, new_pin)) {
673+ debug("SIM change pin request. Done.");
674+ close_all_notifications(true);
675+ } else {
676+ warning("SIM change pin request. Failed.");
677+ close_all_notifications(true);
678+ send_fail_notification("Failed to change pin.");
679+ }
680+ } else {
681+ close_all_notifications(true);
682+ send_fail_notification(_("Pin codes did not match"));
683+ }
684+ }
685+
686+ private bool enter_pin(string type, string pin, out bool retry)
687+ {
688+ retry = false;
689+ try {
690+ if (simmanager != null) {
691+ debug(@"SimManager: Entering $(type) pin");
692+ simmanager.enter_pin(type, pin);
693+ return true;
694+ }
695+ } catch (DBusError e) {
696+ warning(@"Failed to enter $(type) pin for '$(device.get_iface())': $(e.message)");
697+ } catch (IOError e) {
698+ warning(@"Failed to enter $(type) pin for '$(device.get_iface())': $(e.message)");
699+ if (check_ofono_error(e, OFONO_ERROR_FAILED)) {
700+ retry = true;
701+ }
702+ }
703+ return false;
704+ }
705+
706+ private bool reset_pin(string type, string puk, string pin)
707+ {
708+ try {
709+ if (simmanager != null) {
710+ debug(@"SimManager: Resetting");
711+ simmanager.reset_pin(type, puk, pin);
712+ return true;
713+ }
714+ } catch (DBusError e) {
715+ warning(@"Failed to reset pin for '$(device.get_iface())': $(e.message)");
716+ } catch (IOError e) {
717+ warning(@"Failed to reset pin for '$(device.get_iface())': $(e.message)");
718+ }
719+ return false;
720+ }
721+
722+ private bool change_pin(string type, string old_pin, string new_pin)
723+ {
724+ try {
725+ if (simmanager != null) {
726+ debug(@"SimManager: Changing $type pin");
727+ simmanager.change_pin(type, old_pin, new_pin);
728+ return true;
729+ }
730+ } catch (DBusError e) {
731+ warning(@"Failed to change pin for '$(device.get_iface())': $(e.message)");
732+ } catch (IOError e) {
733+ warning(@"Failed to change pin for '$(device.get_iface())': $(e.message)");
734+ }
735+ return false;
736+ }
737+
738+ private void unlock_cancelled() {
739+ debug(@"SIM notification cancelled");
740+ close_all_notifications(true);
741+ }
742+
743+ private void close_all_notifications(bool reset_data) {
744+ unowned List<CurrentNotification?>? element = notifications.first ();
745+ while (element != null) {
746+ CurrentNotification? entry = element.data;
747+ if (entry != null) {
748+ try {
749+ if (entry.unlock_menu_export_id != 0) {
750+ conn.unexport_menu_model(entry.unlock_menu_export_id);
751+ }
752+ if (entry.unlock_actions_export_id != 0) {
753+ conn.unexport_action_group(entry.unlock_actions_export_id);
754+ }
755+ debug(@"closing notification $(entry.notification.id)");
756+ entry.notification.close();
757+ } catch (Error e) {
758+ warning("Failed to close notification for '$(device.get_iface())': $(e.message)");
759+ }
760+ }
761+ element = notifications.next;
762+ }
763+ if (reset_data) {
764+ clear_stored_data();
765+ }
766+ }
767+
768+ private void clear_stored_data()
769+ {
770+ new_pin = "";
771+ old_pin = "";
772+ puk_code = "";
773+ }
774+
775+ private void clear_notification (CurrentNotification? notification)
776+ {
777+ if (notification.unlock_menu_export_id != 0) {
778+ conn.unexport_menu_model(notification.unlock_menu_export_id);
779+ }
780+
781+ if (notification.unlock_actions_export_id != 0) {
782+ conn.unexport_action_group(notification.unlock_actions_export_id);
783+ }
784+ }
785+
786+ private void notification_closed (Notification? notification)
787+ {
788+ unowned List<CurrentNotification?>? element = notifications.first ();
789+ while (element != null) {
790+ unowned CurrentNotification? entry = element.data;
791+
792+ if (entry != null && notification.id == entry.notification.id) {
793+ debug(@"notification_closed $(notification.id)");
794+
795+ clear_notification(entry);
796+ notifications.delete_link(element);
797+ break;
798+ }
799+ element = notifications.next;
800+ }
801+ if (notifications.length () == 0) {
802+ pin_unlocking = false;
803+ }
804+ }
805+
806+ private bool check_ofono_error(Error e, string value)
807+ {
808+ return DBusError.get_remote_error(e) == value;
809+ }
810+
811+ }
812+}
813
814=== modified file 'network/network-action-manager.vala'
815--- network/network-action-manager.vala 2013-10-09 20:27:33 +0000
816+++ network/network-action-manager.vala 2013-10-10 15:57:20 +0000
817@@ -112,7 +112,7 @@
818 /* Check to see if the modem supports voice */
819 try {
820 oFono.Modem? ofono_modem = watched_modems.lookup(modemmaybe.get_iface());
821-
822+
823 if (ofono_modem == null) {
824 ofono_modem = Bus.get_proxy_sync (BusType.SYSTEM, "org.ofono", modemmaybe.get_iface());
825
826@@ -133,15 +133,15 @@
827 return;
828 }
829
830- if (!variant_contains(interfaces, "org.ofono.VoiceCallManager")) {
831+ if (!Utils.variant_contains(interfaces, "org.ofono.VoiceCallManager")) {
832 debug(@"Modem '$(modemmaybe.get_iface())' doesn't have voice support only: $(interfaces.print(false))");
833 return;
834 }
835- if (!variant_contains(interfaces, "org.ofono.SimManager")) {
836+ if (!Utils.variant_contains(interfaces, "org.ofono.SimManager")) {
837 debug(@"Modem '$(modemmaybe.get_iface())' doesn't have SIM management support only: $(interfaces.print(false))");
838 return;
839 }
840- if (!variant_contains(interfaces, "org.ofono.NetworkRegistration")) {
841+ if (!Utils.variant_contains(interfaces, "org.ofono.NetworkRegistration")) {
842 debug(@"Modem '$(modemmaybe.get_iface())' doesn't have Network Registration support only: $(interfaces.print(false))");
843 return;
844 }
845@@ -304,24 +304,6 @@
846 return "pre-edge";
847 }
848
849- private bool variant_contains (Variant variant, string needle)
850- {
851- if (variant.is_of_type(VariantType.VARIANT))
852- return variant_contains(variant.get_variant(), needle);
853-
854- if (!variant.is_container())
855- return false;
856-
857- Variant item;
858- var iter = new VariantIter(variant);
859- for (item = iter.next_value(); item != null; item = iter.next_value()) {
860- if (item.get_string() == needle)
861- return true;
862- }
863-
864- return false;
865- }
866-
867 private Variant? icon_serialize (string icon_name)
868 {
869 try {
870@@ -557,13 +539,13 @@
871 var dev = act_dev as NM.DeviceWifi;
872
873 dev.notify["active-access-point"].disconnect (active_access_point_changed);
874-
875+
876 if (act_ap != null)
877 {
878 act_ap.notify["strength"].disconnect (active_connection_strength_changed);
879 act_ap = null;
880 }
881-
882+
883 break;
884 default:
885 break;
886
887=== modified file 'network/network-menu-service.vala'
888--- network/network-menu-service.vala 2013-08-25 18:53:54 +0000
889+++ network/network-menu-service.vala 2013-10-10 15:57:20 +0000
890@@ -19,6 +19,7 @@
891 */
892
893 using Config;
894+using Notify;
895
896 public static int main (string[] args)
897 {
898@@ -32,10 +33,10 @@
899
900 GLib.Unix.signal_add(GLib.ProcessSignal.TERM, () => {
901 debug("Recieved SIGTERM");
902- mainloop.quit();
903+ mainloop.quit();
904 return false;
905 });
906-
907+ Notify.init("indicator-network");
908 var menu = new Network.NetworkMenu ();
909 mainloop.run ();
910 return 0;
911
912=== modified file 'network/network-menu.vala'
913--- network/network-menu.vala 2013-09-30 18:48:11 +0000
914+++ network/network-menu.vala 2013-10-10 15:57:20 +0000
915@@ -179,6 +179,7 @@
916 private NM.Client client;
917 private ActionManager am;
918 private GLibLocal.ActionMuxer muxer = new GLibLocal.ActionMuxer();
919+ private GLib.DBusConnection conn;
920
921 public NetworkMenu ()
922 {
923@@ -190,7 +191,7 @@
924
925 try
926 {
927- var conn = Bus.get_sync (BusType.SESSION, null);
928+ conn = Bus.get_sync (BusType.SESSION, null);
929
930 conn.export_action_group (ACTION_GROUP_PATH, muxer as ActionGroup);
931
932@@ -236,7 +237,7 @@
933 private void add_device (NM.Device device)
934 {
935 Device.Base? founddev = null;
936-
937+
938 founddev = desktop.find_device(device.get_path());
939 if (founddev != null) return;
940
941@@ -256,9 +257,9 @@
942
943 break;
944 case NM.DeviceType.MODEM:
945- var mobiledesktopdev = new Device.Mobile(this.client, device as NM.DeviceModem, this.muxer, true);
946+ var mobiledesktopdev = new Device.Mobile(this.client, device as NM.DeviceModem, this.muxer, true, conn);
947 desktop.append_device(mobiledesktopdev);
948- var mobilephonedev = new Device.Mobile(this.client, device as NM.DeviceModem, this.muxer, false);
949+ var mobilephonedev = new Device.Mobile(this.client, device as NM.DeviceModem, this.muxer, false, conn);
950 phone.append_device(mobilephonedev);
951 break;
952 case NM.DeviceType.ETHERNET:
953
954=== modified file 'network/ofono.vala'
955--- network/ofono.vala 2013-08-22 20:57:12 +0000
956+++ network/ofono.vala 2013-10-10 15:57:20 +0000
957@@ -5,23 +5,53 @@
958
959 [DBus (name = "org.ofono.Modem") ]
960 public interface Modem : GLib.Object {
961+
962+ [DBus (name = "SetProperty")]
963 public abstract void set_property (string property, GLib.Variant value) throws IOError;
964+
965+ [DBus (name = "GetProperties")]
966 public abstract GLib.HashTable<string, GLib.Variant> get_properties () throws IOError;
967+
968+ [DBus (name = "PropertyChanged")]
969 public signal void property_changed (string property, GLib.Variant value);
970 }
971
972 [DBus (name = "org.ofono.NetworkRegistration") ]
973 public interface NetworkRegistration : GLib.Object {
974+
975+ [DBus (name = "GetProperties")]
976 public abstract GLib.HashTable<string, GLib.Variant> get_properties () throws IOError;
977
978+ [DBus (name = "PropertyChanged")]
979 public signal void property_changed (string property, GLib.Variant value);
980 }
981
982 [DBus (name = "org.ofono.SimManager") ]
983 public interface SIMManager : GLib.Object {
984+
985+ [DBus (name = "SetProperty")]
986 public abstract void set_property (string property, GLib.Variant value) throws IOError;
987+
988+ [DBus (name = "GetProperties")]
989 public abstract GLib.HashTable<string, GLib.Variant> get_properties () throws IOError;
990+
991+ [DBus (name = "PropertyChanged")]
992 public signal void property_changed (string property, GLib.Variant value);
993+
994+ [DBus (name = "ChangePin")]
995+ public abstract void change_pin(string type, string old_pin, string new_pin) throws DBusError, IOError;
996+
997+ [DBus (name = "EnterPin")]
998+ public abstract void enter_pin(string type, string pin) throws DBusError, IOError;
999+
1000+ [DBus (name = "ResetPin")]
1001+ public abstract void reset_pin(string type, string puk, string new_pin) throws DBusError, IOError;
1002+
1003+ [DBus (name = "LockPin")]
1004+ public abstract void lock_pin(string type, string pin) throws DBusError, IOError;
1005+
1006+ [DBus (name = "UnlockPin")]
1007+ public abstract void unlock_pin(string type, string pin) throws DBusError, IOError;
1008 }
1009
1010
1011
1012=== added file 'network/utils.vala'
1013--- network/utils.vala 1970-01-01 00:00:00 +0000
1014+++ network/utils.vala 2013-10-10 15:57:20 +0000
1015@@ -0,0 +1,23 @@
1016+using GLib;
1017+
1018+namespace Utils {
1019+
1020+ public bool variant_contains (Variant variant, string needle)
1021+ {
1022+ if (variant.is_of_type(VariantType.VARIANT))
1023+ return variant_contains(variant.get_variant(), needle);
1024+
1025+ if (!variant.is_container())
1026+ return false;
1027+
1028+ Variant item;
1029+ var iter = new VariantIter(variant);
1030+ for (item = iter.next_value(); item != null; item = iter.next_value()) {
1031+ if (item.get_string() == needle)
1032+ return true;
1033+ }
1034+
1035+ return false;
1036+ }
1037+
1038+}

Subscribers

People subscribed via source and target branches