/* Copyright 2019 Wolfgang Thaller. This file is part of Retro68. Retro68 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Retro68 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Retro68. If not, see <http://www.gnu.org/licenses/>.*/ #include <Quickdraw.h>#include <Windows.h>#include <Menus.h>#include <Fonts.h>#include <Resources.h>#include <TextEdit.h>#include <TextUtils.h>#include <Dialogs.h>#include <Devices.h>#include <Traps.h>#include <LowMem.h>#include <SegLoad.h>#include <Gestalt.h> #include "AppLauncher.h"#include "StatusDisplay.h"#include "AboutBox.h"#include "Preferences.h" #include <ServerProtocol.h>#include <Processes.h>#include <string.h>#include <memory> #include "ConnectionProvider.h"#if !TARGET_API_MAC_CARBON#include "SerialConnectionProvider.h"#endif#if HAVE_MACTCP#include "TCPConnectionProvider.h"#endif#ifdef HAVE_OPENTRANSPORT#include "OpenTptConnectionProvider.h"#endif#include "SharedFileProvider.h" #include "SystemInfo.h" #include "CarbonFileCompat.h" #include <Stream.h> enum{ kMenuApple = 128, kMenuFile, kMenuEdit, kMenuConnection}; enum{ kItemAbout = 1, kItemClose = 1, kItemQuit = 3, kItemChooseFolder = 14}; #if TARGET_API_MAC_CARBONbool portsAvailable[] = { false, false, false, false, true };#else#ifdef HAVE_OPENTRANSPORTbool portsAvailable[] = { true, true, false, false, true };#elsebool portsAvailable[] = { true, false, false, false, true };#endif#endifbool hasIconUtils = true;bool hasColorQD = true;bool hasSys7StdFile = true; Prefs gPrefs; void WritePrefs(){ short refNum; Create("\pLaunchAPPLServer Preferences", 0, 'R68L', 'LAPR'); if(OpenDF("\pLaunchAPPLServer Preferences", 0, &refNum) == noErr) { long count = sizeof(gPrefs); FSWrite(refNum, &count, &gPrefs); FSClose(refNum); }} void ReadPrefs(){ short refNum; if(OpenDF("\pLaunchAPPLServer Preferences", 0, &refNum) == noErr) { long count = sizeof(gPrefs); gPrefs.version = -1; FSRead(refNum, &count, &gPrefs); if(gPrefs.version != Prefs::currentVersion) gPrefs = Prefs(); FSClose(refNum); }} bool gQuitting = false;WindowRef aboutWindow = nullptr;void ConnectionChanged(); #if TARGET_API_MAC_CARBON #define EnableItem EnableMenuItem #define DisableItem DisableMenuItem#endifvoid SetItemEnabled(MenuHandle m, short item, bool enabled){ if(enabled) EnableItem(m,item); else DisableItem(m,item);} void UpdateMenus(){ MenuRef m = GetMenuHandle(kMenuFile); WindowRef w = FrontWindow(); m = GetMenuHandle(kMenuFile); if(w && (w == aboutWindow || GetWindowKind(w) < 0)) EnableItem(m,kItemClose); else DisableItem(m,kItemClose); m = GetMenuHandle(kMenuEdit); bool enableEditMenu = (w && GetWindowKind(w) < 0); // Desk accessory in front: Enable edit menu items // Application window or nothing in front, disable edit menu for(short i : {1,3,4,5,6}) SetItemEnabled(m,i,enableEditMenu); m = GetMenuHandle(kMenuConnection); SetItemEnabled(m, 1, portsAvailable[(int)Port::macTCP]); CheckMenuItem(m, 1, gPrefs.port == Port::macTCP); SetItemEnabled(m, 2, portsAvailable[(int)Port::openTptTCP]); CheckMenuItem(m, 2, gPrefs.port == Port::openTptTCP); SetItemEnabled(m, 3, portsAvailable[(int)Port::modemPort]); CheckMenuItem(m, 3, gPrefs.port == Port::modemPort); SetItemEnabled(m, 4, portsAvailable[(int)Port::printerPort]); CheckMenuItem(m, 4, gPrefs.port == Port::printerPort); SetItemEnabled(m, 5, portsAvailable[(int)Port::sharedFiles]); CheckMenuItem(m, 5, gPrefs.port == Port::sharedFiles); for(int i = 7; i < kItemChooseFolder; i++) { Str255 str; long baud; GetMenuItemText(m, i, str); StringToNum(str, &baud); CheckMenuItem(m, i, baud == gPrefs.baud); SetItemEnabled(m, i, gPrefs.port == Port::modemPort || gPrefs.port == Port::printerPort); }} void DoMenuCommand(long menuCommand){ Str255 str; WindowRef w; short menuID = menuCommand >> 16; short menuItem = menuCommand & 0xFFFF; if(menuID == kMenuApple) { if(menuItem == kItemAbout) AboutBox::ShowAboutBox();#if !TARGET_API_MAC_CARBON else { GetMenuItemText(GetMenu(128), menuItem, str); OpenDeskAcc(str); }#endif } else if(menuID == kMenuFile) { switch(menuItem) { case kItemClose: w = FrontWindow(); if(w) {#if !TARGET_API_MAC_CARBON if(GetWindowKind(w) < 0) CloseDeskAcc(GetWindowKind(w)); else #endif if(w == aboutWindow) { DisposeWindow(w); aboutWindow = nullptr; } } break; case kItemQuit: gQuitting = true; break; } } else if(menuID == kMenuEdit) {#if !TARGET_API_MAC_CARBON if(!SystemEdit(menuItem - 1))#endif { // edit command not handled by desk accessory } } else if(menuID == kMenuConnection) { switch(menuItem) { case 1: gPrefs.port = Port::macTCP; break; case 2: gPrefs.port = Port::openTptTCP; break; case 3: gPrefs.port = Port::modemPort; break; case 4: gPrefs.port = Port::printerPort; break; case 5: gPrefs.port = Port::sharedFiles; break; case kItemChooseFolder: ChooseSharedDirectory(); UnloadSeg((void*) &ChooseSharedDirectory); break; default: GetMenuItemText(GetMenuHandle(menuID), menuItem, str); StringToNum(str, &gPrefs.baud); } ConnectionChanged(); } HiliteMenu(0);} std::unique_ptr<StatusDisplay> statusDisplay; std::unique_ptr<ConnectionProvider> connection; class LaunchServer : public StreamListener{ uint32_t dataSize, rsrcSize; uint32_t remainingSize; short refNum; short outRefNum; long outSize, outSizeRemaining; std::unique_ptr<AppLauncher> appLauncher; int nullEventCounter = 0; enum class State { command, header, data, rsrc, launch, wait, respond }; State state = State::command; RemoteCommand command; bool upgrade = false; OSType type, creator; public: void onReset() { AppStatus readyState{ (int)AppStatus::readyModem + (int)gPrefs.port - (int)Port::modemPort }; statusDisplay->SetStatus(readyState, 0, 0); state = State::command; } size_t onReceive(const uint8_t* p, size_t n) {#ifdef DEBUG_CONSOLE printf("Received %d bytes in state %d.\n", (int)n, (int)state);#endif switch(state) { case State::command: { if(n < 1) return 0; command = (RemoteCommand)p[0]; if(command == RemoteCommand::launchApp || command == RemoteCommand::upgradeLauncher) state = State::header; return 1; } case State::header: { if(n < 16) return 0; type = *(const OSType*)(p+0); creator = *(const OSType*)(p+4); dataSize = *(const uint32_t*)(p+8); rsrcSize = *(const uint32_t*)(p+12); statusDisplay->SetStatus(command == RemoteCommand::upgradeLauncher ? AppStatus::upgrading : AppStatus::downloading, 0, dataSize + rsrcSize); FSDelete("\pRetro68App", 0); Create("\pRetro68App", 0, creator, type); OpenDF("\pRetro68App", 0, &refNum); FSDelete("\pout", 0); Create("\pout", 0, 'ttxt', 'TEXT'); if(dataSize) { state = State::data; remainingSize = dataSize; } else if(rsrcSize) { FSClose(refNum); OpenRF("\pRetro68App", 0, &refNum); state = State::rsrc; remainingSize = rsrcSize; } else state = State::launch; return 16; } case State::data: { long count = n < remainingSize ? n : remainingSize; FSWrite(refNum, &count, p); remainingSize -= count; statusDisplay->SetProgress(dataSize - remainingSize, dataSize + rsrcSize); if(remainingSize) return count; FSClose(refNum); OpenRF("\pRetro68App", 0, &refNum); if(rsrcSize) { state = State::rsrc; remainingSize = rsrcSize; } else state = State::launch; return count; } case State::rsrc: { long count = n < remainingSize ? n : remainingSize; FSWrite(refNum, &count, p); remainingSize -= count; statusDisplay->SetProgress(dataSize + rsrcSize - remainingSize, dataSize + rsrcSize); if(remainingSize) return count; FSClose(refNum); statusDisplay->SetStatus(AppStatus::running); state = State::launch; return count; } default: return 0; } } void idle() { ++nullEventCounter; if(connection) connection->idle(); if(state == State::launch) { if(command == RemoteCommand::upgradeLauncher) { Stream *stream = connection->getStream(); if(creator == 'R68L' && type == 'APPL') { uint32_t zero = 0; stream->write(&zero, 4); stream->write(&zero, 4); upgrade = true; } else { uint32_t error = 1; stream->write(&error, 4); } stream->flushWrite(); outRefNum = 0; outSizeRemaining = 0; outSize = 0; state = State::respond; } else { connection->suspend();#if TARGET_CPU_68K if(void *seg = connection->segmentToUnload()) UnloadSeg(seg);#endif gPrefs.inSubLaunch = true; WritePrefs(); if(type == 'MPST') appLauncher = CreateToolLauncher(); else appLauncher = CreateAppLauncher(); bool launched = appLauncher->Launch("\pRetro68App"); gPrefs.inSubLaunch = false; WritePrefs(); if(launched) { state = State::wait; nullEventCounter = 0; statusDisplay->SetStatus(AppStatus::running, 0, 0); } else {#ifdef DEBUG_CONSOLE printf("Failed to Launch.\n");#endif connection->resume(); onReset(); } } } else if(state == State::wait && nullEventCounter > 3) { if(!appLauncher->IsRunning("\pRetro68App")) { appLauncher.reset(); UnloadSeg((void*) &CreateAppLauncher); UnloadSeg((void*) &CreateToolLauncher); connection->resume(); StartResponding(); } } else if(state == State::respond) { Stream *stream = connection->getStream(); while(outSizeRemaining && stream->readyToWrite()) { char buf[1024]; long count = outSizeRemaining > 1024 ? 1024 : outSizeRemaining; FSRead(outRefNum, &count, buf); stream->write(buf, count); outSizeRemaining -= count; } statusDisplay->SetStatus(AppStatus::uploading, outSize - outSizeRemaining, outSize); if(outSizeRemaining == 0 && outRefNum)Lines 1–500 of 824. Load more
/* Copyright 2019 Wolfgang Thaller. This file is part of Retro68. Retro68 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Retro68 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Retro68. If not, see <http://www.gnu.org/licenses/>. */ #include <Quickdraw.h> #include <Windows.h> #include <Menus.h> #include <Fonts.h> #include <Resources.h> #include <TextEdit.h> #include <TextUtils.h> #include <Dialogs.h> #include <Devices.h> #include <Traps.h> #include <LowMem.h> #include <SegLoad.h> #include <Gestalt.h> #include "AppLauncher.h" #include "StatusDisplay.h" #include "AboutBox.h" #include "Preferences.h" #include <ServerProtocol.h> #include <Processes.h> #include <string.h> #include <memory> #include "ConnectionProvider.h" #if !TARGET_API_MAC_CARBON #include "SerialConnectionProvider.h" #endif #if HAVE_MACTCP #include "TCPConnectionProvider.h" #endif #ifdef HAVE_OPENTRANSPORT #include "OpenTptConnectionProvider.h" #endif #include "SharedFileProvider.h" #include "SystemInfo.h" #include "CarbonFileCompat.h" #include <Stream.h> enum { kMenuApple = 128, kMenuFile, kMenuEdit, kMenuConnection }; enum { kItemAbout = 1, kItemClose = 1, kItemQuit = 3, kItemChooseFolder = 14 }; #if TARGET_API_MAC_CARBON bool portsAvailable[] = { false, false, false, false, true }; #else #ifdef HAVE_OPENTRANSPORT bool portsAvailable[] = { true, true, false, false, true }; #else bool portsAvailable[] = { true, false, false, false, true }; #endif #endif bool hasIconUtils = true; bool hasColorQD = true; bool hasSys7StdFile = true; Prefs gPrefs; void WritePrefs() { short refNum; Create("\pLaunchAPPLServer Preferences", 0, 'R68L', 'LAPR'); if(OpenDF("\pLaunchAPPLServer Preferences", 0, &refNum) == noErr) { long count = sizeof(gPrefs); FSWrite(refNum, &count, &gPrefs); FSClose(refNum); } } void ReadPrefs() { short refNum; if(OpenDF("\pLaunchAPPLServer Preferences", 0, &refNum) == noErr) { long count = sizeof(gPrefs); gPrefs.version = -1; FSRead(refNum, &count, &gPrefs); if(gPrefs.version != Prefs::currentVersion) gPrefs = Prefs(); FSClose(refNum); } } bool gQuitting = false; WindowRef aboutWindow = nullptr; void ConnectionChanged(); #if TARGET_API_MAC_CARBON #define EnableItem EnableMenuItem #define DisableItem DisableMenuItem #endif void SetItemEnabled(MenuHandle m, short item, bool enabled) { if(enabled) EnableItem(m,item); else DisableItem(m,item); } void UpdateMenus() { MenuRef m = GetMenuHandle(kMenuFile); WindowRef w = FrontWindow(); m = GetMenuHandle(kMenuFile); if(w && (w == aboutWindow || GetWindowKind(w) < 0)) EnableItem(m,kItemClose); else DisableItem(m,kItemClose); m = GetMenuHandle(kMenuEdit); bool enableEditMenu = (w && GetWindowKind(w) < 0); // Desk accessory in front: Enable edit menu items // Application window or nothing in front, disable edit menu for(short i : {1,3,4,5,6}) SetItemEnabled(m,i,enableEditMenu); m = GetMenuHandle(kMenuConnection); SetItemEnabled(m, 1, portsAvailable[(int)Port::macTCP]); CheckMenuItem(m, 1, gPrefs.port == Port::macTCP); SetItemEnabled(m, 2, portsAvailable[(int)Port::openTptTCP]); CheckMenuItem(m, 2, gPrefs.port == Port::openTptTCP); SetItemEnabled(m, 3, portsAvailable[(int)Port::modemPort]); CheckMenuItem(m, 3, gPrefs.port == Port::modemPort); SetItemEnabled(m, 4, portsAvailable[(int)Port::printerPort]); CheckMenuItem(m, 4, gPrefs.port == Port::printerPort); SetItemEnabled(m, 5, portsAvailable[(int)Port::sharedFiles]); CheckMenuItem(m, 5, gPrefs.port == Port::sharedFiles); for(int i = 7; i < kItemChooseFolder; i++) { Str255 str; long baud; GetMenuItemText(m, i, str); StringToNum(str, &baud); CheckMenuItem(m, i, baud == gPrefs.baud); SetItemEnabled(m, i, gPrefs.port == Port::modemPort || gPrefs.port == Port::printerPort); } } void DoMenuCommand(long menuCommand) { Str255 str; WindowRef w; short menuID = menuCommand >> 16; short menuItem = menuCommand & 0xFFFF; if(menuID == kMenuApple) { if(menuItem == kItemAbout) AboutBox::ShowAboutBox(); #if !TARGET_API_MAC_CARBON else { GetMenuItemText(GetMenu(128), menuItem, str); OpenDeskAcc(str); } #endif } else if(menuID == kMenuFile) { switch(menuItem) { case kItemClose: w = FrontWindow(); if(w) { #if !TARGET_API_MAC_CARBON if(GetWindowKind(w) < 0) CloseDeskAcc(GetWindowKind(w)); else #endif if(w == aboutWindow) { DisposeWindow(w); aboutWindow = nullptr; } } break; case kItemQuit: gQuitting = true; break; } } else if(menuID == kMenuEdit) { #if !TARGET_API_MAC_CARBON if(!SystemEdit(menuItem - 1)) #endif { // edit command not handled by desk accessory } } else if(menuID == kMenuConnection) { switch(menuItem) { case 1: gPrefs.port = Port::macTCP; break; case 2: gPrefs.port = Port::openTptTCP; break; case 3: gPrefs.port = Port::modemPort; break; case 4: gPrefs.port = Port::printerPort; break; case 5: gPrefs.port = Port::sharedFiles; break; case kItemChooseFolder: ChooseSharedDirectory(); UnloadSeg((void*) &ChooseSharedDirectory); break; default: GetMenuItemText(GetMenuHandle(menuID), menuItem, str); StringToNum(str, &gPrefs.baud); } ConnectionChanged(); } HiliteMenu(0); } std::unique_ptr<StatusDisplay> statusDisplay; std::unique_ptr<ConnectionProvider> connection; class LaunchServer : public StreamListener { uint32_t dataSize, rsrcSize; uint32_t remainingSize; short refNum; short outRefNum; long outSize, outSizeRemaining; std::unique_ptr<AppLauncher> appLauncher; int nullEventCounter = 0; enum class State { command, header, data, rsrc, launch, wait, respond }; State state = State::command; RemoteCommand command; bool upgrade = false; OSType type, creator; public: void onReset() { AppStatus readyState{ (int)AppStatus::readyModem + (int)gPrefs.port - (int)Port::modemPort }; statusDisplay->SetStatus(readyState, 0, 0); state = State::command; } size_t onReceive(const uint8_t* p, size_t n) { #ifdef DEBUG_CONSOLE printf("Received %d bytes in state %d.\n", (int)n, (int)state); #endif switch(state) { case State::command: { if(n < 1) return 0; command = (RemoteCommand)p[0]; if(command == RemoteCommand::launchApp || command == RemoteCommand::upgradeLauncher) state = State::header; return 1; } case State::header: { if(n < 16) return 0; type = *(const OSType*)(p+0); creator = *(const OSType*)(p+4); dataSize = *(const uint32_t*)(p+8); rsrcSize = *(const uint32_t*)(p+12); statusDisplay->SetStatus(command == RemoteCommand::upgradeLauncher ? AppStatus::upgrading : AppStatus::downloading, 0, dataSize + rsrcSize); FSDelete("\pRetro68App", 0); Create("\pRetro68App", 0, creator, type); OpenDF("\pRetro68App", 0, &refNum); FSDelete("\pout", 0); Create("\pout", 0, 'ttxt', 'TEXT'); if(dataSize) { state = State::data; remainingSize = dataSize; } else if(rsrcSize) { FSClose(refNum); OpenRF("\pRetro68App", 0, &refNum); state = State::rsrc; remainingSize = rsrcSize; } else state = State::launch; return 16; } case State::data: { long count = n < remainingSize ? n : remainingSize; FSWrite(refNum, &count, p); remainingSize -= count; statusDisplay->SetProgress(dataSize - remainingSize, dataSize + rsrcSize); if(remainingSize) return count; FSClose(refNum); OpenRF("\pRetro68App", 0, &refNum); if(rsrcSize) { state = State::rsrc; remainingSize = rsrcSize; } else state = State::launch; return count; } case State::rsrc: { long count = n < remainingSize ? n : remainingSize; FSWrite(refNum, &count, p); remainingSize -= count; statusDisplay->SetProgress(dataSize + rsrcSize - remainingSize, dataSize + rsrcSize); if(remainingSize) return count; FSClose(refNum); statusDisplay->SetStatus(AppStatus::running); state = State::launch; return count; } default: return 0; } } void idle() { ++nullEventCounter; if(connection) connection->idle(); if(state == State::launch) { if(command == RemoteCommand::upgradeLauncher) { Stream *stream = connection->getStream(); if(creator == 'R68L' && type == 'APPL') { uint32_t zero = 0; stream->write(&zero, 4); stream->write(&zero, 4); upgrade = true; } else { uint32_t error = 1; stream->write(&error, 4); } stream->flushWrite(); outRefNum = 0; outSizeRemaining = 0; outSize = 0; state = State::respond; } else { connection->suspend(); #if TARGET_CPU_68K if(void *seg = connection->segmentToUnload()) UnloadSeg(seg); #endif gPrefs.inSubLaunch = true; WritePrefs(); if(type == 'MPST') appLauncher = CreateToolLauncher(); else appLauncher = CreateAppLauncher(); bool launched = appLauncher->Launch("\pRetro68App"); gPrefs.inSubLaunch = false; WritePrefs(); if(launched) { state = State::wait; nullEventCounter = 0; statusDisplay->SetStatus(AppStatus::running, 0, 0); } else { #ifdef DEBUG_CONSOLE printf("Failed to Launch.\n"); #endif connection->resume(); onReset(); } } } else if(state == State::wait && nullEventCounter > 3) { if(!appLauncher->IsRunning("\pRetro68App")) { appLauncher.reset(); UnloadSeg((void*) &CreateAppLauncher); UnloadSeg((void*) &CreateToolLauncher); connection->resume(); StartResponding(); } } else if(state == State::respond) { Stream *stream = connection->getStream(); while(outSizeRemaining && stream->readyToWrite()) { char buf[1024]; long count = outSizeRemaining > 1024 ? 1024 : outSizeRemaining; FSRead(outRefNum, &count, buf); stream->write(buf, count); outSizeRemaining -= count; } statusDisplay->SetStatus(AppStatus::uploading, outSize - outSizeRemaining, outSize); if(outSizeRemaining == 0 && outRefNum)