Download
jcs
/wifi_da
/main.c
(View History)
jcs *: Don't rely on our static wifi_da persisting | Latest amendment: 40 on 2025-01-07 |
1 | /* |
2 | * Copyright (c) 2023 joshua stein <jcs@jcs.org> |
3 | * |
4 | * Permission to use, copy, modify, and distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #include <stdarg.h> |
18 | #include <stdio.h> |
19 | #include <string.h> |
20 | #include <Script.h> |
21 | #include "wi-fi.h" |
22 | |
23 | /* device control entry */ |
24 | DCtlPtr dce = NULL; |
25 | |
26 | SysEnvRec world; |
27 | #define ON_SYSTEM_7 (world.systemVersion >= 0x0700) |
28 | |
29 | struct wifi_da wifi_da = { 0 }; |
30 | short wifi_scsi_id = WIFI_SCSI_ID_FINDING; |
31 | unsigned long wifi_scan_started = 0; |
32 | struct wifi_network_entry wifi_cur_info; |
33 | struct wifi_network_entry wifi_scan_networks[10]; |
34 | MenuHandle menu, apple_menu; |
35 | short menuID = 0; |
36 | Cursor watch; |
37 | |
38 | short main(cntrlParam *p, DCtlPtr d, short n); |
39 | void da_open(void); |
40 | void da_control(short code, short *param); |
41 | void da_close(void); |
42 | bool handle_menu(short i); |
43 | void handle_event(EventRecord *e); |
44 | void handle_timer(void); |
45 | void logger_vprintf(const char *format, va_list ap); |
46 | |
47 | short |
48 | main(cntrlParam *p, DCtlPtr d, short n) |
49 | { |
50 | if (d->dCtlStorage == 0) { |
51 | /* no global memory allocated by THINK C stub */ |
52 | if (n == 0) { /* open request */ |
53 | SysBeep(3); |
54 | CloseDriver(d->dCtlRefNum); |
55 | return -1; |
56 | } |
57 | return 0; |
58 | } |
59 | |
60 | if (dce == NULL) { |
61 | util_init(d); |
62 | SysEnvirons(1, &world); |
63 | } |
64 | |
65 | dce = d; |
66 | dce->dCtlFlags &= ~dCtlEnable; |
67 | |
68 | switch (n) { |
69 | case 0: |
70 | da_open(); |
71 | break; |
72 | case 2: |
73 | da_control(p->csCode, p->csParam); |
74 | break; |
75 | case 4: |
76 | da_close(); |
77 | break; |
78 | } |
79 | |
80 | dce->dCtlFlags |= dCtlEnable; |
81 | |
82 | return 0; |
83 | } |
84 | |
85 | /* |
86 | * This is called each time the DA is selected from the Apple menu, |
87 | * even if we're already open. However, the Device Manager resets |
88 | * the "dCtlFlags", "dCtlMenu", "dCtlDelay", and "dCtlEMask" fields |
89 | * of the device control entry from the corresponding fields of the |
90 | * device header each time the desk accessory is opened. |
91 | */ |
92 | void |
93 | da_open(void) |
94 | { |
95 | Str255 str; |
96 | CursHandle h; |
97 | Rect bounds; |
98 | bool dispose; |
99 | |
100 | dce->dCtlFlags |= dNeedLock | dNeedTime | dNeedGoodBye; |
101 | dce->dCtlDelay = 61; |
102 | |
103 | if (wifi_da.win) |
104 | SelectWindow(wifi_da.win); |
105 | |
106 | if (wifi_da.state != STATE_CLOSED) { |
107 | dce->dCtlMenu = menuID; |
108 | return; |
109 | } |
110 | |
111 | wifi_da.state = STATE_INIT; |
112 | memset(&wifi_cur_info, 0, sizeof(wifi_cur_info)); |
113 | memset(&wifi_scan_networks, 0, sizeof(wifi_scan_networks)); |
114 | |
115 | SetResLoad(false); |
116 | h = GetCursor(watchCursor); |
117 | dispose = (GetHandleSize((Handle)h) == 0); |
118 | SetResLoad(true); |
119 | BlockMove(*(h = GetCursor(watchCursor)), &watch, sizeof(Cursor)); |
120 | if (dispose) |
121 | ReleaseResource((Handle)h); |
122 | |
123 | if (!ON_SYSTEM_7) { |
124 | dce->dCtlMenu = menuID = OwnedResourceID(MAIN_MENU_ID); |
125 | menu = GetMenu(menuID); |
126 | (**menu).menuID = menuID; |
127 | menu = GetMenu(menuID); |
128 | GetIndString(str, find_str_res_id(), STR_ABOUT_WIFI_ID); |
129 | SetItem(menu, MAIN_MENU_ABOUT_ID, str); |
130 | InsertMenu(menu, 0); |
131 | DrawMenuBar(); |
132 | } |
133 | |
134 | create_window(dce->dCtlRefNum); |
135 | dce->dCtlWindow = wifi_da.win; |
136 | |
137 | HiliteMenu(0); |
138 | } |
139 | |
140 | void |
141 | da_control(short code, short *param) |
142 | { |
143 | switch (code) { |
144 | case accMenu: |
145 | handle_menu(param[1]); |
146 | break; |
147 | case accEvent: |
148 | handle_event(*((EventRecord **)param)); |
149 | break; |
150 | case accRun: |
151 | handle_timer(); |
152 | break; |
153 | case goodbye: |
154 | break; |
155 | } |
156 | } |
157 | |
158 | void |
159 | da_close(void) |
160 | { |
161 | WindowPtr win; |
162 | |
163 | if (!ON_SYSTEM_7) { |
164 | DeleteMenu(dce->dCtlMenu); |
165 | DrawMenuBar(); |
166 | DisposeMenu(menu); |
167 | } |
168 | |
169 | dce->dCtlMenu = 0; |
170 | destroy_windows(); |
171 | dce->dCtlWindow = 0; |
172 | wifi_da.state = STATE_CLOSED; |
173 | } |
174 | |
175 | bool |
176 | handle_menu(short i) |
177 | { |
178 | bool ret = true; |
179 | |
180 | switch (i) { |
181 | case MAIN_MENU_ABOUT_ID: |
182 | wifi_about(); |
183 | break; |
184 | case MAIN_MENU_QUIT_ID: |
185 | CloseDriver(dce->dCtlRefNum); |
186 | break; |
187 | default: |
188 | ret = false; |
189 | } |
190 | |
191 | HiliteMenu(0); |
192 | return ret; |
193 | } |
194 | |
195 | void |
196 | handle_event(EventRecord *e) |
197 | { |
198 | short key, mk; |
199 | |
200 | switch (e->what) { |
201 | case updateEvt: |
202 | update_window(false); |
203 | break; |
204 | case mouseDown: |
205 | window_mousedown(e->where); |
206 | update_window(false); |
207 | break; |
208 | case activateEvt: |
209 | activate_window((bool)(e->modifiers & activeFlag)); |
210 | break; |
211 | case keyDown: |
212 | case autoKey: |
213 | key = e->message & charCodeMask; |
214 | if ((e->modifiers & cmdKey) != 0) { |
215 | mk = MenuKey(key); |
216 | if (mk != 0 && handle_menu(mk)) |
217 | break; |
218 | } |
219 | break; |
220 | } |
221 | } |
222 | |
223 | void |
224 | handle_timer(void) |
225 | { |
226 | static long last_update = 0; |
227 | static long last_scan = 0; |
228 | |
229 | if (!wifi_da.win) |
230 | return; |
231 | |
232 | switch (wifi_da.state) { |
233 | case STATE_SCANNING: |
234 | /* check every second */ |
235 | if ((Ticks - last_update) < (60 * 1)) |
236 | break; |
237 | logger_printf("%ld - handle_timer - checking for scan completion", |
238 | Ticks); |
239 | last_update = Ticks; |
240 | if (!scsi_wifi_scan_finished(wifi_scsi_id)) { |
241 | logger_printf("%ld - handle_timer - scan not done", Ticks); |
242 | if (Time - wifi_scan_started <= 5) |
243 | break; |
244 | logger_printf("Wi-Fi scan failed to finish, canceling"); |
245 | } |
246 | last_scan = Ticks; |
247 | wifi_da.state = STATE_IDLE; |
248 | logger_printf("%ld - handle_timer - scan done, updating list", |
249 | Ticks); |
250 | update_wifi_ssid_list(true); |
251 | break; |
252 | case STATE_IDLE: |
253 | /* refresh SSID/RSSI every 5 seconds, scan every 30 */ |
254 | if ((Ticks - last_update) < (60 * 5)) |
255 | break; |
256 | last_update = Ticks; |
257 | |
258 | if ((Ticks - last_scan) > (60 * 30)) { |
259 | wifi_da.state = STATE_SCANNING; |
260 | logger_printf("%ld - handle_timer - idle, scanning", Ticks); |
261 | scsi_wifi_scan(wifi_scsi_id); |
262 | } else { |
263 | logger_printf("%ld - handle_timer - idle, updating info", |
264 | Ticks); |
265 | update_wifi_cur_info(); |
266 | } |
267 | break; |
268 | } |
269 | } |
270 | |
271 | void |
272 | logger_printf(const char *format, ...) |
273 | { |
274 | va_list va; |
275 | |
276 | if (!wifi_da.logger) |
277 | return; |
278 | |
279 | va_start(va, format); |
280 | logger_vprintf(format, va); |
281 | va_end(va); |
282 | } |
283 | |
284 | void |
285 | logger_vprintf(const char *format, va_list ap) |
286 | { |
287 | static char buf[256]; |
288 | GrafPtr savePort; |
289 | ssize_t len; |
290 | RgnHandle clip; |
291 | |
292 | if (!wifi_da.logger) |
293 | return; |
294 | |
295 | len = vsnprintf(buf, sizeof(buf), format, ap); |
296 | |
297 | GetPort(&savePort); |
298 | SetPort(wifi_da.logger); |
299 | |
300 | clip = NewRgn(); |
301 | ScrollRect(&wifi_da.logger->portRect, 0, -11, clip); |
302 | DisposeRgn(clip); |
303 | |
304 | MoveTo(4, wifi_da.logger->portRect.bottom - 4); |
305 | TextFont(geneva); |
306 | TextSize(9); |
307 | DrawText(buf, 0, len); |
308 | |
309 | ValidRect(&wifi_da.logger->portRect); |
310 | SetPort(savePort); |
311 | } |
312 | |
313 | short |
314 | find_str_res_id(void) |
315 | { |
316 | Handle itlb_h, str_h; |
317 | ItlbRecord itlb; |
318 | short str_res_id; |
319 | |
320 | /* find language of this system */ |
321 | str_res_id = OwnedResourceID(STR_BASE_ID); |
322 | itlb_h = GetResource('itlb', 0); |
323 | if (itlb_h != NULL) { |
324 | HLock(itlb_h); |
325 | itlb = *(ItlbRecord *)(*itlb_h); |
326 | ReleaseResource(itlb_h); |
327 | |
328 | str_h = GetResource('STR#', str_res_id + itlb.itlbLang); |
329 | if (str_h != NULL) { |
330 | /* we have strings in this language */ |
331 | str_res_id += itlb.itlbLang; |
332 | ReleaseResource(str_h); |
333 | return str_res_id; |
334 | } |
335 | } |
336 | |
337 | /* fall back to english (itlbLang 0) */ |
338 | str_h = GetResource('STR#', str_res_id); |
339 | if (str_h == NULL) |
340 | panic("Can't find STR# %d", str_res_id); |
341 | ReleaseResource(str_h); |
342 | |
343 | return str_res_id; |
344 | } |