├── .gitignore ├── CMakeLists.txt ├── Comms.cpp ├── Comms.h ├── MacWifi.cpp ├── MacWifi.h ├── MacWifi.sln ├── MacWifi.vcxproj ├── MacWifiLib.cpp ├── MacWifiLib.h ├── MacWifiTest.cpp ├── MacWifiTest.r ├── Modules ├── OpenWRT.cpp ├── OpenWRT.h ├── VM300.cpp ├── VM300.h ├── WifiModule.cpp └── WifiModule.h ├── Prefs.cpp ├── Prefs.h ├── README.md ├── ShowInitIcon.c ├── ShowInitIcon.h ├── Util.cpp ├── Util.h ├── WifiEvents.h ├── WifiShared.h ├── iconv.hpp ├── resources.r ├── sysmenu.cpp └── sysmenu.h /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | /.vs 3 | /Debug -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | add_executable(MacWifiINIT 4 | sysmenu.cpp 5 | Util.cpp 6 | ShowInitIcon.c 7 | resources.r 8 | ) 9 | 10 | target_link_libraries(MacWifiINIT) 11 | 12 | # See: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html 13 | SET(CMAKE_CXX_FLAGS "-Ofast") 14 | 15 | set_target_properties(MacWifiINIT PROPERTIES 16 | COMPILE_OPTIONS -ffunction-sections # make things smaller 17 | 18 | # set a linker flag that says we want a flat piece 19 | # of code in a data file, specify entry point, 20 | # and add -Wl,-gc-sections to make things smaller. 21 | LINK_FLAGS "-Wl,--mac-flat -Wl,-gc-sections" 22 | ) 23 | 24 | # wrap the compiled INIT into a resource 25 | add_custom_command( 26 | OUTPUT MacWifiINIT.rsrc.bin 27 | COMMAND ${REZ} -I ${REZ_INCLUDE_PATH} 28 | ${CMAKE_CURRENT_SOURCE_DIR}/resources.r 29 | -o MacWifiINIT.rsrc.bin 30 | DEPENDS MacWifiINIT resources.r 31 | ) 32 | 33 | # Now build the application 34 | add_application(MacWifi 35 | MacWifi.cpp 36 | resources.r 37 | Modules/WifiModule.cpp 38 | Modules/VM300.cpp 39 | Modules/OpenWRT.cpp 40 | Comms.cpp 41 | Util.cpp 42 | Prefs.cpp 43 | 44 | # the separately compiled WDEF resource 45 | ${CMAKE_CURRENT_BINARY_DIR}/MacWifiINIT.rsrc.bin 46 | 47 | TYPE "appe" # application extension 48 | CREATOR "MWFI" 49 | ) 50 | 51 | target_link_libraries(MacWifi MacHTTP MacTCPHelper gason iconv charset) 52 | 53 | # again, add some options to make things smaller. 54 | set_target_properties(MacWifi PROPERTIES COMPILE_OPTIONS -ffunction-sections) 55 | set_target_properties(MacWifi PROPERTIES LINK_FLAGS "-Wl,-gc-sections") 56 | 57 | # MacWifi client library 58 | add_library(MacWifiLib STATIC 59 | MacWifiLib.cpp 60 | ) 61 | 62 | install(TARGETS MacWifiLib 63 | DESTINATION "lib" 64 | ) 65 | 66 | install(FILES MacWifiLib.h WifiEvents.h 67 | DESTINATION "include/macwifi" 68 | ) 69 | 70 | set_target_properties(MacWifiLib PROPERTIES COMPILE_OPTIONS -ffunction-sections) 71 | set_target_properties(MacWifiLib PROPERTIES LINK_FLAGS "-Wl,-gc-sections") 72 | 73 | add_application(MacWifiTest 74 | MacWifiTest.cpp 75 | MacWifiTest.r 76 | Util.cpp 77 | CONSOLE 78 | ) 79 | 80 | target_link_libraries(MacWifiTest MacWifiLib) 81 | 82 | set_target_properties(MacWifiTest PROPERTIES COMPILE_OPTIONS -ffunction-sections) 83 | set_target_properties(MacWifiTest PROPERTIES LINK_FLAGS "-Wl,-gc-sections") 84 | -------------------------------------------------------------------------------- /Comms.cpp: -------------------------------------------------------------------------------- 1 | #include "Comms.h" 2 | 3 | HttpClient Comms::Http; -------------------------------------------------------------------------------- /Comms.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Comms 4 | { 5 | public: 6 | static HttpClient Http; 7 | }; 8 | 9 | -------------------------------------------------------------------------------- /MacWifi.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "iconv.hpp" 6 | #include "WifiShared.h" 7 | #include "MacWifi.h" 8 | #include "Prefs.h" 9 | #include "WifiEvents.h" 10 | #include "Modules\VM300.h" 11 | #include "Modules\OpenWRT.h" 12 | 13 | WifiModule* _wifiModule; 14 | WifiData* _sharedDataPtr; 15 | Prefs _prefs; 16 | iconvpp::converter _conv("MACROMAN//TRANSLIT", "UTF-8", true, 1024); 17 | 18 | int main() 19 | { 20 | EventRecord event; 21 | 22 | EventInit(); 23 | GetSharedData(); 24 | GetPrefs(); 25 | GetWifiModule(); 26 | 27 | while (_run) 28 | { 29 | if (WaitNextEvent(everyEvent, &event, 0, NULL)) 30 | { 31 | switch (event.what) 32 | { 33 | case kHighLevelEvent: 34 | AEProcessAppleEvent(&event); 35 | break; 36 | } 37 | } 38 | else 39 | { 40 | switch (_sharedDataPtr->Status) 41 | { 42 | case ScanRequest: 43 | _sharedDataPtr->Status = Scanning; 44 | _sharedDataPtr->Error = false; 45 | 46 | _wifiModule->GetNetworks(); 47 | break; 48 | 49 | case ConnectRequest: 50 | _sharedDataPtr->Status = Connecting; 51 | _sharedDataPtr->Error = false; 52 | 53 | _wifiModule->Connect( 54 | std::string(_sharedDataPtr->ConnectName), 55 | std::string(_sharedDataPtr->ConnectId), 56 | _sharedDataPtr->ConnectMode, 57 | _sharedDataPtr->ConnectEncryption, 58 | std::string(_sharedDataPtr->ConnectPwd)); 59 | break; 60 | 61 | case RestartRequest: 62 | _sharedDataPtr->Status = Restarting; 63 | _sharedDataPtr->Error = false; 64 | Restart(); 65 | break; 66 | 67 | case SavePrefsRequest: 68 | SavePrefs(); 69 | _sharedDataPtr->Status = ScanRequest; 70 | _sharedDataPtr->Error = false; 71 | _sharedDataPtr->UpdateUI = true; 72 | break; 73 | } 74 | 75 | Comms::Http.ProcessRequests(); 76 | } 77 | } 78 | } 79 | 80 | void GetSharedData() 81 | { 82 | MemLocHandle memHandle = (MemLocHandle)Get1Resource('memr', 128); 83 | 84 | if (ResError() != resNotFound) 85 | { 86 | _sharedDataPtr = (WifiData*)**memHandle; 87 | 88 | RemoveResource((Handle)memHandle); 89 | UpdateResFile(CurResFile()); 90 | ReleaseResource((Handle)memHandle); 91 | } 92 | } 93 | 94 | void GetPrefs() 95 | { 96 | memset(_sharedDataPtr->Hostname, 0, sizeof(_sharedDataPtr->Hostname)); 97 | memset(_sharedDataPtr->Username, 0, sizeof(_sharedDataPtr->Username)); 98 | memset(_sharedDataPtr->Password, 0, sizeof(_sharedDataPtr->Password)); 99 | 100 | if (_prefs.Data.Device > 0) 101 | { 102 | _sharedDataPtr->Device = _prefs.Data.Device; 103 | strcpy(_sharedDataPtr->Hostname, _prefs.Data.Hostname); 104 | strcpy(_sharedDataPtr->Username, _prefs.Data.Username); 105 | strcpy(_sharedDataPtr->Password, _prefs.Data.Password); 106 | } 107 | else 108 | { 109 | // Default to Vonets default settings 110 | _sharedDataPtr->Device = 1; 111 | strcpy(_sharedDataPtr->Hostname, "vonets.cfg"); 112 | strcpy(_sharedDataPtr->Username, "admin"); 113 | strcpy(_sharedDataPtr->Password, "admin"); 114 | } 115 | } 116 | 117 | void GetWifiModule() 118 | { 119 | switch (_sharedDataPtr->Device) 120 | { 121 | case 2: 122 | _wifiModule = new OpenWRT; 123 | break; 124 | 125 | default: 126 | _wifiModule = new VM300; 127 | break; 128 | } 129 | 130 | _wifiModule->WifiDataPtr = _sharedDataPtr; 131 | } 132 | 133 | void EventInit() 134 | { 135 | AEInstallEventHandler( 136 | kCoreEventClass, 137 | kAEQuitApplication, 138 | (AEEventHandlerUPP)Quit, 139 | 0L, 140 | false); 141 | 142 | AEInstallEventHandler( 143 | kWifiClass, 144 | kRequest, 145 | (AEEventHandlerUPP)ProcessRequestEvent, 146 | 0L, 147 | false); 148 | } 149 | 150 | void Restart() 151 | { 152 | AEDesc finderAddr = { typeNull, nil }; 153 | AppleEvent myShutDown = { typeNull, nil }; 154 | AppleEvent nilReply = { typeNull, nil }; 155 | OSErr errCode; 156 | OSType finderSig = 'MACS'; 157 | 158 | errCode = AECreateDesc(typeApplSignature, &finderSig, sizeof(OSType), &finderAddr); 159 | 160 | if (noErr == errCode) { 161 | errCode = AECreateAppleEvent(kAEFinderEvents, kAERestart, 162 | &finderAddr, kAutoGenerateReturnID, 163 | kAnyTransactionID, &myShutDown); 164 | } 165 | 166 | if (noErr == errCode) { 167 | errCode = AESend(&myShutDown, &nilReply, 168 | kAENoReply + kAECanSwitchLayer + kAEAlwaysInteract, 169 | kAENormalPriority, kAEDefaultTimeout, nil, nil); 170 | } 171 | 172 | AEDisposeDesc(&finderAddr); 173 | AEDisposeDesc(&myShutDown); 174 | AEDisposeDesc(&nilReply); 175 | } 176 | 177 | void SavePrefs() 178 | { 179 | _prefs.Data.Device = _sharedDataPtr->Device; 180 | strcpy(_prefs.Data.Hostname, _sharedDataPtr->Hostname); 181 | strcpy(_prefs.Data.Username, _sharedDataPtr->Username); 182 | strcpy(_prefs.Data.Password, _sharedDataPtr->Password); 183 | _prefs.Save(); 184 | 185 | GetWifiModule(); 186 | } 187 | 188 | pascal OSErr ProcessRequestEvent(AppleEvent* appleEvent, AppleEvent* reply, long refCon) 189 | { 190 | Size actualSize; 191 | DescType typeCode; 192 | EventRecord event; 193 | string method, url, authorization, data; 194 | bool utf8ToMacRoman; 195 | int callbackId; 196 | 197 | GetParamAsString(appleEvent, kMethodParam, method); 198 | GetParamAsString(appleEvent, kUriParam, url); 199 | GetParamAsString(appleEvent, kAuthorizationParam, authorization); 200 | GetParamAsString(appleEvent, kDataParam, data); 201 | AEGetParamPtr(appleEvent, kUtf8ToMacRomanParam, typeBoolean, &typeCode, &utf8ToMacRoman, sizeof(bool), &actualSize); 202 | AEGetParamPtr(appleEvent, kCallbackIdParam, typeInteger, &typeCode, &callbackId, sizeof(int), &actualSize); 203 | 204 | try 205 | { 206 | Uri uri(url); 207 | 208 | _requestStatus = Init; 209 | while (_requestStatus != Complete) 210 | { 211 | WaitNextEvent(everyEvent - highLevelEventMask, &event, 0, NULL); 212 | 213 | switch (_requestStatus) 214 | { 215 | case Init: 216 | InitTunnel(uri); 217 | break; 218 | 219 | case Request: 220 | DoRequest(method, uri, authorization, data); 221 | break; 222 | } 223 | 224 | Comms::Http.ProcessRequests(); 225 | } 226 | } 227 | catch (const invalid_argument& e) 228 | { 229 | DoError("Invalid request uri."); 230 | } 231 | 232 | string content; 233 | 234 | if (utf8ToMacRoman) 235 | { 236 | _conv.convert(_response.Content, content); 237 | } 238 | else 239 | { 240 | content = _response.Content; 241 | } 242 | 243 | const char* cErrorMsg = _response.ErrorMsg.c_str(); 244 | vector v(content.begin(), content.end()); 245 | const char* cContent = &v[0]; 246 | 247 | AEPutParamPtr(reply, kCallbackIdParam, typeInteger, &callbackId, sizeof(int)); 248 | AEPutParamPtr(reply, kSuccessParam, typeBoolean, &_response.Success, sizeof(bool)); 249 | AEPutParamPtr(reply, kStatusCodeParam, typeInteger, &_response.StatusCode, sizeof(int)); 250 | AEPutParamPtr(reply, kErrorMsgParam, typeChar, cErrorMsg, strlen(cErrorMsg)); 251 | AEPutParamPtr(reply, kContentParam, typeChar, cContent, content.size()); 252 | 253 | return noErr; 254 | } 255 | 256 | void GetParamAsString(AppleEvent* appleEvent, AEKeyword keyword, string &output) 257 | { 258 | DescType typeCode; 259 | Size sizeOfParam, actualSize; 260 | char* buffer; 261 | string retVal; 262 | 263 | AESizeOfParam(appleEvent, keyword, &typeCode, &sizeOfParam); 264 | buffer = (char*)NewPtr(sizeOfParam + 2); 265 | 266 | AEGetParamPtr(appleEvent, keyword, typeChar, &typeCode, buffer, sizeOfParam + 1, &actualSize); 267 | buffer[actualSize] = '\0'; 268 | 269 | output.assign(buffer, actualSize); 270 | DisposePtr(buffer); 271 | } 272 | 273 | void InitTunnel(Uri uri) 274 | { 275 | Comms::Http.SetStunnel("", 0); 276 | 277 | if (uri.Scheme == "https") 278 | { 279 | _requestStatus = Processing; 280 | _wifiModule->GetTunnel(uri.Host, InitTunnelComplete); 281 | } 282 | else 283 | { 284 | _requestStatus = Request; 285 | } 286 | } 287 | 288 | void InitTunnelComplete(GetTunnelResult result) 289 | { 290 | if (result.Success) 291 | { 292 | Comms::Http.SetStunnel(result.Host, result.Port); 293 | _requestStatus = Request; 294 | } 295 | else 296 | { 297 | DoError(result.ErrorMsg); 298 | } 299 | } 300 | 301 | void DoRequest(string method, Uri uri, string authorization, string data) 302 | { 303 | Comms::Http.SetAuthorization(authorization); 304 | 305 | if (method == "GET") 306 | { 307 | Comms::Http.Get(uri, RequestComplete); 308 | } 309 | else if (method == "POST") 310 | { 311 | Comms::Http.Post(uri, data, RequestComplete); 312 | } 313 | else if (method == "PUT") 314 | { 315 | Comms::Http.Put(uri, data, RequestComplete); 316 | } 317 | 318 | _requestStatus = Processing; 319 | } 320 | 321 | void RequestComplete(HttpResponse response) 322 | { 323 | _requestStatus = Complete; 324 | _response = response; 325 | } 326 | 327 | void DoError(string errorMsg) 328 | { 329 | HttpResponse response; 330 | 331 | response.Success = false; 332 | response.StatusCode = -1; 333 | response.ErrorMsg = errorMsg; 334 | 335 | _response = response; 336 | _requestStatus = Complete; 337 | } 338 | 339 | pascal OSErr Quit(AppleEvent* appleEvent, AppleEvent* reply, long refCon) 340 | { 341 | _run = false; 342 | } -------------------------------------------------------------------------------- /MacWifi.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "Modules\WifiModule.h" 3 | 4 | typedef int MemLoc; 5 | typedef MemLoc* MemLocPtr; 6 | typedef MemLocPtr* MemLocHandle; 7 | 8 | enum RequestStatus 9 | { 10 | Init, 11 | Request, 12 | Processing, 13 | Complete 14 | }; 15 | 16 | bool _run = true; 17 | 18 | int main(); 19 | void GetSharedData(); 20 | void EventInit(); 21 | void GetPrefs(); 22 | void GetWifiModule(); 23 | void Restart(); 24 | void SavePrefs(); 25 | void InitTunnel(Uri uri); 26 | void InitTunnelComplete(GetTunnelResult result); 27 | void DoRequest(string method, Uri uri, string authorization, string data); 28 | void RequestComplete(HttpResponse response); 29 | void DoError(string errorMsg); 30 | void GetParamAsString(AppleEvent* appleEvent, AEKeyword keyword, string &output); 31 | 32 | RequestStatus _requestStatus; 33 | HttpResponse _response; 34 | 35 | pascal OSErr ProcessRequestEvent(AppleEvent* appleEvent, AppleEvent* reply, long refCon); 36 | pascal OSErr Quit(AppleEvent* appleEvent, AppleEvent* reply, long refCon); -------------------------------------------------------------------------------- /MacWifi.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27004.2009 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MacWifi", "MacWifi.vcxproj", "{746DC640-3FE3-4F44-B0A3-371940591DC8}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {746DC640-3FE3-4F44-B0A3-371940591DC8}.Debug|x64.ActiveCfg = Debug|x64 17 | {746DC640-3FE3-4F44-B0A3-371940591DC8}.Debug|x64.Build.0 = Debug|x64 18 | {746DC640-3FE3-4F44-B0A3-371940591DC8}.Debug|x86.ActiveCfg = Debug|Win32 19 | {746DC640-3FE3-4F44-B0A3-371940591DC8}.Debug|x86.Build.0 = Debug|Win32 20 | {746DC640-3FE3-4F44-B0A3-371940591DC8}.Release|x64.ActiveCfg = Release|x64 21 | {746DC640-3FE3-4F44-B0A3-371940591DC8}.Release|x64.Build.0 = Release|x64 22 | {746DC640-3FE3-4F44-B0A3-371940591DC8}.Release|x86.ActiveCfg = Release|Win32 23 | {746DC640-3FE3-4F44-B0A3-371940591DC8}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {CD4920A5-A52C-4A22-9497-434AC0F16B79} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /MacWifi.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {5C382B6E-788C-4D06-8CA9-93E61469652B} 24 | Win32Proj 25 | 26 | 27 | 28 | Makefile 29 | true 30 | v141 31 | 32 | 33 | Makefile 34 | false 35 | v141 36 | 37 | 38 | Makefile 39 | true 40 | v141 41 | 42 | 43 | Makefile 44 | false 45 | v141 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | set errorlevel=0 67 | cd $(ProjectDir)$(Configuration) 68 | make clean 69 | cmake .. -DCMAKE_TOOLCHAIN_FILE=~/Retro68-build/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake 70 | make 71 | xcopy *.APPL "C:\Users\AnthonySuper\OneDrive\Documents\Personal\Mac\Apps\BasiliskII\Virtual Desktop\" /y /s 72 | $(ProjectName).exe 73 | WIN32_DEBUG;$(NMakePreprocessorDefinitions) 74 | C:\cygwin64\home\AnthonySuper\Retro68-build\toolchain\CIncludes;C:\cygwin64\home\AnthonySuper\Retro68-build\toolchain\m68k-apple-macos\include 75 | $(VC_SourcePath); 76 | set errorlevel=0 77 | cd $(ProjectDir)$(Configuration) 78 | make clean 79 | cmake .. -DCMAKE_TOOLCHAIN_FILE=~/Retro68-build/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake 80 | make 81 | xcopy *.APPL "C:\Users\AnthonySuper\OneDrive\Documents\Personal\Mac\Apps\BasiliskII\Virtual Desktop\" /y /s 82 | 83 | 84 | set errorlevel=0 85 | cd $(ProjectDir)$(Configuration) 86 | cmake .. -DCMAKE_TOOLCHAIN_FILE=~/Retro68-build/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake 87 | make 88 | xcopy *.APPL "C:\Users\AnthonySuper\OneDrive\Documents\Personal\Mac\Apps\BasiliskII\Virtual Desktop\" /y /s 89 | $(ProjectName).exe 90 | _DEBUG;$(NMakePreprocessorDefinitions) 91 | C:\cygwin64\home\AnthonySuper\Retro68-build\toolchain\CIncludes;C:\cygwin64\home\AnthonySuper\Retro68-build\toolchain\m68k-apple-macos\include 92 | 93 | 94 | test_command 95 | $(ProjectName).exe 96 | WIN32NDEBUG;$(NMakePreprocessorDefinitions) 97 | 98 | 99 | test_command 100 | $(ProjectName).exe 101 | NDEBUG;$(NMakePreprocessorDefinitions) 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /MacWifiLib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "MacWifiLib.h" 6 | #include "Util.h" 7 | 8 | MacWifiLib::MacWifiLib() 9 | { 10 | _authorization = ""; 11 | _utf8ToMacRoman = true; 12 | } 13 | 14 | void MacWifiLib::Get(const string& requestUri, function onComplete, long id) 15 | { 16 | SendRequestEvent("GET", requestUri, "", onComplete, id); 17 | } 18 | 19 | void MacWifiLib::Post(const string& requestUri, const string& content, function onComplete, long id) 20 | { 21 | SendRequestEvent("POST", requestUri, content, onComplete, id); 22 | } 23 | 24 | void MacWifiLib::Put(const string& requestUri, const string& content, function onComplete, long id) 25 | { 26 | SendRequestEvent("PUT", requestUri, content, onComplete, id); 27 | } 28 | 29 | void MacWifiLib::SendRequestEvent(const string& method, const string& uri, const string& content, function onComplete, long id) 30 | { 31 | AEAddressDesc address; 32 | AppleEvent appleEvent; 33 | 34 | GetEventAddress(&address); 35 | 36 | AECreateAppleEvent( 37 | kWifiClass, 38 | kRequest, 39 | &address, 40 | kAutoGenerateReturnID, 41 | 1L, 42 | &appleEvent); 43 | 44 | const char* cMethod = method.c_str(); 45 | const char* cUri = uri.c_str(); 46 | const char* cContent = content.c_str(); 47 | const char* cAuthorization = _authorization.c_str(); 48 | 49 | _callbackIndex++; 50 | MacWifiCallback callback; 51 | callback.Callback = onComplete; 52 | callback.Id = id; 53 | 54 | _callbacks.insert(pair(_callbackIndex, callback)); 55 | 56 | AEPutParamPtr(&appleEvent, kMethodParam, typeChar, cMethod, strlen(cMethod)); 57 | AEPutParamPtr(&appleEvent, kUriParam, typeChar, cUri, strlen(cUri)); 58 | AEPutParamPtr(&appleEvent, kDataParam, typeChar, cContent, strlen(cContent)); 59 | AEPutParamPtr(&appleEvent, kAuthorizationParam, typeChar, cAuthorization, strlen(cAuthorization)); 60 | AEPutParamPtr(&appleEvent, kUtf8ToMacRomanParam, typeBoolean, &_utf8ToMacRoman, sizeof(bool)); 61 | AEPutParamPtr(&appleEvent, kCallbackIdParam, typeInteger, &_callbackIndex, sizeof(int)); 62 | 63 | OSErr err = SendEvent(&appleEvent); 64 | 65 | if (err != noErr) 66 | { 67 | MacWifiResponse response; 68 | response.Success = false; 69 | response.ErrorMsg = "Cound not send event due to error " + to_string(err); 70 | onComplete(response); 71 | } 72 | } 73 | 74 | void MacWifiLib::SetAuthorization(string authorization) 75 | { 76 | _authorization = authorization; 77 | } 78 | 79 | void MacWifiLib::Utf8ToMacRoman(bool enabled) 80 | { 81 | _utf8ToMacRoman = enabled; 82 | } 83 | 84 | void MacWifiLib::GetEventAddress(AEAddressDesc* address) 85 | { 86 | OSType appSig = 'MWFI'; 87 | 88 | AECreateDesc( 89 | typeApplSignature, 90 | (Ptr)(&appSig), 91 | (Size)sizeof(appSig), 92 | address); 93 | } 94 | 95 | OSErr MacWifiLib::SendEvent(AppleEvent* appleEvent) 96 | { 97 | AppleEvent reply; 98 | OSErr err = AESend( 99 | appleEvent, 100 | &reply, 101 | kAEQueueReply, 102 | kAENormalPriority, 103 | kAEDefaultTimeout, nil, nil); 104 | 105 | return err; 106 | } 107 | 108 | OSErr MacWifiLib::ProcessReply(AppleEvent* appleEvent) 109 | { 110 | Size actualSize; 111 | DescType typeCode; 112 | MacWifiResponse response; 113 | int callbackId; 114 | 115 | AEGetParamPtr(appleEvent, kCallbackIdParam, typeInteger, &typeCode, &callbackId, sizeof(int), &actualSize); 116 | AEGetParamPtr(appleEvent, kSuccessParam, typeBoolean, &typeCode, &response.Success, sizeof(bool), &actualSize); 117 | AEGetParamPtr(appleEvent, kStatusCodeParam, typeInteger, &typeCode, &response.StatusCode, sizeof(int), &actualSize); 118 | GetParamAsString(appleEvent, kErrorMsgParam, response.ErrorMsg); 119 | GetParamAsString(appleEvent, kContentParam, response.Content); 120 | response.Id = _callbacks[callbackId].Id; 121 | 122 | _callbacks[callbackId].Callback(response); 123 | _callbacks.erase(callbackId); 124 | } 125 | 126 | void MacWifiLib::GetParamAsString(AppleEvent* appleEvent, AEKeyword keyword, string& output) 127 | { 128 | DescType typeCode; 129 | Size sizeOfParam, actualSize; 130 | char* buffer; 131 | string retVal; 132 | 133 | AESizeOfParam(appleEvent, keyword, &typeCode, &sizeOfParam); 134 | buffer = (char*)NewPtr(sizeOfParam + 2); 135 | 136 | AEGetParamPtr(appleEvent, keyword, typeChar, &typeCode, buffer, sizeOfParam + 1, &actualSize); 137 | buffer[actualSize] = '\0'; 138 | 139 | output.assign(buffer, actualSize); 140 | DisposePtr(buffer); 141 | } 142 | 143 | string MacWifiLib::Encode(const string& value) 144 | { 145 | ostringstream escaped; 146 | escaped.fill('0'); 147 | escaped << hex; 148 | 149 | for (string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) { 150 | string::value_type c = (*i); 151 | 152 | // Keep alphanumeric and other accepted characters intact 153 | if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { 154 | escaped << c; 155 | continue; 156 | } 157 | 158 | // Any other characters are percent-encoded 159 | escaped << uppercase; 160 | escaped << '%' << setw(2) << int((unsigned char)c); 161 | escaped << nouppercase; 162 | } 163 | 164 | return escaped.str(); 165 | } -------------------------------------------------------------------------------- /MacWifiLib.h: -------------------------------------------------------------------------------- 1 | #ifndef __MACWIFI__ 2 | #define __MACWIFI__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include "WifiEvents.h" 8 | 9 | using namespace std; 10 | 11 | class MacWifiResponse 12 | { 13 | public: 14 | bool Success; 15 | unsigned int StatusCode; 16 | string ErrorMsg; 17 | string Content; 18 | long Id; 19 | }; 20 | 21 | class MacWifiCallback 22 | { 23 | public: 24 | function Callback; 25 | long Id; 26 | }; 27 | 28 | class MacWifiLib 29 | { 30 | public: 31 | MacWifiLib(); 32 | void Get(const string& requestUri, function onComplete, long id = 0); 33 | void Post(const string& requestUri, const string& content, function onComplete, long id = 0); 34 | void Put(const string& requestUri, const string& content, function onComplete, long id = 0); 35 | void SetAuthorization(string authorization); 36 | OSErr ProcessReply(AppleEvent* appleEvent); 37 | static string Encode(const string &value); 38 | void Utf8ToMacRoman(bool enabled); 39 | 40 | private: 41 | OSType _appSig; 42 | string _authorization; 43 | bool _utf8ToMacRoman; 44 | map _callbacks; 45 | int _callbackIndex = 0; 46 | void SendRequestEvent(const string& method, const string& uri, const string& content, function onComplete, long id); 47 | void GetEventAddress(AEAddressDesc* address); 48 | OSErr SendEvent(AppleEvent* appleEvent); 49 | void GetParamAsString(AppleEvent* appleEvent, AEKeyword keyword, string& output); 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /MacWifiTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "MacWifiLib.h" 4 | #include "Util.h" 5 | 6 | #define arraylen(arr) ((int) (sizeof (arr) / sizeof (arr)[0])) 7 | 8 | string _requests[4][2] = 9 | { 10 | { "Small http request", "http://httpbin.org/status/418" }, 11 | { "Small https request", "https://httpbin.org/status/418" }, 12 | { "Facebook", "https://facebook.com" }, 13 | { "Google", "https://google.com" } 14 | }; 15 | 16 | bool _doRequest = true; 17 | int _curRequest = 0; 18 | MacWifiLib _wifiLib; 19 | Util _util; 20 | 21 | void DoRequest(const string& title, const string& url); 22 | void OnResponse(MacWifiResponse& response); 23 | pascal OSErr ProcessResponseEvent(AppleEvent* appleEvent, AppleEvent* reply, long refCon); 24 | 25 | int main() 26 | { 27 | EventRecord event; 28 | 29 | AEInstallEventHandler( 30 | kCoreEventClass, 31 | kAEAnswer, 32 | (AEEventHandlerUPP)ProcessResponseEvent, 33 | 0L, 34 | false); 35 | 36 | while (_curRequest < arraylen(_requests)) 37 | { 38 | if (_doRequest) 39 | { 40 | DoRequest(_requests[_curRequest][0], _requests[_curRequest][1]); 41 | } 42 | 43 | if (WaitNextEvent(everyEvent, &event, 0, NULL)) 44 | { 45 | switch (event.what) 46 | { 47 | case kHighLevelEvent: 48 | AEProcessAppleEvent(&event); 49 | break; 50 | } 51 | } 52 | } 53 | 54 | printf("All done!\n"); 55 | getchar(); getchar(); 56 | return 0; 57 | } 58 | 59 | void DoRequest(const string& title, const string& url) 60 | { 61 | printf("%s (press return)...\n", title.c_str()); 62 | fflush(stdout); 63 | getchar(); getchar(); 64 | 65 | printf("%s says:\n\n", url.c_str()); 66 | 67 | _util.StartTimer(); 68 | _wifiLib.Get(url, OnResponse); 69 | _doRequest = false; 70 | } 71 | 72 | void OnResponse(MacWifiResponse& response) 73 | { 74 | int timeTaken = _util.StopTimer(); 75 | printf("\n\nRequest took %dms.\n\n", timeTaken); 76 | 77 | printf("Status: %d\n\n", response.StatusCode); 78 | 79 | if (response.Success) 80 | { 81 | printf("\n\nContent:\n\n"); 82 | 83 | printf("%s\n\n", response.Content.c_str()); 84 | } 85 | else 86 | { 87 | printf("ERROR: %s\n\n", response.ErrorMsg.c_str()); 88 | } 89 | 90 | _curRequest++; 91 | _doRequest = true; 92 | } 93 | 94 | pascal OSErr ProcessResponseEvent(AppleEvent* appleEvent, AppleEvent* reply, long refCon) 95 | { 96 | _wifiLib.ProcessReply(appleEvent); 97 | } -------------------------------------------------------------------------------- /MacWifiTest.r: -------------------------------------------------------------------------------- 1 | #include "Processes.r" 2 | 3 | resource 'SIZE' (-1) { 4 | dontSaveScreen, 5 | acceptSuspendResumeEvents, 6 | enableOptionSwitch, 7 | canBackground, 8 | multiFinderAware, 9 | backgroundAndForeground, 10 | dontGetFrontClicks, 11 | ignoreChildDiedEvents, 12 | is32BitCompatible, 13 | isHighLevelEventAware, 14 | onlyLocalHLEvents, 15 | notStationeryAware, 16 | reserved, 17 | reserved, 18 | reserved, 19 | reserved, 20 | 3000 * 1024, 21 | 3000 * 1024 22 | }; -------------------------------------------------------------------------------- /Modules/OpenWRT.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "OpenWRT.h" 5 | 6 | void OpenWRT::Login(std::function onComplete, std::function onError) 7 | { 8 | _onLoginComplete = onComplete; 9 | _onLoginError = onError; 10 | 11 | Comms::Http.Post( 12 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/auth", 13 | "{ \"id\": 1, \"method\": \"login\", \"params\": [ \"" + string(WifiDataPtr->Username) + "\", \"" + string(WifiDataPtr->Password) + "\" ] }", 14 | std::bind(&OpenWRT::LoginResponse, this, _1)); 15 | } 16 | 17 | void OpenWRT::LoginResponse(HttpResponse& response) 18 | { 19 | if (response.Success) 20 | { 21 | if (response.StatusCode == 200) 22 | { 23 | JsonAllocator allocator; 24 | JsonValue root; 25 | JsonParseStatus status = jsonParse((char*)response.Content.c_str(), root, allocator); 26 | 27 | if (status == JSON_PARSE_OK) 28 | { 29 | if (root("error") && root("error").child("message")) 30 | { 31 | _onLoginError("Login: " + string(root("error").child("message").toString())); 32 | return; 33 | } 34 | 35 | if (root("result")) 36 | { 37 | _token = root("result").toString(); 38 | _onLoginComplete(); 39 | } 40 | else 41 | { 42 | _onLoginError("Login: No token in response."); 43 | } 44 | } 45 | else 46 | { 47 | _onLoginError("Login: Error parsing response."); 48 | } 49 | } 50 | else 51 | { 52 | _onLoginError("Login: " + std::to_string(response.StatusCode) + " status returned."); 53 | } 54 | } 55 | else 56 | { 57 | _onLoginError("Login: " + response.ErrorMsg); 58 | } 59 | } 60 | 61 | void OpenWRT::GetNetworks() 62 | { 63 | Login(std::bind(&OpenWRT::GetConnectedNetworkRequest, this), std::bind(&OpenWRT::DoError, this, _1)); 64 | } 65 | 66 | void OpenWRT::GetConnectedNetworkRequest() 67 | { 68 | Comms::Http.Post( 69 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 70 | "{ \"id\": 1, \"method\": \"get_all\", \"params\": [ \"wireless\", \"@wifi-iface[0]\" ] }", 71 | std::bind(&OpenWRT::GetConnectedNetworkResponse, this, _1)); 72 | } 73 | 74 | void OpenWRT::GetConnectedNetworkResponse(HttpResponse& response) 75 | { 76 | _currentSsid = ""; 77 | 78 | if (response.Success) 79 | { 80 | if (response.StatusCode == 200) 81 | { 82 | JsonAllocator allocator; 83 | JsonValue root; 84 | JsonParseStatus status = jsonParse((char*)response.Content.c_str(), root, allocator); 85 | 86 | if (status == JSON_PARSE_OK) 87 | { 88 | if (root("error") && root("error").child("message")) 89 | { 90 | DoError("GetConnectedNetwork: " + string(root("error")("message").toString())); 91 | return; 92 | } 93 | 94 | JsonValue network = root("result"); 95 | 96 | if (network("bssid")) 97 | { 98 | _currentSsid = network("bssid").toString(); 99 | } 100 | } 101 | else 102 | { 103 | DoError("GetConnectedNetwork: Error parsing response."); 104 | } 105 | 106 | GetNetworksRequest(); 107 | } 108 | else 109 | { 110 | DoError("GetConnectedNetwork: " + std::to_string(response.StatusCode) + " status returned."); 111 | } 112 | } 113 | else 114 | { 115 | DoError("GetConnectedNetwork: " + response.ErrorMsg); 116 | } 117 | } 118 | 119 | void OpenWRT::GetNetworksRequest() 120 | { 121 | Comms::Http.Post( 122 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/sys?auth=" + _token, 123 | "{ \"id\": 1, \"method\": \"wifi.getiwinfo\", \"params\": [ \"@wifi-device[0]\", \"scanlist\" ] }", 124 | std::bind(&OpenWRT::GetNetworksResponse, this, _1)); 125 | } 126 | 127 | void OpenWRT::GetNetworksResponse(HttpResponse& response) 128 | { 129 | if (response.Success) 130 | { 131 | if (response.StatusCode == 200) 132 | { 133 | WifiDataPtr->Networks.clear(); 134 | 135 | JsonAllocator allocator; 136 | JsonValue root; 137 | JsonParseStatus status = jsonParse((char*)response.Content.c_str(), root, allocator); 138 | 139 | if (status == JSON_PARSE_OK) 140 | { 141 | JsonValue networks = root("result"); 142 | 143 | JsonIterator it = gason::begin(networks); 144 | while (it.isValid()) 145 | { 146 | JsonValue networkNode = it->value; 147 | 148 | if (networkNode("ssid")) 149 | { 150 | Network network; 151 | network.Name = networkNode("ssid").toString(); 152 | network.Id = networkNode("bssid").toString(); 153 | network.Encryption = GetEncryption(networkNode("encryption")); 154 | network.Mode = GetWifiMode(networkNode("encryption")); 155 | network.Connected = (network.Id == _currentSsid); 156 | 157 | bool exists = false; 158 | for (Network& net : WifiDataPtr->Networks) 159 | { 160 | if (net.Name == network.Name) 161 | { 162 | exists = true; 163 | break; 164 | } 165 | } 166 | 167 | if (!exists) 168 | { 169 | WifiDataPtr->Networks.push_back(network); 170 | } 171 | } 172 | 173 | it++; 174 | } 175 | 176 | WifiDataPtr->Status = Idle; 177 | WifiDataPtr->UpdateUI = true; 178 | } 179 | else 180 | { 181 | DoError("GetNetworks: Error parsing response."); 182 | } 183 | } 184 | else 185 | { 186 | DoError("GetNetworks: " + std::to_string(response.StatusCode) + " status returned."); 187 | } 188 | } 189 | else 190 | { 191 | DoError("GetNetworks: " + response.ErrorMsg); 192 | } 193 | } 194 | 195 | void OpenWRT::Connect(string name, string id, WifiMode mode, WifiEncryption encryption, string pwd) 196 | { 197 | _ssid = name; 198 | _bssid = id; 199 | _mode = mode; 200 | _encryption = encryption; 201 | _pwd = pwd; 202 | 203 | Login(std::bind(&OpenWRT::SetSsidRequest, this), std::bind(&OpenWRT::DoError, this, _1)); 204 | } 205 | 206 | void OpenWRT::SetSsidRequest() 207 | { 208 | Comms::Http.Post( 209 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 210 | "{ \"id\": 1, \"method\": \"set\", \"params\": [ \"wireless\", \"@wifi-iface[0]\", \"ssid\", \"" + _ssid + "\" ] }", 211 | std::bind(&OpenWRT::SetBssidRequest, this, _1)); 212 | } 213 | 214 | void OpenWRT::SetBssidRequest(HttpResponse& response) 215 | { 216 | if (response.Success) 217 | { 218 | if (response.StatusCode == 200) 219 | { 220 | Comms::Http.Post( 221 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 222 | "{ \"id\": 1, \"method\": \"set\", \"params\": [ \"wireless\", \"@wifi-iface[0]\", \"bssid\", \"" + _bssid + "\" ] }", 223 | std::bind(&OpenWRT::SetEncryptionRequest, this, _1)); 224 | } 225 | else 226 | { 227 | DoError("SetSsidRequest: " + std::to_string(response.StatusCode) + " status returned."); 228 | } 229 | } 230 | else 231 | { 232 | DoError("SetSsidRequest: " + response.ErrorMsg); 233 | } 234 | } 235 | 236 | void OpenWRT::SetEncryptionRequest(HttpResponse& response) 237 | { 238 | if (response.Success) 239 | { 240 | if (response.StatusCode == 200) 241 | { 242 | Comms::Http.Post( 243 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 244 | "{ \"id\": 1, \"method\": \"set\", \"params\": [ \"wireless\", \"@wifi-iface[0]\", \"encryption\", \"" + GetEncryptionStr(_mode) + "\" ] }", 245 | std::bind(&OpenWRT::SetKeyRequest, this, _1)); 246 | } 247 | else 248 | { 249 | DoError("SetBssidRequest: " + std::to_string(response.StatusCode) + " status returned."); 250 | } 251 | } 252 | else 253 | { 254 | DoError("SetBssidRequest: " + response.ErrorMsg); 255 | } 256 | } 257 | 258 | void OpenWRT::SetKeyRequest(HttpResponse& response) 259 | { 260 | if (response.Success) 261 | { 262 | if (response.StatusCode == 200) 263 | { 264 | Comms::Http.Post( 265 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 266 | "{ \"id\": 1, \"method\": \"set\", \"params\": [ \"wireless\", \"@wifi-iface[0]\", \"key\", \"" + _pwd + "\" ] }", 267 | std::bind(&OpenWRT::CommitRequest, this, _1)); 268 | } 269 | else 270 | { 271 | DoError("SetEncryptionRequest: " + std::to_string(response.StatusCode) + " status returned."); 272 | } 273 | } 274 | else 275 | { 276 | DoError("SetEncryptionRequest: " + response.ErrorMsg); 277 | } 278 | } 279 | 280 | void OpenWRT::CommitRequest(HttpResponse& response) 281 | { 282 | if (response.Success) 283 | { 284 | if (response.StatusCode == 200) 285 | { 286 | Comms::Http.Post( 287 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 288 | "{ \"id\": 1, \"method\": \"commit\", \"params\": [ \"wireless\" ] }", 289 | std::bind(&OpenWRT::ReloadRequest, this, _1)); 290 | } 291 | else 292 | { 293 | DoError("SetKeyRequest: " + std::to_string(response.StatusCode) + " status returned."); 294 | } 295 | } 296 | else 297 | { 298 | DoError("SetKeyRequest: " + response.ErrorMsg); 299 | } 300 | } 301 | 302 | void OpenWRT::ReloadRequest(HttpResponse& response) 303 | { 304 | if (response.Success) 305 | { 306 | if (response.StatusCode == 200) 307 | { 308 | Comms::Http.Post( 309 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/sys?auth=" + _token, 310 | "{ \"id\": 1, \"method\": \"exec\", \"params\": [ \"luci-reload\" ] }", 311 | std::bind(&OpenWRT::ReloadResponse, this, _1)); 312 | } 313 | else 314 | { 315 | DoError("CommitRequest: " + std::to_string(response.StatusCode) + " status returned."); 316 | } 317 | } 318 | else 319 | { 320 | DoError("CommitRequest: " + response.ErrorMsg); 321 | } 322 | } 323 | 324 | void OpenWRT::ReloadResponse(HttpResponse& response) 325 | { 326 | if (response.Success) 327 | { 328 | if (response.StatusCode == 200) 329 | { 330 | for (std::vector::iterator it = WifiDataPtr->Networks.begin(); it != WifiDataPtr->Networks.end(); ++it) 331 | { 332 | it->Connected = (it->Id == _bssid); 333 | } 334 | 335 | WifiDataPtr->Status = Idle; 336 | WifiDataPtr->UpdateUI = true; 337 | } 338 | else 339 | { 340 | DoError("ReloadRequest: " + std::to_string(response.StatusCode) + " status returned."); 341 | } 342 | } 343 | else 344 | { 345 | DoError("ReloadRequest: " + response.ErrorMsg); 346 | } 347 | } 348 | 349 | void OpenWRT::GetTunnel(string connect, function onComplete) 350 | { 351 | transform(connect.begin(), connect.end(), connect.begin(), ::tolower); 352 | connect += ":443"; 353 | _tunnelConnect = connect; 354 | _onAddTunnelComplete = onComplete; 355 | 356 | if (!_tunnelsInited) 357 | { 358 | Login(bind(&OpenWRT::InitStunnel, this), bind(&OpenWRT::TunnelError, this, _1)); 359 | } 360 | else 361 | { 362 | Login(bind(&OpenWRT::AddOrGetTunnel, this), bind(&OpenWRT::TunnelError, this, _1)); 363 | } 364 | } 365 | 366 | void OpenWRT::InitStunnel() 367 | { 368 | _tunnels.clear(); 369 | _tunnelPort = 2000; 370 | 371 | Comms::Http.Post( 372 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 373 | "{ \"id\": 1, \"method\": \"get_all\", \"params\": [ \"stunnel\" ] }", 374 | std::bind(&OpenWRT::PopulateTunnelCache, this, _1)); 375 | } 376 | 377 | void OpenWRT::PopulateTunnelCache(HttpResponse& response) 378 | { 379 | if (response.Success) 380 | { 381 | if (response.StatusCode == 200) 382 | { 383 | JsonAllocator allocator; 384 | JsonValue root; 385 | string type, client, connect; 386 | int port; 387 | 388 | JsonParseStatus status = jsonParse((char*)response.Content.c_str(), root, allocator); 389 | 390 | if (status == JSON_PARSE_OK) 391 | { 392 | if (root("error") && root("error").child("message")) 393 | { 394 | TunnelError("PopulateTunnelCache: " + string(root("error").child("message").toString())); 395 | return; 396 | } 397 | 398 | const JsonValue tunnels = root("result"); 399 | 400 | JsonIterator it = gason::begin(tunnels); 401 | while (it.isValid()) 402 | { 403 | JsonValue tunnel = it->value; 404 | 405 | // Is this a valid tunnel? 406 | if (tunnel(".type").isString() && 407 | tunnel("accept_port").isString() && 408 | tunnel("connect").isString() && 409 | tunnel("client").isString()) 410 | { 411 | type = tunnel(".type").toString(); 412 | client = tunnel("client").toString(); 413 | 414 | if (type == "service" && client == "yes") 415 | { 416 | connect = tunnel("connect").toString(); 417 | transform(connect.begin(), connect.end(), connect.begin(), ::tolower); 418 | port = stoi(tunnel("accept_port").toString()); 419 | 420 | if (_tunnels.count(connect) == 0) 421 | { 422 | _tunnels.insert(pair(connect, port)); 423 | 424 | if (port > _tunnelPort) 425 | { 426 | _tunnelPort = port; 427 | } 428 | } 429 | } 430 | } 431 | it++; 432 | } 433 | 434 | _tunnelsInited = true; 435 | AddOrGetTunnel(); 436 | } 437 | else 438 | { 439 | TunnelError("PopulateTunnelCache: Error parsing response."); 440 | } 441 | } 442 | else 443 | { 444 | TunnelError("PopulateTunnelCache: " + to_string(response.StatusCode) + " status returned."); 445 | } 446 | } 447 | else 448 | { 449 | TunnelError("PopulateTunnelCache: " + response.ErrorMsg); 450 | } 451 | } 452 | 453 | void OpenWRT::AddOrGetTunnel() 454 | { 455 | if (_tunnels.count(_tunnelConnect) > 0) 456 | { 457 | // Already in cache, return port 458 | GetTunnelResult result; 459 | 460 | result.Success = true; 461 | result.Host = string(WifiDataPtr->Hostname); 462 | result.Port = _tunnels[_tunnelConnect]; 463 | 464 | _onAddTunnelComplete(result); 465 | } 466 | else 467 | { 468 | // Not in cache, so add to stunnel 469 | Comms::Http.Post( 470 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 471 | "{ \"id\": 1, \"method\": \"add\", \"params\": [ \"stunnel\", \"service\" ] }", 472 | std::bind(&OpenWRT::SetTunnelClient, this, _1)); 473 | } 474 | } 475 | 476 | void OpenWRT::SetTunnelClient(HttpResponse& response) 477 | { 478 | if (response.Success) 479 | { 480 | if (response.StatusCode == 200) 481 | { 482 | JsonAllocator allocator; 483 | JsonValue root; 484 | string connect; 485 | 486 | JsonParseStatus status = jsonParse((char*)response.Content.c_str(), root, allocator); 487 | 488 | if (status == JSON_PARSE_OK) 489 | { 490 | if (root("error") && root("error").child("message")) 491 | { 492 | TunnelError("SetTunnelClient: " + string(root("error").child("message").toString())); 493 | return; 494 | } 495 | 496 | _tunnelId = root("result").toString(); 497 | 498 | Comms::Http.Post( 499 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 500 | "{ \"id\": 1, \"method\": \"set\", \"params\": [ \"stunnel\", \"" + _tunnelId + "\", \"client\", \"yes\" ] }", 501 | std::bind(&OpenWRT::SetTunnelPort, this, _1)); 502 | 503 | } 504 | else 505 | { 506 | TunnelError("SetTunnelClient: Error parsing response."); 507 | } 508 | } 509 | else 510 | { 511 | TunnelError("SetTunnelClient: " + to_string(response.StatusCode) + " status returned."); 512 | } 513 | } 514 | else 515 | { 516 | TunnelError("SetTunnelClient: " + response.ErrorMsg); 517 | } 518 | } 519 | 520 | void OpenWRT::SetTunnelPort(HttpResponse& response) 521 | { 522 | if (response.Success) 523 | { 524 | if (response.StatusCode == 200) 525 | { 526 | _tunnelPort++; 527 | 528 | Comms::Http.Post( 529 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 530 | "{ \"id\": 1, \"method\": \"set\", \"params\": [ \"stunnel\", \"" + _tunnelId + "\", \"accept_port\", \"" + to_string(_tunnelPort) + "\" ] }", 531 | std::bind(&OpenWRT::SetTunnelConnect, this, _1)); 532 | 533 | } 534 | else 535 | { 536 | TunnelError("SetTunnelPort: " + to_string(response.StatusCode) + " status returned."); 537 | } 538 | } 539 | else 540 | { 541 | TunnelError("SetTunnelPort: " + response.ErrorMsg); 542 | } 543 | } 544 | 545 | void OpenWRT::SetTunnelConnect(HttpResponse& response) 546 | { 547 | if (response.Success) 548 | { 549 | if (response.StatusCode == 200) 550 | { 551 | Comms::Http.Post( 552 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 553 | "{ \"id\": 1, \"method\": \"set\", \"params\": [ \"stunnel\", \"" + _tunnelId + "\", \"connect\", \"" + _tunnelConnect + "\" ] }", 554 | std::bind(&OpenWRT::CommitTunnel, this, _1)); 555 | 556 | } 557 | else 558 | { 559 | TunnelError("SetTunnelConnect: " + to_string(response.StatusCode) + " status returned."); 560 | } 561 | } 562 | else 563 | { 564 | TunnelError("SetTunnelConnect: " + response.ErrorMsg); 565 | } 566 | } 567 | 568 | void OpenWRT::CommitTunnel(HttpResponse& response) 569 | { 570 | if (response.Success) 571 | { 572 | if (response.StatusCode == 200) 573 | { 574 | Comms::Http.Post( 575 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/uci?auth=" + _token, 576 | "{ \"id\": 1, \"method\": \"commit\", \"params\": [ \"stunnel\" ] }", 577 | std::bind(&OpenWRT::StunnelRestart, this, _1)); 578 | } 579 | else 580 | { 581 | TunnelError("CommitTunnel: " + to_string(response.StatusCode) + " status returned."); 582 | } 583 | } 584 | else 585 | { 586 | TunnelError("CommitTunnel: " + response.ErrorMsg); 587 | } 588 | } 589 | 590 | void OpenWRT::StunnelRestart(HttpResponse& response) 591 | { 592 | if (response.Success) 593 | { 594 | if (response.StatusCode == 200) 595 | { 596 | Comms::Http.Post( 597 | "http://" + string(WifiDataPtr->Hostname) + "/cgi-bin/luci/rpc/sys?auth=" + _token, 598 | "{ \"id\": 1, \"method\": \"exec\", \"params\": [ \"/etc/init.d/stunnel restart\" ] }", 599 | std::bind(&OpenWRT::AddTunnelToCache, this, _1)); 600 | } 601 | else 602 | { 603 | TunnelError("StunnelRestart: " + to_string(response.StatusCode) + " status returned."); 604 | } 605 | } 606 | else 607 | { 608 | TunnelError("StunnelRestart: " + response.ErrorMsg); 609 | } 610 | } 611 | 612 | void OpenWRT::AddTunnelToCache(HttpResponse& response) 613 | { 614 | if (response.Success) 615 | { 616 | if (response.StatusCode == 200) 617 | { 618 | if (_tunnels.count(_tunnelConnect) == 0) 619 | { 620 | _tunnels.insert(pair(_tunnelConnect, _tunnelPort)); 621 | 622 | GetTunnelResult result; 623 | 624 | result.Success = true; 625 | result.Host = string(WifiDataPtr->Hostname); 626 | result.Port = _tunnelPort; 627 | 628 | // Give stunnel time to restart before issuing requests (250 milliseconds) 629 | // This is probably only needed when running under emulation 630 | Util::Sleep(250); 631 | 632 | _onAddTunnelComplete(result); 633 | } 634 | } 635 | else 636 | { 637 | TunnelError("AddTunnelToCache: " + to_string(response.StatusCode) + " status returned."); 638 | } 639 | } 640 | else 641 | { 642 | TunnelError("AddTunnelToCache: " + response.ErrorMsg); 643 | } 644 | } 645 | 646 | void OpenWRT::TunnelError(string errorMsg) 647 | { 648 | GetTunnelResult result; 649 | 650 | result.Success = false; 651 | result.ErrorMsg = errorMsg; 652 | 653 | _onAddTunnelComplete(result); 654 | } 655 | 656 | WifiMode OpenWRT::GetWifiMode(const JsonValue& encryption) 657 | { 658 | if (encryption("wpa").isNumber()) 659 | { 660 | int wpaType = encryption("wpa").toInt(); 661 | 662 | switch (wpaType) 663 | { 664 | case 1: 665 | return WPA; 666 | case 2: 667 | return WPA2; 668 | } 669 | } 670 | 671 | return Open; 672 | } 673 | 674 | string OpenWRT::GetEncryptionStr(WifiMode& mode) 675 | { 676 | switch (mode) 677 | { 678 | case WPA2: 679 | return "psk2"; 680 | 681 | case WPA: 682 | return "psk"; 683 | 684 | default: 685 | return ""; 686 | } 687 | } 688 | 689 | WifiEncryption OpenWRT::GetEncryption(const JsonValue& encryption) 690 | { 691 | if (encryption("auth_suites").isArray() && 692 | encryption("auth_suites")[0].isString() && 693 | encryption("auth_suites")[0].toString() == "PSK") 694 | return AES; 695 | 696 | return None; 697 | } 698 | -------------------------------------------------------------------------------- /Modules/OpenWRT.h: -------------------------------------------------------------------------------- 1 | #ifndef _OPENWRT_ 2 | #define _OPENWRT_ 3 | 4 | #include 5 | #include 6 | #include "WifiModule.h" 7 | #include "../Util.h" 8 | 9 | using namespace gason; 10 | 11 | class OpenWRT : public WifiModule 12 | { 13 | public: 14 | virtual void GetNetworks(); 15 | virtual void Connect(string name, string id, WifiMode mode, WifiEncryption encryption, string pwd); 16 | virtual void GetTunnel(string connect, function onComplete); 17 | 18 | private: 19 | std::function _onLoginComplete; 20 | std::function _onLoginError; 21 | string _ssid; 22 | string _bssid; 23 | WifiMode _mode; 24 | WifiEncryption _encryption; 25 | string _token; 26 | string _pwd; 27 | string _currentSsid; 28 | 29 | bool _tunnelsInited = false; 30 | map _tunnels; 31 | string _tunnelId; 32 | string _tunnelConnect; 33 | int _tunnelPort; 34 | function _onAddTunnelComplete = 0; 35 | 36 | void Login(std::function onComplete, std::function onError); 37 | void LoginResponse(HttpResponse& response); 38 | 39 | void GetConnectedNetworkRequest(); 40 | void GetConnectedNetworkResponse(HttpResponse& response); 41 | 42 | void GetNetworksRequest(); 43 | void GetNetworksResponse(HttpResponse& response); 44 | 45 | void SetSsidRequest(); 46 | void SetBssidRequest(HttpResponse& response); 47 | void SetEncryptionRequest(HttpResponse& response); 48 | void SetKeyRequest(HttpResponse& response); 49 | void CommitRequest(HttpResponse& response); 50 | void ReloadRequest(HttpResponse& response); 51 | void ReloadResponse(HttpResponse& response); 52 | 53 | void InitStunnel(); 54 | void PopulateTunnelCache(HttpResponse& response); 55 | void AddOrGetTunnel(); 56 | void SetTunnelClient(HttpResponse& response); 57 | void SetTunnelPort(HttpResponse& response); 58 | void SetTunnelConnect(HttpResponse& response); 59 | void CommitTunnel(HttpResponse& response); 60 | void StunnelRestart(HttpResponse& response); 61 | void AddTunnelToCache(HttpResponse& response); 62 | void TunnelError(string errorMsg); 63 | 64 | WifiMode GetWifiMode(const JsonValue& mode); 65 | string GetEncryptionStr(WifiMode& mode); 66 | WifiEncryption GetEncryption(const JsonValue& encryption); 67 | }; 68 | 69 | #endif // _OPENWRT_ 70 | -------------------------------------------------------------------------------- /Modules/VM300.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "VM300.h" 6 | 7 | void VM300::Login(std::function onComplete) 8 | { 9 | _onLoginComplete = onComplete; 10 | 11 | Comms::Http.Post( 12 | "http://" + string(WifiDataPtr->Hostname) + "/goform/login", 13 | "username=" + string(WifiDataPtr->Username) + "&z999=z999&password=" + string(WifiDataPtr->Password) + "&Login=&platform=pc", 14 | std::bind(&VM300::LoginResponse, this, _1)); 15 | } 16 | 17 | void VM300::LoginResponse(HttpResponse& response) 18 | { 19 | if (response.Success) 20 | { 21 | _onLoginComplete(); 22 | } 23 | else 24 | { 25 | DoError("Login: " + response.ErrorMsg); 26 | } 27 | } 28 | 29 | void VM300::GetNetworks() 30 | { 31 | Login(std::bind(&VM300::GetConnectedNetworkRequest, this)); 32 | } 33 | 34 | void VM300::GetConnectedNetworkRequest() 35 | { 36 | Comms::Http.Get( 37 | "http://" + string(WifiDataPtr->Hostname) + "/adm/status.asp", 38 | std::bind(&VM300::GetConnectedNetworkResponse, this, _1)); 39 | } 40 | 41 | void VM300::GetConnectedNetworkResponse(HttpResponse& response) 42 | { 43 | if (response.Success) 44 | { 45 | if (response.StatusCode == 200) 46 | { 47 | string searchStart = "SSID\r\n "; 48 | size_t startLength = searchStart.length(); 49 | size_t start = response.Content.find(searchStart); 50 | size_t end; 51 | 52 | _currentSsid = ""; 53 | 54 | if (start != string::npos) 55 | { 56 | end = response.Content.find("", start + startLength); 57 | 58 | _currentSsid = response.Content.substr( 59 | start + startLength, 60 | end - start - startLength); 61 | } 62 | 63 | GetNetworksRequest(); 64 | } 65 | else 66 | { 67 | DoError("GetConnectedNetwork: " + std::to_string(response.StatusCode) + " status returned."); 68 | } 69 | } 70 | else 71 | { 72 | DoError("GetConnectedNetwork: " + response.ErrorMsg); 73 | } 74 | } 75 | 76 | void VM300::GetNetworksRequest() 77 | { 78 | Comms::Http.Get( 79 | "http://" + string(WifiDataPtr->Hostname) + "/goform/get_web_hotspots_list", 80 | std::bind(&VM300::GetNetworksResponse, this, _1)); 81 | } 82 | 83 | void VM300::GetNetworksResponse(HttpResponse& response) 84 | { 85 | if (response.Success) 86 | { 87 | if (response.StatusCode == 200) 88 | { 89 | WifiDataPtr->Networks.clear(); 90 | 91 | stringstream ss; 92 | string line; 93 | 94 | ss.str(response.Content); 95 | 96 | while (std::getline(ss, line)) 97 | { 98 | stringstream linestream(line); 99 | string name, temp, enc, mode; 100 | 101 | std::getline(linestream, name, '\t'); 102 | linestream >> temp; // Column 2 = ID 103 | linestream >> temp; // Column 3 = Channel 104 | linestream >> temp; // Column 4 = Strength 105 | linestream >> enc; // Column 5 = Encryption 106 | linestream >> mode; // Column 6 = Mode 107 | 108 | bool exists = false; 109 | for (std::vector::iterator it = WifiDataPtr->Networks.begin(); it != WifiDataPtr->Networks.end(); ++it) 110 | { 111 | if (it->Name == name) 112 | { 113 | exists = true; 114 | break; 115 | } 116 | } 117 | 118 | if (!exists && name != "[HiddenSSID]") 119 | { 120 | Network network; 121 | network.Name = name; 122 | network.Encryption = GetEncryption(enc); 123 | network.Mode = GetWifiMode(mode); 124 | network.Connected = (name == _currentSsid); 125 | WifiDataPtr->Networks.push_back(network); 126 | } 127 | } 128 | 129 | WifiDataPtr->Status = Idle; 130 | WifiDataPtr->UpdateUI = true; 131 | } 132 | else 133 | { 134 | DoError("GetNetworks: " + std::to_string(response.StatusCode) + " status returned."); 135 | } 136 | } 137 | else 138 | { 139 | DoError("GetNetworks: " + response.ErrorMsg); 140 | } 141 | } 142 | 143 | void VM300::Connect(string name, string id, WifiMode mode, WifiEncryption encryption, string pwd) 144 | { 145 | _ssid = name; 146 | _mode = mode; 147 | _encryption = encryption; 148 | _pwd = pwd; 149 | 150 | Login(std::bind(&VM300::DeleteHotspotsRequest, this)); 151 | } 152 | 153 | void VM300::DeleteHotspotsRequest() 154 | { 155 | Comms::Http.Post( 156 | "http://" + string(WifiDataPtr->Hostname) + "/goform/deleteAllHotspots", "", 157 | std::bind(&VM300::DeleteHotspotsResponse, this, _1)); 158 | } 159 | 160 | void VM300::DeleteHotspotsResponse(HttpResponse& response) 161 | { 162 | if (response.Success) 163 | { 164 | if (response.StatusCode == 200) 165 | { 166 | ConnectRequest(); 167 | } 168 | else 169 | { 170 | DoError("DeleteHotspots: " + std::to_string(response.StatusCode) + " status returned."); 171 | } 172 | } 173 | else 174 | { 175 | DoError("DeleteHotspots: " + response.ErrorMsg); 176 | } 177 | } 178 | 179 | void VM300::ConnectRequest() 180 | { 181 | Comms::Http.Post( 182 | "http://" + string(WifiDataPtr->Hostname) + "/goform/wirelessBrdgApcli", 183 | "apcli_ssid=" + Util::UrlEncode(_ssid) + 184 | "&apcli_mode=" + GetWifiModeStr(_mode) + 185 | "&apcli_enc=" + GetEncryptionStr(_encryption) + 186 | "&apcli_ishide=0" 187 | "&apcli_wpapsk=" + Util::UrlEncode(_pwd) + 188 | "&apcli_issyn=1" 189 | "&apcli_repeaterssid=" + Util::UrlEncode(_ssid) + "_64" 190 | "&ra_off=0" 191 | "&EnDynamicMatchPara=1" 192 | "&isDnsNeedChange=1" 193 | "&allow_motion_dect=0" 194 | "&dhcpEnableButton=0" 195 | "&ApcliMatchMode=2" 196 | "&ApcliBlkCount=0", 197 | std::bind(&VM300::ConnectResponse, this, _1)); 198 | } 199 | 200 | void VM300::ConnectResponse(HttpResponse& response) 201 | { 202 | if (response.Success) 203 | { 204 | if (response.StatusCode == 200) 205 | { 206 | Restart(); 207 | } 208 | else 209 | { 210 | DoError("Connect: " + std::to_string(response.StatusCode) + " status returned."); 211 | } 212 | } 213 | else 214 | { 215 | DoError("Connect: " + response.ErrorMsg); 216 | } 217 | } 218 | 219 | void VM300::Restart() 220 | { 221 | Login(std::bind(&VM300::RestartRequest, this)); 222 | } 223 | 224 | void VM300::RestartRequest() 225 | { 226 | Comms::Http.Post( 227 | "http://" + string(WifiDataPtr->Hostname) + "/goform/SystemCommand", 228 | "command=reboot&SystemCommandSubmit=Restart", 229 | std::bind(&VM300::RestartResponse, this, _1)); 230 | } 231 | 232 | void VM300::RestartResponse(HttpResponse& response) 233 | { 234 | if (response.Success) 235 | { 236 | if (response.StatusCode == 200) 237 | { 238 | // Reboot takes about 60 secs - lets wait 80 239 | const double waitTime = (80 * 1000000); 240 | UnsignedWide startTime, curTime, diff; 241 | double timeDiff; 242 | 243 | Microseconds(&startTime); 244 | 245 | do 246 | { 247 | Microseconds(&curTime); 248 | timeDiff = Util::MicrosecondToDouble(&curTime) - Util::MicrosecondToDouble(&startTime); 249 | YieldToAnyThread(); 250 | } while (timeDiff < waitTime); 251 | 252 | // Flag restart required for the Mac to get its new IP 253 | WifiDataPtr->Status = RestartRequired; 254 | WifiDataPtr->UpdateUI = true; 255 | } 256 | else 257 | { 258 | DoError("Restart: " + std::to_string(response.StatusCode) + " status returned."); 259 | } 260 | } 261 | else 262 | { 263 | DoError("Restart: " + response.ErrorMsg); 264 | } 265 | } 266 | 267 | void VM300::GetTunnel(string connect, function onComplete) 268 | { 269 | GetTunnelResult result; 270 | 271 | result.Success = false; 272 | result.ErrorMsg = "stunnel not supported by VM300 device."; 273 | 274 | onComplete(result); 275 | } 276 | 277 | string VM300::GetWifiModeStr(WifiMode& mode) 278 | { 279 | switch (mode) 280 | { 281 | case WPA2: 282 | return "WPA2PSK"; 283 | 284 | case WPA: 285 | return "WPAPSKWPA2PSK"; 286 | 287 | default: 288 | return "OPEN"; 289 | } 290 | } 291 | 292 | WifiMode VM300::GetWifiMode(string& mode) 293 | { 294 | if (mode == "WPA2-PSK") 295 | return WPA2; 296 | 297 | if (mode == "WPAPSK-WPA2PSK") 298 | return WPA; 299 | 300 | return Open; 301 | } 302 | 303 | string VM300::GetEncryptionStr(WifiEncryption& encryption) 304 | { 305 | switch (encryption) 306 | { 307 | case AES: 308 | return "AES"; 309 | 310 | case TKIP: 311 | return "TKIPAES"; 312 | 313 | default: 314 | return "NONE"; 315 | } 316 | } 317 | 318 | WifiEncryption VM300::GetEncryption(string& encryption) 319 | { 320 | if (encryption == "AES") 321 | return AES; 322 | 323 | if (encryption == "TKIPAES") 324 | return TKIP; 325 | 326 | return None; 327 | } -------------------------------------------------------------------------------- /Modules/VM300.h: -------------------------------------------------------------------------------- 1 | #ifndef _VM300_ 2 | #define _VM300_ 3 | 4 | #include 5 | #include "WifiModule.h" 6 | #include "../Util.h" 7 | 8 | class VM300 : public WifiModule 9 | { 10 | public: 11 | virtual void GetNetworks(); 12 | virtual void Connect(string name, string id, WifiMode mode, WifiEncryption encryption, string pwd); 13 | virtual void GetTunnel(string connect, function onComplete); 14 | 15 | private: 16 | std::function _onLoginComplete; 17 | string _ssid; 18 | WifiMode _mode; 19 | WifiEncryption _encryption; 20 | string _pwd; 21 | string _currentSsid; 22 | 23 | void Login(std::function onComplete); 24 | void LoginResponse(HttpResponse& response); 25 | 26 | void GetConnectedNetworkRequest(); 27 | void GetConnectedNetworkResponse(HttpResponse& response); 28 | 29 | void GetNetworksRequest(); 30 | void GetNetworksResponse(HttpResponse& response); 31 | 32 | void DeleteHotspotsRequest(); 33 | void DeleteHotspotsResponse(HttpResponse& response); 34 | 35 | void ConnectRequest(); 36 | void ConnectResponse(HttpResponse& response); 37 | 38 | void Restart(); 39 | void RestartRequest(); 40 | void RestartResponse(HttpResponse& response); 41 | 42 | string GetWifiModeStr(WifiMode& mode); 43 | WifiMode GetWifiMode(string& mode); 44 | 45 | string GetEncryptionStr(WifiEncryption& encryption); 46 | WifiEncryption GetEncryption(string& encryption); 47 | }; 48 | 49 | #endif // _VM300_ -------------------------------------------------------------------------------- /Modules/WifiModule.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "WifiModule.h" 4 | #include "../Util.h" 5 | 6 | void WifiModule::DoError(std::string errorMsg) 7 | { 8 | memset(WifiDataPtr->ErrorMsg, 0, sizeof(WifiDataPtr->ErrorMsg)); 9 | strcpy(WifiDataPtr->ErrorMsg, errorMsg.c_str()); 10 | 11 | WifiDataPtr->Error = true; 12 | WifiDataPtr->Status = Idle; 13 | WifiDataPtr->UpdateUI = true; 14 | } -------------------------------------------------------------------------------- /Modules/WifiModule.h: -------------------------------------------------------------------------------- 1 | #ifndef _WIFI_MODULE_ 2 | #define _WIFI_MODULE_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../Comms.h" 9 | #include "../WifiShared.h" 10 | 11 | using namespace std; 12 | using namespace std::placeholders; 13 | 14 | class GetTunnelResult 15 | { 16 | public: 17 | bool Success; 18 | string Host; 19 | int Port; 20 | string ErrorMsg; 21 | }; 22 | 23 | class WifiModule 24 | { 25 | public: 26 | WifiData* WifiDataPtr; 27 | virtual void GetNetworks() = 0; 28 | virtual void Connect(string name, string id, WifiMode mode, WifiEncryption encryption, string pwd) = 0; 29 | virtual void GetTunnel(string connect, function onComplete) = 0; 30 | 31 | protected: 32 | void DoError(string errorMsg); 33 | }; 34 | 35 | #endif // _WIFI_MODULE_ -------------------------------------------------------------------------------- /Prefs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "Prefs.h" 5 | 6 | Prefs::Prefs() 7 | { 8 | long theSize = 0, start = 0; 9 | PrefData data; 10 | FSSpec theSpec; 11 | short theFile; 12 | OSErr err; 13 | 14 | data.Device = 0; 15 | 16 | if (GetPrefsSpec(&theSpec)) 17 | { 18 | if (FSpOpenDF(&theSpec, fsRdPerm, &theFile) == noErr) 19 | { 20 | theSize = sizeof(PrefData); 21 | err = FSRead(theFile, &theSize, &data); 22 | 23 | if (err == noErr || err == eofErr) 24 | { 25 | Data = data; 26 | } 27 | 28 | FSClose(theFile); 29 | } 30 | } 31 | } 32 | 33 | bool Prefs::Save() 34 | { 35 | long size = sizeof(PrefData); 36 | FSSpec fsSpec; 37 | short file; 38 | OSErr err; 39 | 40 | if (GetPrefsSpec(&fsSpec)) { 41 | err = FSpOpenDF(&fsSpec, fsRdWrPerm, &file); 42 | if (err != noErr) { 43 | if ((err = FSpCreate(&fsSpec, 'MWFI', 'pref', 0)) == noErr) 44 | err = FSpOpenDF(&fsSpec, fsRdWrPerm, &file); 45 | } 46 | if (err == noErr) { 47 | if (SetEOF(file, 0L) == noErr) { 48 | if (FSWrite(file, &size, &Data) == noErr) { 49 | FSClose(file); 50 | return true; 51 | } 52 | 53 | FSClose(file); 54 | } 55 | } 56 | } 57 | 58 | return false; 59 | } 60 | 61 | bool Prefs::GetPrefsSpec(FSSpec *theSpec) 62 | { 63 | Str255 prefsName = "\pMacWifi Preferences"; 64 | short vRefNum; 65 | long dirID; 66 | 67 | if (FindFolder(kOnSystemDisk, kPreferencesFolderType, kCreateFolder, &vRefNum, &dirID) == noErr) { 68 | FSMakeFSSpec(vRefNum, dirID, prefsName, theSpec); 69 | return true; 70 | } 71 | 72 | return false; 73 | } -------------------------------------------------------------------------------- /Prefs.h: -------------------------------------------------------------------------------- 1 | #ifndef _PREFS_ 2 | #define _PREFS_ 3 | 4 | struct PrefData 5 | { 6 | int Device; 7 | char Hostname[255]; 8 | char Username[255]; 9 | char Password[255]; 10 | }; 11 | 12 | class Prefs 13 | { 14 | public: 15 | Prefs(); 16 | PrefData Data; 17 | bool Save(); 18 | private: 19 | bool GetPrefsSpec(FSSpec *theSpec); 20 | }; 21 | 22 | #endif // _PREFS_ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MacWifi 2 | MacWifi is a System Extension to add wifi functionality to your 68k Mac. MacWifi allows you to view available wifi 3 | networks and connect to a wifi network through a familiar menu in the menu bar. WPA2, WPA and public networks are supported. 4 | 5 | ## System Requirements 6 | * System 7 or greater. The [Thread Manager](http://macintoshgarden.org/apps/thread-manager) extension is required for OS versions below System 7.5 7 | * MacTCP or Open Transport installed 8 | 9 | Your Mac will also need an ethernet device and a wifi device. Currently, MacWifi supports the following wifi devices: 10 | 11 | * OpenWRT devices (MacWifi has been tested on a [GL.iNet GL-AR300M16-Ext](https://www.gl-inet.com/products/gl-ar300m/), but other OpenWRT devices should work) 12 | * [Vonets VM300](http://www.vonets.com/ProductViews.asp?D_ID=33) wifi module 13 | 14 | The Vonets VM300 is less expensive than OpenWRT devices, however OpenWRT is recommended for better speed, stability and features. 15 | 16 | ## About OpenWRT 17 | OpenWRT is a Linux OS designed for network devices. Your device must have OpenWRT version 18.06.0 or later installed. You can download the latest release here: 18 | 19 | [https://downloads.openwrt.org/](https://downloads.openwrt.org/) ([instructions](https://wiki.openwrt.org/doc/howto/generic.sysupgrade)) 20 | 21 | Note that if you plan to purchase a GL-AR300M device, not all models are supported. Only the models with NOR memory are supported - models with NAND memory will 22 | not work, as they cannot be upgraded to the latest version of OpenWRT. The following models are supported: 23 | 24 | * GL-AR300M16 (internal antennas, 16m NOR memory only) 25 | * GL-AR300M16-Ext (external antennas, 16m NOR memory only) 26 | 27 | For the AR300M, you'll find the correct upgrade package under ar71xx > generic > ar300m file ending in sysupgrade.bin. The quick way of updating firmware 28 | is via the Luci interface under System > Backup / Flash Firmware. You can upload you package file from there. 29 | 30 | You must also install the following packages: 31 | 32 | * Json RPC ([instructions](https://github.com/openwrt/luci/wiki/JsonRpcHowTo)) 33 | * ethtool (via the Software page in the Luci interface) 34 | * stunnel (as above). This package is only required if you want to use an SSL-enabled app that requires MacWifi. 35 | 36 | Finally, for OpenWRT to be able to communicate with your vintage Mac ethernet card; you need to set the LAN port to operate at 10mbs Half Duplex 37 | (some Mac ethernet cards support full duplex, in which case replace the word _half_ with _full_ below). 38 | 39 | Add the following to your Startup script in OpenWRT (System > Startup in Luci): 40 | 41 | ethtool -s eth1 autoneg off speed 10 duplex half 42 | 43 | (where _eth1_ is the name of your LAN port that's connected to your Mac) 44 | 45 | Note: For some reason, running ethtool on the AR300M does not work for eth1 - however it does work for eth0. After you've set eth0 to the correct speed 46 | & duplex, you can then swap the LAN & WAN ports via the Luci interface. Go to Network > Interfaces in Luci and edit the LAN & WAN ports. Under 47 | _Physical Settings_ swap the eth1/eth0 ports for each interface. 48 | 49 | ### stunnel Configuration 50 | The following addtional steps are only required if you want to use an SSL-enabled app that requires MacWifi. The stunnel configuration needs 51 | a bit of tweaking to work with MacWifi. 52 | 53 | SSH into your OpenWRT router, and edit the following files using vim: 54 | 55 | vim /etc/config/stunnel 56 | 57 | Remove all contents from this file (it should contain a globals section and dummy service). 58 | 59 | Crash course in vim: Press *i* to enter insert mode, make your edits, press Escape to leave insert mode, then type *:wq* to save & exit. 60 | 61 | vim /etc/init.d/stunnel 62 | 63 | Line 96: Change from: 64 | printf "accept = %s:%s\n" "$accept_host" "$accept_port" >> "$CONF_FILE" 65 | to: 66 | printf "accept = %s\n" "$accept_port" >> "$CONF_FILE" 67 | 68 | Line 134: Remove this line: 69 | print_list_colon "$cfg" ciphers 70 | 71 | ## About the Vonets VM300 72 | The VM300 was the first device I discovered that could communicate with a vintage Mac over 10mbs Half Duplex. Setup instructions are on 73 | the [68KMLA Forums](https://68kmla.org/forums/index.php?app=forums&module=forums&controller=topic&id=31078). 74 | 75 | The VM300 is a very basic device and has a few issues and limitations: 76 | 77 | * When connecting to a wifi network, don’t enter the wrong password! Otherwise you’ll brick the VM300 and you’ll need to do a factory reset (by shorting pins 5 and 8 on the board) 78 | * Connecting to a new wifi network requires the VM300 to restart - the process takes about 2 minutes. 79 | * Fetching the network list takes about 10 seconds. 80 | * If you issue too many requests (i.e. get the list of wifi networks too many times), the device appears to run out of memory and locks up – requiring a restart. 81 | * Occasionally, the device fails to start – a power cycle fixes this. 82 | 83 | ## Building from Source 84 | MacWifi requires Retro68 for compilation, and the following libraries: 85 | 86 | * [MacTCPHelper](https://github.com/antscode/MacTCPHelper) 87 | * [MacHTTP](https://github.com/antscode/MacHTTP) 88 | * [gason++](https://github.com/antscode/gason--) 89 | * [libiconv](https://github.com/LuaDist/libiconv) 90 | 91 | First build and install the above libraries. Note: When building MacHTTP, set HTTPS_ENABLED to OFF in CMakeLists.txt. 92 | HTTPS is not required, and will cause linker errors if it's not disabled. 93 | 94 | Once the above libraries are built and installed, execute these commands from the top level of the MacWifi directory: 95 | 96 | cd .. 97 | mkdir MacWifi-build 98 | cd MacWifi-build 99 | cmake ../MacWifi -DCMAKE_TOOLCHAIN_FILE=<>/toolchain/m68k-apple-macos/cmake/retro68.toolchain.cmake 100 | make 101 | 102 | The MacWifi extension will be in the MacWifi-build directory as a bin file and disk image. 103 | 104 | ## Credits 105 | * MacWifi is built using [Retro68](https://github.com/autc04/Retro68). 106 | * System Menu INIT code based on "SysMenu" shell project by Matt Slot, circa 1995. 107 | * Password field based on code snippet by Phil Kearney, circa 1994. 108 | * Startup icon code by Peter Lewis, Jim Walker & François Pottier, 1994. 109 | * [iconvpp](https://github.com/unnonouno/iconvpp) C++ wrapper for iconv 110 | -------------------------------------------------------------------------------- /ShowInitIcon.c: -------------------------------------------------------------------------------- 1 | // ShowInitIcon - version 1.0.1, May 30th, 1995 2 | // This code is intended to let INIT writers easily display an icon at startup time. 3 | // View in Geneva 9pt, 4-space tabs 4 | 5 | // Written by: Peter N Lewis , Jim Walker 6 | // and François Pottier , with thanks to previous ShowINIT authors. 7 | // Send comments and bug reports to François Pottier. 8 | 9 | // This version features: 10 | // - Short and readable code. 11 | // - Correctly wraps around when more than one row of icons has been displayed. 12 | // - works with System 6 13 | // - Built with Universal Headers & CodeWarrior. Should work with other headers/compilers. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include "ShowInitIcon.h" 20 | 21 | // You should set SystemSixOrLater in your headers to avoid including glue for SysEnvirons. 22 | 23 | // --------------------------------------------------------------------------------------------------------------------- 24 | // Set this flag to 1 if you want to compile this file into a stand-alone resource (see note below). 25 | // Set it to 0 if you want to include this source file into your INIT project. 26 | 27 | #if 0 28 | #define ShowInitIcon main 29 | #endif 30 | 31 | // --------------------------------------------------------------------------------------------------------------------- 32 | // The ShowINIT mechanism works by having each INIT read/write data from these globals. 33 | // The MPW C compiler doesn't accept variables declared at an absolute address, so I use these macros instead. 34 | // Only one macro is defined per variable; there is no need to define a Set and a Get accessor like in . 35 | 36 | #define LMVCheckSum (* (unsigned short*) 0x928) 37 | #define LMVCoord (* ( short*) 0x92A) 38 | #define LMHCoord (* ( short*) 0x92C) 39 | #define LMHCheckSum (* (unsigned short*) 0x92E) 40 | 41 | // --------------------------------------------------------------------------------------------------------------------- 42 | // Prototypes for the subroutines. The main routine comes first; this is necessary to make THINK C's "Custom Header" option work. 43 | 44 | static unsigned short CheckSum (short x); 45 | static void ComputeIconRect (Rect* iconRect, Rect* screenBounds); 46 | static void AdvanceIconPosition (Rect* iconRect); 47 | static void DrawBWIcon (short iconID, Rect *iconRect); 48 | 49 | // --------------------------------------------------------------------------------------------------------------------- 50 | // Main routine. 51 | 52 | typedef struct { 53 | QDGlobals qd; // Storage for the QuickDraw globals 54 | long qdGlobalsPtr; // A5 points to this place; it will contain a pointer to qd 55 | } QDStorage; 56 | 57 | pascal void ShowInitIcon (short iconFamilyID, Boolean advance) 58 | { 59 | long oldA5; // Original value of register A5 60 | QDStorage qds; // Fake QD globals 61 | CGrafPort colorPort; 62 | GrafPort bwPort; 63 | Rect destRect; 64 | SysEnvRec environment; // Machine configuration. 65 | 66 | oldA5 = SetA5((long) &qds.qdGlobalsPtr); // Tell A5 to point to the end of the fake QD Globals 67 | InitGraf(&qds.qd.thePort); // Initialize the fake QD Globals 68 | 69 | SysEnvirons(curSysEnvVers, &environment); // Find out what kind of machine this is 70 | 71 | ComputeIconRect(&destRect, &qds.qd.screenBits.bounds); // Compute where the icon should be drawn 72 | 73 | if (environment.systemVersion >= 0x0700 && environment.hasColorQD) { 74 | OpenCPort(&colorPort); 75 | PlotIconID(&destRect, atNone, ttNone, iconFamilyID); 76 | CloseCPort(&colorPort); 77 | } 78 | else { 79 | OpenPort(&bwPort); 80 | DrawBWIcon(iconFamilyID, &destRect); 81 | ClosePort(&bwPort); 82 | } 83 | 84 | if (advance) 85 | AdvanceIconPosition (&destRect); 86 | 87 | SetA5(oldA5); // Restore A5 to its previous value 88 | } 89 | 90 | // --------------------------------------------------------------------------------------------------------------------- 91 | // A checksum is used to make sure that the data in there was left by another ShowINIT-aware INIT. 92 | 93 | static unsigned short CheckSum (short x) 94 | { 95 | return (unsigned short)(((x << 1) | (x >> 15)) ^ 0x1021); 96 | } 97 | 98 | // --------------------------------------------------------------------------------------------------------------------- 99 | // ComputeIconRect computes where the icon should be displayed. 100 | 101 | static void ComputeIconRect (Rect* iconRect, Rect* screenBounds) 102 | { 103 | if (CheckSum(LMHCoord) != LMHCheckSum) // If we are first, we need to initialize the shared data. 104 | LMHCoord = 8; 105 | if (CheckSum(LMVCoord) != LMVCheckSum) 106 | LMVCoord = (short)(screenBounds->bottom - 40); 107 | 108 | if (LMHCoord + 34 > screenBounds->right) { // Check whether we must wrap 109 | iconRect->left = 8; 110 | iconRect->top = (short)(LMVCoord - 40); 111 | } 112 | else { 113 | iconRect->left = LMHCoord; 114 | iconRect->top = LMVCoord; 115 | } 116 | iconRect->right = (short)(iconRect->left + 32); 117 | iconRect->bottom = (short)(iconRect->top + 32); 118 | } 119 | 120 | // AdvanceIconPosition updates the shared global variables so that the next extension will draw its icon beside ours. 121 | 122 | static void AdvanceIconPosition (Rect* iconRect) 123 | { 124 | LMHCoord = (short)(iconRect->left + 40); // Update the shared data 125 | LMVCoord = iconRect->top; 126 | LMHCheckSum = CheckSum(LMHCoord); 127 | LMVCheckSum = CheckSum(LMVCoord); 128 | } 129 | 130 | // DrawBWIcon draws the 'ICN#' member of the icon family. It works under System 6. 131 | 132 | static void DrawBWIcon (short iconID, Rect *iconRect) 133 | { 134 | Handle icon; 135 | BitMap source, destination; 136 | GrafPtr port; 137 | 138 | icon = Get1Resource('ICN#', iconID); 139 | if (icon != NULL) { 140 | HLock(icon); 141 | // Prepare the source and destination bitmaps. 142 | source.baseAddr = *icon + 128; // Mask address. 143 | source.rowBytes = 4; 144 | SetRect(&source.bounds, 0, 0, 32, 32); 145 | GetPort(&port); 146 | destination = port->portBits; 147 | // Transfer the mask. 148 | CopyBits(&source, &destination, &source.bounds, iconRect, srcBic, nil); 149 | // Then the icon. 150 | source.baseAddr = *icon; 151 | CopyBits(&source, &destination, &source.bounds, iconRect, srcOr, nil); 152 | } 153 | } 154 | 155 | // --------------------------------------------------------------------------------------------------------------------- 156 | // Notes 157 | 158 | // Checking for PlotIconID: 159 | // We (PNL) now check for system 7 and colour QD, and use colour graf ports and PlotIconID only if both are true 160 | // Otherwise we use B&W grafport and draw using PlotBWIcon. 161 | 162 | -------------------------------------------------------------------------------- /ShowInitIcon.h: -------------------------------------------------------------------------------- 1 | #ifndef __ShowInitIcon__ 2 | #define __ShowInitIcon__ 3 | 4 | #include 5 | 6 | // Usage: pass the ID of your icon family (ICN#/icl4/icl8) to have it drawn in the right spot. 7 | // If 'advance' is true, the next INIT icon will be drawn to the right of your icon. If it is false, the next INIT icon will overwrite 8 | // yours. You can use it to create animation effects by calling ShowInitIcon several times with 'advance' set to false. 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | pascal void ShowInitIcon (short iconFamilyID, Boolean advance); 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif 19 | 20 | #endif /* __ShowInitIcon__ */ 21 | 22 | -------------------------------------------------------------------------------- /Util.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Util.h" 9 | 10 | #define kTwoPower32 (4294967296.0) /* 2^32 */ 11 | 12 | char* Util::PtoCStr(unsigned char *s) 13 | { 14 | int theLen; 15 | int t; 16 | 17 | theLen = s[0]; 18 | 19 | for (t = 0; t= 1; t--) 40 | s[t] = s[t - 1]; 41 | 42 | s[0] = (char)theLen; 43 | 44 | return (unsigned char *)s; 45 | } 46 | 47 | unsigned char* Util::StrToPStr(std::string str) 48 | { 49 | char* s = (char*)str.c_str(); 50 | 51 | int theLen; 52 | int t; 53 | 54 | theLen = strlen(s); 55 | 56 | for (t = theLen; t >= 1; t--) 57 | s[t] = s[t - 1]; 58 | 59 | s[0] = (char)theLen; 60 | 61 | return (unsigned char *)s; 62 | } 63 | 64 | void Util::Debug(std::string msg) 65 | { 66 | FILE *fp; 67 | fp = fopen("Mac HD (68K):wifi.txt", "a"); 68 | 69 | if (fp) 70 | { 71 | fprintf(fp, msg.c_str()); 72 | fflush(fp); 73 | } 74 | 75 | fclose(fp); 76 | } 77 | 78 | void Util::DebugClient(std::string msg) 79 | { 80 | FILE *fp; 81 | fp = fopen("Mac HD (68K):wificlient.txt", "a"); 82 | 83 | if (fp) 84 | { 85 | fprintf(fp, msg.c_str()); 86 | fflush(fp); 87 | } 88 | 89 | fclose(fp); 90 | } 91 | 92 | void Util::FrameDefaultButton(DialogPtr dialog, short itemNo, bool active) 93 | { 94 | DialogItemType type; 95 | ControlRef control; 96 | Handle itemH; 97 | Rect box; 98 | 99 | GetDialogItem(dialog, itemNo, &type, &itemH, &box); 100 | InsetRect(&box, -4, -4); 101 | PenSize(3, 3); 102 | 103 | if (!active) 104 | { 105 | RGBColor color; 106 | PixPatHandle pp; 107 | 108 | color.red = 0x8000; 109 | color.green = 0x8000; 110 | color.blue = 0x8000; 111 | 112 | pp = NewPixPat(); 113 | MakeRGBPat(pp, &color); 114 | PenPixPat(pp); 115 | FrameRoundRect(&box, 16, 16); 116 | DisposePixPat(pp); 117 | PenNormal(); 118 | HiliteControl((ControlRef)itemH, 255); 119 | } 120 | else 121 | { 122 | FrameRoundRect(&box, 16, 16); 123 | HiliteControl((ControlRef)itemH, 0); 124 | } 125 | } 126 | 127 | bool Util::IsControlHilited(DialogPtr dialog, short itemNo) 128 | { 129 | DialogItemType type; 130 | Handle itemH; 131 | Rect box; 132 | 133 | GetDialogItem(dialog, itemNo, &type, &itemH, &box); 134 | 135 | ControlRef ctrlRef = (ControlRef)itemH; 136 | ControlPtr ctrlPtr = *ctrlRef; 137 | ControlRecord control = *ctrlPtr; 138 | 139 | return control.contrlHilite == 0; 140 | } 141 | 142 | string Util::UrlEncode(string &value) 143 | { 144 | ostringstream escaped; 145 | escaped.fill('0'); 146 | escaped << hex; 147 | 148 | for (string::const_iterator i = value.begin(), n = value.end(); i != n; ++i) { 149 | string::value_type c = (*i); 150 | 151 | // Keep alphanumeric and other accepted characters intact 152 | if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') { 153 | escaped << c; 154 | continue; 155 | } 156 | 157 | // Any other characters are percent-encoded 158 | escaped << uppercase; 159 | escaped << '%' << setw(2) << int((unsigned char)c); 160 | escaped << nouppercase; 161 | } 162 | 163 | return escaped.str(); 164 | } 165 | 166 | // From: http://www.mactech.com/articles/develop/issue_26/minow.html 167 | double Util::MicrosecondToDouble(register const UnsignedWide *epochPtr) 168 | { 169 | register double result; 170 | 171 | result = (((double)epochPtr->hi) * kTwoPower32) + epochPtr->lo; 172 | return (result); 173 | } 174 | 175 | void Util::Sleep(int milliSeconds) 176 | { 177 | const double waitTime = (milliSeconds * 1000); 178 | UnsignedWide startTime, curTime, diff; 179 | double timeDiff; 180 | 181 | Microseconds(&startTime); 182 | 183 | do 184 | { 185 | Microseconds(&curTime); 186 | timeDiff = Util::MicrosecondToDouble(&curTime) - Util::MicrosecondToDouble(&startTime); 187 | YieldToAnyThread(); 188 | } while (timeDiff < waitTime); 189 | } 190 | 191 | void Util::StartTimer() 192 | { 193 | Microseconds(&_startTime); 194 | } 195 | 196 | int Util::StopTimer() 197 | { 198 | UnsignedWide curTime; 199 | double timeDiff; 200 | 201 | Microseconds(&curTime); 202 | timeDiff = Util::MicrosecondToDouble(&curTime) - Util::MicrosecondToDouble(&_startTime); 203 | 204 | return timeDiff / 1000; // As milliseconds 205 | } -------------------------------------------------------------------------------- /Util.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifndef _UTIL_ 5 | #define _UTIL_ 6 | 7 | using namespace std; 8 | 9 | class Util 10 | { 11 | public: 12 | static char* PtoCStr(unsigned char *s); 13 | static std::string PtoStr(unsigned char *s); 14 | static unsigned char* CtoPStr(char *s); 15 | static unsigned char* StrToPStr(string str); 16 | static void Debug(string msg); 17 | static void DebugClient(string msg); 18 | static void FrameDefaultButton(DialogPtr dialog, short itemNo, bool active); 19 | static bool IsControlHilited(DialogPtr dialog, short itemNo); 20 | static string UrlEncode(string &value); 21 | static double MicrosecondToDouble(register const UnsignedWide *epochPtr); 22 | static void Sleep(int seconds); 23 | void StartTimer(); 24 | int StopTimer(); 25 | 26 | private: 27 | UnsignedWide _startTime; 28 | }; 29 | 30 | #endif // _UTIL_ 31 | -------------------------------------------------------------------------------- /WifiEvents.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Event Classes 4 | enum { 5 | kWifiClass = FOUR_CHAR_CODE('wifi') 6 | }; 7 | 8 | // Event Id's 9 | enum { 10 | kRequest = FOUR_CHAR_CODE('requ'), 11 | kResponse = FOUR_CHAR_CODE('resp') 12 | }; 13 | 14 | // Event Parameters 15 | enum { 16 | kMethodParam = FOUR_CHAR_CODE('mthd'), 17 | kUriParam = FOUR_CHAR_CODE('ruri'), 18 | kDataParam = FOUR_CHAR_CODE('data'), 19 | kCallbackIdParam = FOUR_CHAR_CODE('cbck'), 20 | kSuccessParam = FOUR_CHAR_CODE('scss'), 21 | kStatusCodeParam = FOUR_CHAR_CODE('stat'), 22 | kErrorMsgParam = FOUR_CHAR_CODE('errm'), 23 | kContentParam = FOUR_CHAR_CODE('cont'), 24 | kAuthorizationParam = FOUR_CHAR_CODE('auth'), 25 | kUtf8ToMacRomanParam = FOUR_CHAR_CODE('utmr') 26 | }; -------------------------------------------------------------------------------- /WifiShared.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifndef _WIFI_SHARED_ 5 | #define _WIFI_SHARED_ 6 | 7 | using namespace std; 8 | 9 | enum WifiStatus 10 | { 11 | Idle, 12 | ScanRequest, 13 | Scanning, 14 | ConnectRequest, 15 | Connecting, 16 | RestartRequired, 17 | RestartRequest, 18 | Restarting, 19 | SavePrefsRequest 20 | }; 21 | 22 | enum WifiMode 23 | { 24 | WPA2, 25 | WPA, 26 | Open 27 | }; 28 | 29 | enum WifiEncryption 30 | { 31 | AES, 32 | TKIP, 33 | None 34 | }; 35 | 36 | struct Network 37 | { 38 | public: 39 | string Name; 40 | string Id; 41 | WifiMode Mode; 42 | WifiEncryption Encryption; 43 | bool Connected; 44 | }; 45 | 46 | class WifiData 47 | { 48 | public: 49 | WifiStatus Status; 50 | bool UpdateUI; 51 | bool Error; 52 | char ErrorMsg[255]; 53 | vector Networks; 54 | int Device; 55 | char Hostname[255]; 56 | char Username[255]; 57 | char Password[255]; 58 | char ConnectName[255]; 59 | char ConnectId[255]; 60 | char ConnectPwd[255]; 61 | WifiMode ConnectMode; 62 | WifiEncryption ConnectEncryption; 63 | }; 64 | 65 | typedef int MemLoc; 66 | typedef MemLoc* MemLocPtr; 67 | typedef MemLocPtr* MemLocHandle; 68 | 69 | #endif // _WIFI_SHARED_ -------------------------------------------------------------------------------- /iconv.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2011, Yuya Unno 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of the Yuya Unno nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | 29 | #pragma once 30 | 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | namespace iconvpp { 39 | 40 | class converter { 41 | public: 42 | converter(const std::string& out_encode, 43 | const std::string& in_encode, 44 | bool ignore_error = false, 45 | size_t buf_size = 1024) 46 | : ignore_error_(ignore_error), 47 | buf_size_(buf_size) { 48 | if (buf_size == 0) { 49 | throw std::runtime_error("buffer size must be greater than zero"); 50 | } 51 | 52 | iconv_t conv = ::iconv_open(out_encode.c_str(), in_encode.c_str()); 53 | if (conv == (iconv_t)-1) { 54 | if (errno == EINVAL) 55 | throw std::runtime_error( 56 | "not supported from " + in_encode + " to " + out_encode); 57 | else 58 | throw std::runtime_error("unknown error"); 59 | } 60 | iconv_ = conv; 61 | } 62 | 63 | ~converter() { 64 | iconv_close(iconv_); 65 | } 66 | 67 | void convert(const std::string& input, std::string& output) const { 68 | // copy the string to a buffer as iconv function requires a non-const char 69 | // pointer. 70 | std::vector in_buf(input.begin(), input.end()); 71 | char* src_ptr = &in_buf[0]; 72 | size_t src_size = input.size(); 73 | 74 | std::vector buf(buf_size_); 75 | std::string dst; 76 | while (0 < src_size) { 77 | char* dst_ptr = &buf[0]; 78 | size_t dst_size = buf.size(); 79 | size_t res = ::iconv(iconv_, &src_ptr, &src_size, &dst_ptr, &dst_size); 80 | if (res == (size_t)-1) { 81 | if (errno == E2BIG) { 82 | // ignore this error 83 | } else if (ignore_error_) { 84 | // skip character 85 | ++src_ptr; 86 | --src_size; 87 | } else { 88 | check_convert_error(); 89 | } 90 | } 91 | dst.append(&buf[0], buf.size() - dst_size); 92 | } 93 | dst.swap(output); 94 | } 95 | 96 | private: 97 | void check_convert_error() const { 98 | switch (errno) { 99 | case EILSEQ: 100 | case EINVAL: 101 | throw std::runtime_error("invalid multibyte chars"); 102 | default: 103 | throw std::runtime_error("unknown error"); 104 | } 105 | } 106 | 107 | iconv_t iconv_; 108 | bool ignore_error_; 109 | const size_t buf_size_; 110 | }; 111 | 112 | } // namespace iconvpp 113 | -------------------------------------------------------------------------------- /resources.r: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antscode/MacWifi/49f29a5facf23ebde07655fb116d483213d36e26/resources.r -------------------------------------------------------------------------------- /sysmenu.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antscode/MacWifi/49f29a5facf23ebde07655fb116d483213d36e26/sysmenu.cpp -------------------------------------------------------------------------------- /sysmenu.h: -------------------------------------------------------------------------------- 1 | /* 2 | 2018 Anthony Super. 3 | System Menu INIT code based on "SysMenu" shell project by Matt Slot, circa 1995. 4 | */ 5 | 6 | #include 7 | #include 8 | #include "WifiShared.h" 9 | 10 | #ifndef ____SYSMENU_HEADER____ 11 | #define ____SYSMENU_HEADER____ 12 | 13 | using namespace std; 14 | 15 | extern "C" 16 | { 17 | // * ******************************************************************************* * 18 | // * ******************************************************************************* * 19 | 20 | // Basic debugging flag that enables/disables all Debug() 21 | // and DebugStr() calls embedded into the source files. 22 | // #define ____DEBUG____ 23 | 24 | // When we install the Menu, we will try to get this MenuID. If 25 | // there is already one (2 copies of INIT?), we will do our best 26 | // to get another (but close) ID. (See InsertMenu patch) 27 | #define kPrefMenuID -19999 28 | 29 | // This is an icon family for the menu. Currently the value is set 30 | // to something guaranteed to be available (from the system file). 31 | // You can set it to an icon from your resfile or to 0 for no icon. 32 | #define kPrefIconID 129 33 | 34 | // * ******************************************************************************* * 35 | // * ******************************************************************************* * 36 | 37 | typedef pascal void(*InsertMenuProcPtr) (MenuHandle mHdl, short beforeID); 38 | typedef pascal void(*DrawMenuProcPtr) (); 39 | typedef pascal long(*MenuSelectProcPtr) (Point where); 40 | typedef pascal void(*SystemMenuProcPtr) (long result); 41 | 42 | typedef struct { 43 | InsertMenuProcPtr saveInsertMenu; 44 | DrawMenuProcPtr saveDrawMenuBar; 45 | MenuSelectProcPtr saveMenuSelect; 46 | SystemMenuProcPtr saveSystemMenu; 47 | 48 | short menuID, **sysMenus; 49 | MenuHandle mHdl; 50 | Handle menuIcon; 51 | FSSpec homeFile; 52 | } GlobalsRec; 53 | 54 | // * ******************************************************************************* * 55 | // * ******************************************************************************* * 56 | // Function Prototypes 57 | 58 | void InitSharedData(); 59 | void SaveSharedMemoryLocation(); 60 | short CurResFileAsFSSpec(FSSpec *fileSpec); 61 | ProcPtr ApplyTrapPatch(short trap, ProcPtr patchPtr); 62 | pascal short DetachIcons(long iconType, Handle *iconHdl, void *data); 63 | pascal void Patched_InsertMenu(MenuHandle menu, short beforeID); 64 | pascal void Patched_DrawMenuBar(void); 65 | pascal long Patched_MenuSelect(Point where); 66 | pascal void Patched_SystemMenu(long result); 67 | pascal Boolean PSWDModalFilter(DialogPtr dialog, EventRecord *theEvent, short *itemHit); 68 | pascal Boolean SettingsModalFilter(DialogPtr dialog, EventRecord *theEvent, short *itemHit); 69 | void ShowConnectDialog(Network& network); 70 | void ShowError(); 71 | void ShowSettings(); 72 | void PasswordKey(TEHandle teHndl, char theKey); 73 | string GetWifiModeLabel(WifiMode mode); 74 | } 75 | 76 | #endif --------------------------------------------------------------------------------