1import dbus
2from dbus.service import Object, method, signal
3
4import sys
5
6class FakeConnectivity(object):
7    NM_BUS_NAME = 'org.freedesktop.NetworkManager'
8    NM_PATH = '/org/freedesktop/NetworkManager'
9    NM_PATH_SETTINGS = NM_PATH + '/Settings'
10    NM_INTERFACE = NM_BUS_NAME
11    NM_INTERFACE_SETTINGS = NM_INTERFACE + '.Settings'
12
13    NM_STATE_UNKNOWN          = 0
14    NM_STATE_ASLEEP           = 10
15    NM_STATE_DISCONNECTED     = 20
16    NM_STATE_DISCONNECTING    = 30
17    NM_STATE_CONNECTING       = 40
18    NM_STATE_CONNECTED_LOCAL  = 50
19    NM_STATE_CONNECTED_SITE   = 60
20    NM_STATE_CONNECTED_GLOBAL = 70
21
22    # Our fake GNetworkMonitor uses the ConnMan 0.79 D-Bus API - we don't
23    # have any special support for ConnMan any more, but it's as good an
24    # API as any. The important thing is that it's not NM, because we *do*
25    # have a bit of special support for that.
26    CONNMAN_BUS_NAME = 'net.connman'
27    CONNMAN_PATH = '/'
28    CONNMAN_INTERFACE = 'net.connman.Manager'
29
30    CONNMAN_OFFLINE = "offline"
31    CONNMAN_ONLINE = "online"
32
33    def __init__(self, q, bus, initially_online):
34        self.q = q
35        self.bus = bus
36
37        self.nm_name_ref = dbus.service.BusName(self.NM_BUS_NAME, bus)
38        self.connman_name_ref = dbus.service.BusName(self.CONNMAN_BUS_NAME, bus)
39
40        q.add_dbus_method_impl(self.NM_GetPermissions,
41            path=self.NM_PATH, interface=self.NM_INTERFACE,
42            method='GetPermissions')
43        q.add_dbus_method_impl(self.NM_Get,
44            path=self.NM_PATH, interface=dbus.PROPERTIES_IFACE, method='Get',
45            predicate=lambda e: e.args[0] == self.NM_INTERFACE)
46        q.add_dbus_method_impl(self.NM_GetAll,
47            path=self.NM_PATH, interface=dbus.PROPERTIES_IFACE, method='GetAll',
48            predicate=lambda e: e.args[0] == self.NM_INTERFACE)
49        q.add_dbus_method_impl(self.NM_GetDevices,
50            path=self.NM_PATH, interface=self.NM_INTERFACE, method='GetDevices')
51
52        q.add_dbus_method_impl(self.NM_Settings_Get,
53            path=self.NM_PATH_SETTINGS, interface=dbus.PROPERTIES_IFACE, method='Get',
54            predicate=lambda e: e.args[0] == self.NM_INTERFACE_SETTINGS)
55        q.add_dbus_method_impl(self.NM_Settings_GetAll,
56            path=self.NM_PATH_SETTINGS, interface=dbus.PROPERTIES_IFACE, method='GetAll',
57            predicate=lambda e: e.args[0] == self.NM_INTERFACE_SETTINGS)
58
59        q.add_dbus_method_impl(self.ConnMan_GetProperties,
60            path=self.CONNMAN_PATH, interface=self.CONNMAN_INTERFACE,
61            method='GetProperties')
62
63        self.change_state(initially_online)
64
65    def NM_GetPermissions(self, e):
66        permissions = {
67            self.NM_INTERFACE + '.network-control': 'yes',
68            self.NM_INTERFACE + '.enable-disable-wwan': 'yes',
69            self.NM_INTERFACE + '.settings.modify.own': 'yes',
70            self.NM_INTERFACE + '.wifi.share.protected': 'yes',
71            self.NM_INTERFACE + '.wifi.share.open': 'yes',
72            self.NM_INTERFACE + '.enable-disable-network': 'yes',
73            self.NM_INTERFACE + '.enable-disable-wimax': 'yes',
74            self.NM_INTERFACE + '.sleep-wake': 'no',
75            self.NM_INTERFACE + '.enable-disable-wifi': 'yes',
76            self.NM_INTERFACE + '.settings.modify.system': 'auth',
77            self.NM_INTERFACE + '.settings.modify.hostname': 'auth',
78        }
79        self.q.dbus_return(e.message, permissions, signature='a{ss}')
80
81    def nm_props(self):
82        return {
83            'NetworkingEnabled': True,
84            'WirelessEnabled': True,
85            'WirelessHardwareEnabled': True,
86            'WwanEnabled': False,
87            'WwanHardwareEnabled': True,
88            'WimaxEnabled': True,
89            'WimaxHardwareEnabled': True,
90            'ActiveConnections': dbus.Array([], signature='o'),
91            'Version': '0.9.0',
92            'State': dbus.UInt32(self.nm_state),
93        }
94
95    def NM_Get(self, e):
96        self.q.dbus_return(e.message, self.nm_props()[e.args[1]], signature='v')
97
98    def NM_GetAll(self, e):
99        self.q.dbus_return(e.message, self.nm_props(), signature='a{sv}')
100
101    def NM_GetDevices(self, e):
102        self.q.dbus_return(e.message, [], signature='ao')
103
104    def nm_settings_props(self):
105        return {
106            'CanModify': False,
107            'Hostname': 'localhost',
108            'Connections': dbus.Array([], signature='o'),
109        }
110
111    def NM_Settings_Get(self, e):
112        self.q.dbus_return(e.message, self.nm_settings_props()[e.args[1]], signature='v')
113
114    def NM_Settings_GetAll(self, e):
115        self.q.dbus_return(e.message, self.nm_settings_props(), signature='a{sv}')
116
117    def Connman_props(self):
118        return {
119            'OfflineMode': False,
120            'SessionMode': False,
121            'State': self.connman_state,
122        }
123
124    def ConnMan_GetProperties(self, e):
125        self.q.dbus_return(e.message, self.Connman_props(), signature='a{sv}')
126
127    def change_state(self, online, indeterminate=False):
128        if indeterminate:
129            self.nm_state = self.NM_STATE_DISCONNECTING
130            # keep the previous "ConnMan" (GNetworkMonitor) state;
131            # any other GNetworkMonitor would probably do the same
132            # while trying to disconnect, because e.g. netlink will say the
133            # interface is still up
134        elif online:
135            self.nm_state = self.NM_STATE_CONNECTED_GLOBAL
136            self.connman_state = self.CONNMAN_ONLINE
137        else:
138            self.nm_state = self.NM_STATE_DISCONNECTED
139            self.connman_state = self.CONNMAN_OFFLINE
140
141        self.q.dbus_emit(self.NM_PATH, self.NM_INTERFACE,
142            'PropertiesChanged', { "State": dbus.UInt32(self.nm_state) },
143            signature='a{sv}')
144        self.q.dbus_emit(self.NM_PATH, self.NM_INTERFACE,
145            'StateChanged', self.nm_state,
146            signature='u')
147
148        if not indeterminate:
149            self.q.dbus_emit(self.CONNMAN_PATH, self.CONNMAN_INTERFACE,
150                'PropertyChanged', "State", self.connman_state, signature='sv')
151
152    def go_online(self):
153        self.change_state(True)
154
155    def go_offline(self):
156        self.change_state(False)
157
158    def go_indeterminate(self):
159        self.change_state(None, True)
160