824 lines · 23.1 KB · C++
RawDownload
/*    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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t