]>
Commit | Line | Data |
---|---|---|
5b4622f6 MF |
1 | // Written by Mike Frysinger <vapier@gmail.com>. |
2 | // Released into the public domain. | |
3 | ||
4 | function status(msg) { | |
5 | $$('[name=status]').innerText = msg; | |
6 | } | |
7 | ||
8 | // Create a packet following the spec: | |
9 | // https://en.wikipedia.org/wiki/Wake-on-LAN#Magic_packet | |
10 | function magicpacket(mac, pass) { | |
11 | var data = new ArrayBuffer(6 + 16 * 6 + 6 + 6); | |
12 | var bytes = new Uint8Array(data); | |
13 | var i, j, base = 0; | |
14 | ||
15 | // First 6 bytes should be all 0xFF. | |
16 | for (i = 0; i < 6; ++i) | |
17 | bytes[base + i] = 0xff; | |
18 | base += 6; | |
19 | ||
20 | // Then the MAC address is repeated 16 times. | |
21 | for (i = 0; i < 6; ++i) | |
22 | for (j = 0; j < 16 * 6; j += 6) | |
23 | bytes[base + j + i] = mac[i]; | |
24 | base += 16 * 6; | |
25 | ||
26 | // Then 6 bytes before the pass should be 0xFF. | |
27 | for (i = 0; i < 6; ++i) | |
28 | bytes[base + i] = 0xff; | |
29 | base += 6; | |
30 | ||
31 | // Finally the 6 bytes of the password. | |
32 | for (i = 0; i < 6; ++i) | |
33 | bytes[base + i] = pass[i]; | |
34 | ||
35 | return data; | |
36 | } | |
37 | ||
38 | function split_data(v) { | |
39 | var data = Array(6); | |
40 | var i, idata; | |
41 | ||
42 | window['sync_' + v](); | |
43 | ||
44 | for (i = 0; i < 6; ++i) { | |
45 | idata = $$('input[name=' + v + i + ']'); | |
46 | if (!/^[0-9a-fA-F]?[0-9a-fA-F]$/.test(idata.value.replace(' ', ''))) { | |
47 | status(v + ' byte ' + i + ' is invalid; must be 2 hex characters'); | |
48 | idata.focus(); | |
49 | idata.setSelectionRange(0, idata.value.length); | |
50 | return false; | |
51 | } | |
52 | data[i] = parseInt(idata.value, 16); | |
53 | } | |
54 | ||
55 | return data; | |
56 | } | |
57 | ||
58 | function send() { | |
59 | status('initializing'); | |
60 | ||
61 | var form = $$('form[name=settings]'); | |
62 | var shost = '0.0.0.0'; | |
63 | var dhost = form.host.value; | |
64 | var port = parseInt(form.port.value); | |
65 | ||
66 | // Get the MAC address & password to convert to packet data. | |
67 | var mac = split_data('mac'); | |
68 | var pass = split_data('pass'); | |
69 | var data = magicpacket(mac, pass); | |
70 | console.log('packet', new Uint8Array(data)); | |
71 | ||
72 | var checkresult = function(s, step, result) { | |
73 | if (result < 0) { | |
74 | status('error in ' + step + ': ' + net_error_list[result]); | |
75 | chrome.sockets.udp.close(s, nullcb); | |
76 | return false; | |
77 | } | |
78 | return true; | |
79 | }; | |
80 | ||
81 | // Create the socket ... | |
82 | chrome.sockets.udp.create({}, function(createInfo) { | |
83 | var s = createInfo.socketId; | |
84 | ||
85 | console.log('[create] socketInfo', createInfo); | |
86 | status('binding ' + shost); | |
87 | ||
88 | // Bind it locally ... | |
89 | chrome.sockets.udp.bind(s, shost, 0, function(result) { | |
90 | console.log('[bind] result', result); | |
91 | ||
92 | if (!checkresult(s, 'bind', result)) | |
93 | return false; | |
94 | ||
95 | status('enabling broadcast'); | |
96 | ||
97 | // Turn on broadcast support ... | |
98 | chrome.sockets.udp.setBroadcast(s, true, function(result) { | |
99 | console.log('[setBroadcast] result', result); | |
100 | ||
101 | if (!checkresult(s, 'broadcast', result)) | |
102 | return false; | |
103 | ||
104 | status('sending to ' + dhost + ':' + port); | |
105 | ||
106 | // Send the backet ... | |
107 | chrome.sockets.udp.send(s, data, dhost, port, function(sendInfo) { | |
108 | console.log('[send] sendInfo', sendInfo); | |
109 | ||
110 | if (!checkresult(s, 'send', sendInfo.resultCode)) | |
111 | return false; | |
112 | ||
113 | status('closing'); | |
114 | ||
115 | // Shut it down ... | |
116 | chrome.sockets.udp.close(s, function() { | |
117 | status('sent to ' + dhost + ':' + port); | |
118 | store_settings(); | |
119 | }); | |
120 | }); | |
121 | }); | |
122 | }); | |
123 | }); | |
124 | ||
125 | // Keep the form from submitting. | |
126 | return false; | |
127 | } | |
128 | ||
129 | function sync_it(v) { | |
130 | var smany = $$('span[name=' + v + '-many]'); | |
131 | var sone = $$('span[name=' + v + '-one]'); | |
132 | ||
133 | // Sync the two sets of fields. | |
134 | var i; | |
135 | if (smany.hidden) { | |
136 | var idata = $$('input[name=' + v + ']'); | |
137 | var data = idata.value.split(':'); | |
138 | ||
139 | if (data.length != 6) { | |
140 | data = idata.value.replace(/[ :]/g, ''); | |
141 | if (data.length != 6 * 2) { | |
142 | status('invalid ' + v + '; please fix'); | |
143 | return false; | |
144 | } | |
145 | data = data.match(/../g); | |
146 | } else { | |
147 | for (i = 0; i < 6; ++i) | |
148 | if (data[i].length > 2) { | |
149 | status('invalid ' + v + ' please fix'); | |
150 | return false; | |
151 | } | |
152 | } | |
153 | ||
154 | for (i = 0; i < 6; ++i) | |
155 | $$('input[name=' + v + i + ']').value = data[i]; | |
156 | } else { | |
157 | var data = ''; | |
158 | ||
159 | for (i = 0; i < 6; ++i) { | |
160 | data += $$('input[name=' + v + i + ']').value; | |
161 | if (i < 5) | |
162 | data += ':'; | |
163 | } | |
164 | ||
165 | $$('input[name=' + v + ']').value = data; | |
166 | } | |
167 | } | |
168 | function sync_mac() { return sync_it('mac'); } | |
169 | function sync_pass() { return sync_it('pass'); } | |
170 | ||
171 | ||
172 | function paste_mac() { | |
173 | sync_mac(); | |
174 | ||
175 | var smany = $$('span[name=mac-many]'); | |
176 | var sone = $$('span[name=mac-one]'); | |
177 | smany.hidden = !smany.hidden; | |
178 | sone.hidden = !sone.hidden; | |
179 | ||
180 | return false; | |
181 | } | |
182 | ||
183 | function paste_pass() { | |
184 | sync_pass(); | |
185 | ||
186 | var smany = $$('span[name=pass-many]'); | |
187 | var sone = $$('span[name=pass-one]'); | |
188 | smany.hidden = !smany.hidden; | |
189 | sone.hidden = !sone.hidden; | |
190 | ||
191 | return false; | |
192 | } | |
193 | ||
194 | /* | |
195 | * Storage logic. | |
196 | */ | |
197 | var settings_keys = [ | |
198 | 'host', | |
199 | 'mac', | |
200 | 'pass', | |
201 | 'port', | |
6293bf85 | 202 | 'theme', |
5b4622f6 MF |
203 | ]; |
204 | ||
e54503ce MF |
205 | var default_theme = 'dark'; |
206 | var default_host = '192.168.0.255'; | |
207 | var default_port = '40000'; | |
208 | var default_mac = '20:00:00:00:00:00'; | |
209 | var default_pass = '00:00:00:00:00:00'; | |
210 | ||
5b4622f6 MF |
211 | function load_settings() { |
212 | var storage = chrome.storage.local; | |
213 | ||
214 | chrome.storage.local.get(settings_keys, function(settings) { | |
e54503ce | 215 | set_theme(settings['theme'] || default_theme); |
5b4622f6 | 216 | var form = $$('form[name=settings]'); |
e54503ce MF |
217 | form.host.value = settings['host'] || default_host; |
218 | form.port.value = settings['port'] || default_port; | |
5b4622f6 MF |
219 | // We assume we only get called during init. |
220 | paste_mac(); | |
e54503ce | 221 | form.mac.value = settings['mac'] || default_mac; |
5b4622f6 MF |
222 | paste_mac(); |
223 | paste_pass(); | |
e54503ce | 224 | form.pass.value = settings['pass'] || default_pass; |
5b4622f6 MF |
225 | paste_pass(); |
226 | }); | |
227 | } | |
228 | ||
229 | function store_settings() { | |
230 | var form = $$('form[name=settings]'); | |
231 | sync_mac(); | |
232 | sync_pass(); | |
233 | var settings = { | |
234 | 'host': form.host.value, | |
235 | 'mac': form.mac.value, | |
236 | 'pass': form.pass.value, | |
237 | 'port': form.port.value, | |
6293bf85 | 238 | 'theme': curr_theme, |
5b4622f6 MF |
239 | }; |
240 | chrome.storage.local.set(settings); | |
241 | } | |
242 | ||
243 | /* | |
244 | * Startup. | |
245 | */ | |
246 | window.onload = function() { | |
247 | $$('form[name=settings]').onsubmit = send; | |
248 | $$('a[name=mac-paste]').onclick = paste_mac; | |
249 | $$('a[name=pass-paste]').onclick = paste_pass; | |
6293bf85 | 250 | $$('input[name=theme]').onclick = toggle_theme; |
5b4622f6 MF |
251 | |
252 | load_settings(); | |
253 | }; |