/* * Copyright (c) 2023 joshua stein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include "wi-fi.h" /* device control entry */ DCtlPtr dce = NULL; SysEnvRec world; #define ON_SYSTEM_7 (world.systemVersion >= 0x0700) struct wifi_da wifi_da = { 0 }; short wifi_scsi_id = WIFI_SCSI_ID_FINDING; unsigned long wifi_scan_started = 0; struct wifi_network_entry wifi_cur_info; struct wifi_network_entry wifi_scan_networks[10]; MenuHandle menu, apple_menu; short menuID = 0; Cursor watch; short main(cntrlParam *p, DCtlPtr d, short n); void da_open(void); void da_control(short code, short *param); void da_close(void); bool handle_menu(short i); void handle_event(EventRecord *e); void handle_timer(void); void logger_vprintf(const char *format, va_list ap); short main(cntrlParam *p, DCtlPtr d, short n) { if (d->dCtlStorage == 0) { /* no global memory allocated by THINK C stub */ if (n == 0) { /* open request */ SysBeep(3); CloseDriver(d->dCtlRefNum); return -1; } return 0; } if (dce == NULL) { util_init(d); SysEnvirons(1, &world); } dce = d; dce->dCtlFlags &= ~dCtlEnable; switch (n) { case 0: da_open(); break; case 2: da_control(p->csCode, p->csParam); break; case 4: da_close(); break; } dce->dCtlFlags |= dCtlEnable; return 0; } /* * This is called each time the DA is selected from the Apple menu, * even if we're already open. However, the Device Manager resets * the "dCtlFlags", "dCtlMenu", "dCtlDelay", and "dCtlEMask" fields * of the device control entry from the corresponding fields of the * device header each time the desk accessory is opened. */ void da_open(void) { Str255 str; CursHandle h; Rect bounds; bool dispose; dce->dCtlFlags |= dNeedLock | dNeedTime | dNeedGoodBye; dce->dCtlDelay = 61; if (wifi_da.win) SelectWindow(wifi_da.win); if (wifi_da.state != STATE_CLOSED) { dce->dCtlMenu = menuID; return; } wifi_da.state = STATE_INIT; memset(&wifi_cur_info, 0, sizeof(wifi_cur_info)); memset(&wifi_scan_networks, 0, sizeof(wifi_scan_networks)); SetResLoad(false); h = GetCursor(watchCursor); dispose = (GetHandleSize((Handle)h) == 0); SetResLoad(true); BlockMove(*(h = GetCursor(watchCursor)), &watch, sizeof(Cursor)); if (dispose) ReleaseResource((Handle)h); if (!ON_SYSTEM_7) { dce->dCtlMenu = menuID = OwnedResourceID(MAIN_MENU_ID); menu = GetMenu(menuID); (**menu).menuID = menuID; menu = GetMenu(menuID); GetIndString(str, find_str_res_id(), STR_ABOUT_WIFI_ID); SetItem(menu, MAIN_MENU_ABOUT_ID, str); InsertMenu(menu, 0); DrawMenuBar(); } create_window(dce->dCtlRefNum); dce->dCtlWindow = wifi_da.win; HiliteMenu(0); } void da_control(short code, short *param) { switch (code) { case accMenu: handle_menu(param[1]); break; case accEvent: handle_event(*((EventRecord **)param)); break; case accRun: handle_timer(); break; case goodbye: break; } } void da_close(void) { WindowPtr win; if (!ON_SYSTEM_7) { DeleteMenu(dce->dCtlMenu); DrawMenuBar(); DisposeMenu(menu); } dce->dCtlMenu = 0; destroy_windows(); dce->dCtlWindow = 0; wifi_da.state = STATE_CLOSED; } bool handle_menu(short i) { bool ret = true; switch (i) { case MAIN_MENU_ABOUT_ID: wifi_about(); break; case MAIN_MENU_QUIT_ID: CloseDriver(dce->dCtlRefNum); break; default: ret = false; } HiliteMenu(0); return ret; } void handle_event(EventRecord *e) { short key, mk; switch (e->what) { case updateEvt: update_window(false); break; case mouseDown: window_mousedown(e->where); update_window(false); break; case activateEvt: activate_window((bool)(e->modifiers & activeFlag)); break; case keyDown: case autoKey: key = e->message & charCodeMask; if ((e->modifiers & cmdKey) != 0) { mk = MenuKey(key); if (mk != 0 && handle_menu(mk)) break; } break; } } void handle_timer(void) { static long last_update = 0; static long last_scan = 0; if (!wifi_da.win) return; switch (wifi_da.state) { case STATE_SCANNING: /* check every second */ if ((Ticks - last_update) < (60 * 1)) break; logger_printf("%ld - handle_timer - checking for scan completion", Ticks); last_update = Ticks; if (!scsi_wifi_scan_finished(wifi_scsi_id)) { logger_printf("%ld - handle_timer - scan not done", Ticks); if (Time - wifi_scan_started <= 5) break; logger_printf("Wi-Fi scan failed to finish, canceling"); } last_scan = Ticks; wifi_da.state = STATE_IDLE; logger_printf("%ld - handle_timer - scan done, updating list", Ticks); update_wifi_ssid_list(true); break; case STATE_IDLE: /* refresh SSID/RSSI every 5 seconds, scan every 30 */ if ((Ticks - last_update) < (60 * 5)) break; last_update = Ticks; if ((Ticks - last_scan) > (60 * 30)) { wifi_da.state = STATE_SCANNING; logger_printf("%ld - handle_timer - idle, scanning", Ticks); scsi_wifi_scan(wifi_scsi_id); } else { logger_printf("%ld - handle_timer - idle, updating info", Ticks); update_wifi_cur_info(); } break; } } void logger_printf(const char *format, ...) { va_list va; if (!wifi_da.logger) return; va_start(va, format); logger_vprintf(format, va); va_end(va); } void logger_vprintf(const char *format, va_list ap) { static char buf[256]; GrafPtr savePort; ssize_t len; RgnHandle clip; if (!wifi_da.logger) return; len = vsnprintf(buf, sizeof(buf), format, ap); GetPort(&savePort); SetPort(wifi_da.logger); clip = NewRgn(); ScrollRect(&wifi_da.logger->portRect, 0, -11, clip); DisposeRgn(clip); MoveTo(4, wifi_da.logger->portRect.bottom - 4); TextFont(geneva); TextSize(9); DrawText(buf, 0, len); ValidRect(&wifi_da.logger->portRect); SetPort(savePort); } short find_str_res_id(void) { Handle itlb_h, str_h; ItlbRecord itlb; short str_res_id; /* find language of this system */ str_res_id = OwnedResourceID(STR_BASE_ID); itlb_h = GetResource('itlb', 0); if (itlb_h != NULL) { HLock(itlb_h); itlb = *(ItlbRecord *)(*itlb_h); ReleaseResource(itlb_h); str_h = GetResource('STR#', str_res_id + itlb.itlbLang); if (str_h != NULL) { /* we have strings in this language */ str_res_id += itlb.itlbLang; ReleaseResource(str_h); return str_res_id; } } /* fall back to english (itlbLang 0) */ str_h = GetResource('STR#', str_res_id); if (str_h == NULL) panic("Can't find STR# %d", str_res_id); ReleaseResource(str_h); return str_res_id; }