1# Copyright (c) 2012 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Base class for objects to configure Linksys single band access points
6   using webdriver."""
7
8import logging
9import urlparse
10
11import dynamic_ap_configurator
12import ap_spec
13
14from selenium.common.exceptions import WebDriverException
15
16
17class LinksyseSingleBandAPConfigurator(
18        dynamic_ap_configurator.DynamicAPConfigurator):
19    """Base class for objects to configure Linksys single band access points
20       using webdriver."""
21
22    def __init__(self, ap_config):
23        super(LinksyseSingleBandAPConfigurator, self).__init__(ap_config)
24        self._dhcp_delay = 30
25
26
27    def _sec_alert(self, alert):
28        text = alert.text
29        if 'Your wireless security mode is not compatible with' in text:
30            alert.accept()
31        elif 'WARNING: Your Wireless-N devices will only operate' in text:
32            alert.accept()
33        elif 'Wireless security is currently disabled.' in text:
34            alert.accept()
35            self.click_button_by_id('divBT1', alert_handler=self._sec_alert)
36        elif 'Your new setting will disable Wi-Fi Protected Setup.' in text:
37            alert.accept()
38        elif 'Illegal characters [ acceptable characters: 0 to 9 ]' in text:
39            alert.accept()
40            raise RuntimeError('Invalid characters used for key renewal. '
41                               'Error: %s' % text)
42        elif 'The Key must be between 8 and 63 ASCII characters' in text:
43            alert.accept()
44        else:
45            raise RuntimeError('Unhandled alert message: %s' % text)
46
47
48    def get_number_of_pages(self):
49        return 2
50
51
52    def get_supported_modes(self):
53        return [{'band': ap_spec.BAND_2GHZ,
54                 'modes': [ap_spec.MODE_M, ap_spec.MODE_B | ap_spec.MODE_G,
55                           ap_spec.MODE_G, ap_spec.MODE_B, ap_spec.MODE_N]}]
56
57
58    def get_supported_bands(self):
59        return [{'band': ap_spec.BAND_2GHZ,
60                 'channels': ['Auto', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}]
61
62
63    def is_security_mode_supported(self, security_mode):
64        """Returns if the passes security mode is supported.
65
66        @param security_mode: a valid ap_spec security mode
67
68        @returns True if the mode is supported; False otherwise
69
70        """
71        return security_mode in (ap_spec.SECURITY_TYPE_DISABLED,
72                                 ap_spec.SECURITY_TYPE_WPAPSK,
73                                 ap_spec.SECURITY_TYPE_WPA2PSK,
74                                 ap_spec.SECURITY_TYPE_WEP)
75
76
77    def navigate_to_page(self, page_number):
78        """Navigates to the passed in page.
79
80        @param page_number: the page number as an integer
81
82        """
83        if page_number == 1:
84            page_url = urlparse.urljoin(self.admin_interface_url,
85                                        'Wireless_Basic.asp')
86            self.get_url(page_url, page_title='Settings')
87        elif page_number == 2:
88            page_url = urlparse.urljoin(self.admin_interface_url,
89                                        'WL_WPATable.asp')
90            self.get_url(page_url, page_title='Security')
91        else:
92            raise RuntimeError('Invalid page number passed. Number of pages '
93                               '%d, page value sent was %d' %
94                               (self.get_number_of_pages(), page_number))
95
96
97    def save_page(self, page_number):
98        """Save the given page.
99
100        @param page_number: the page number as an integer
101
102        """
103        try:
104            self.click_button_by_id('divBT1', alert_handler=self._sec_alert)
105        except:
106            self._handle_alert('//input[@id="divBT1"]', self._sec_alert)
107        xpath_continue = '//input[@value="Continue"]'
108        self.wait_for_object_by_xpath(xpath_continue, wait_time=20)
109        self.click_button_by_xpath(xpath_continue,
110                                   alert_handler=self._sec_alert)
111
112
113    def set_mode(self, mode, band=None):
114        self.add_item_to_command_list(self._set_mode, (mode,), 1, 900)
115
116
117    def _set_mode(self, mode, band=None):
118        mode_mapping = {ap_spec.MODE_M:'Mixed',
119                        ap_spec.MODE_B | ap_spec.MODE_G:'Wireless-B/G Only',
120                        ap_spec.MODE_G:'Wireless-G Only',
121                        ap_spec.MODE_B:'Wireless-B Only',
122                        ap_spec.MODE_N:'Wireless-N Only',
123                        'Disabled':'Disabled'}
124        mode_name = mode_mapping.get(mode)
125        if not mode_name:
126            raise RuntimeError('The mode %d not supported by router %s. ',
127                               hex(mode), self.name)
128        xpath = '//select[@name="net_mode_24g"]'
129        self.select_item_from_popup_by_xpath(mode_name, xpath,
130                                             alert_handler=self._sec_alert)
131
132
133    def set_ssid(self, ssid):
134        self.add_item_to_command_list(self._set_ssid, (ssid,), 1, 900)
135
136
137    def _set_ssid(self, ssid):
138        xpath = '//input[@maxlength="32" and @name="ssid_24g"]'
139        self.set_content_of_text_field_by_xpath(ssid, xpath, abort_check=False)
140        # If security is off leaving focus from the field will throw
141        # a alert dialog.
142        ssid_field = self.driver.find_element_by_xpath(xpath)
143        self._ssid = ssid
144        try:
145            ssid_field.send_keys('\t')
146            return
147        except WebDriverException, e:
148            message = str(e)
149            if message.find('An open modal dialog blocked the operation') == -1:
150                return
151        self._sec_alert(self.driver.switch_to_alert())
152
153
154    def set_channel(self, channel):
155        self.add_item_to_command_list(self._set_channel, (channel,), 1, 900)
156
157
158    def _set_channel(self, channel):
159        position = self._get_channel_popup_position(channel)
160        xpath = '//select[@name="_wl0_channel"]'
161        channels = ['Auto',
162                    '1 - 2.412GHZ', '2 - 2.417GHZ', '3 - 2.422GHZ',
163                    '4 - 2.427GHZ', '5 - 2.432GHZ', '6 - 2.437GHZ',
164                    '7 - 2.442GHZ', '8 - 2.447GHZ', '9 - 2.452GHZ',
165                    '10 - 2.457GHZ', '11 - 2.462GHZ']
166        self.select_item_from_popup_by_xpath(channels[position], xpath)
167
168
169    def set_channel_width(self, channel_wid):
170        """
171        Adjusts the channel channel width.
172
173        @param channel_width: the channel width
174        """
175        self.add_item_to_command_list(self._set_channel_width,(channel_wid,),
176                                      1, 900)
177
178
179    def _set_channel_width(self, channel_wid):
180        channel_width_choice = ['Auto (20 MHz or 40 MHz)', '20 MHz Only']
181        xpath = '//select[@name="_wl0_nbw"]'
182        self.select_item_from_popup_by_xpath(channel_width_choice[channel_wid],
183                                             xpath)
184
185
186    def set_radio(self, enabled=True):
187        weight = 1 if enabled else 1000
188        self.add_item_to_command_list(self._set_radio, (enabled,), 1, weight)
189
190
191    def _set_radio(self, enabled=True):
192        if not enabled:
193            self._set_mode('Disabled')
194        else:
195            self._set_mode(ap_spec.MODE_G)
196
197
198    def set_band(self, enabled=True):
199        logging.debug('set_band is not supported in Linksys single band AP.')
200        return None
201
202
203    def set_security_disabled(self):
204        self.add_item_to_command_list(self._set_security_disabled, (), 2, 1000)
205
206
207    def _set_security_disabled(self):
208        xpath = '//select[@name="wl0_security_mode"]'
209        self.select_item_from_popup_by_xpath('Disabled', xpath,
210                                             alert_handler=self._sec_alert)
211
212
213    def set_security_wep(self, key_value, authentication):
214        self.add_item_to_command_list(self._set_security_wep,
215                                      (key_value, authentication), 2, 1000)
216
217
218    def _set_security_wep(self, key_value, authentication):
219        # WEP and WPA-Personal are not supported for Wireless-N only mode
220        # and Mixed mode.
221        # WEP and WPA-Personal do not show up in the list, no alert is thrown.
222        popup = '//select[@name="wl0_security_mode"]'
223        if not self.item_in_popup_by_xpath_exist('WEP', popup):
224            raise RuntimeError('The popup %s did not contain the item %s. '
225                               'Is the mode N?' % (popup, self.security_wep))
226        self.select_item_from_popup_by_xpath('WEP', popup,
227                                             alert_handler=self._sec_alert)
228        text = '//input[@name="wl0_passphrase"]'
229        self.set_content_of_text_field_by_xpath(key_value, text,
230                                                abort_check=True)
231        xpath = '//input[@value="Generate"]'
232        self.click_button_by_xpath(xpath, alert_handler=self._sec_alert)
233
234
235    def set_security_wpapsk(self, security, shared_key, update_interval=None):
236        # WEP and WPA-Personal are not supported for Wireless-N only mode,
237        self.add_item_to_command_list(self._set_security_wpapsk,
238                                      (security, shared_key, update_interval),
239                                       2, 900)
240
241
242    def _set_security_wpapsk(self, security, shared_key, upadate_interval=None):
243        """Common method to set wpapsk and wpa2psk modes."""
244        popup = '//select[@name="wl0_security_mode"]'
245        self.wait_for_object_by_xpath(popup)
246        if security == ap_spec.SECURITY_TYPE_WPAPSK:
247            wpa_item = 'WPA Personal'
248        else:
249            wpa_item = 'WPA2 Personal'
250        self.select_item_from_popup_by_xpath(wpa_item, popup,
251                                             alert_handler=self._sec_alert)
252        text = '//input[@name="wl0_wpa_psk"]'
253        self.set_content_of_text_field_by_xpath(shared_key, text,
254                                                abort_check=False)
255
256
257    def is_update_interval_supported(self):
258        """
259        Returns True if setting the PSK refresh interval is supported.
260
261        @return True is supported; False otherwise
262        """
263        return False
264
265
266    def set_visibility(self, visible=True):
267        self.add_item_to_command_list(self._set_visibility, (visible,), 1, 900)
268
269
270    def _set_visibility(self, visible=True):
271        int_value = 0 if visible else 1
272        xpath = ('//input[@value="%d" and @name="closed_24g"]' % int_value)
273        self.click_button_by_xpath(xpath, alert_handler=self._sec_alert)
274